diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 9b7b299cb8..15914ce2ba 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -3,12 +3,12 @@ import cn.hutool.core.util.RuntimeUtil apply plugin: "com.android.application" apply plugin: "kotlin-android" -def verName = "10.2.9" -def verCode = 1149 +def verName = "10.3.2" +def verCode = 1150 -def officialVer = "10.2.9" -def officialCode = 4087 +def officialVer = "10.3.2" +def officialCode = 4145 def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json") diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp index 68ef0738e8..b651482904 100644 --- a/TMessagesProj/jni/gifvideo.cpp +++ b/TMessagesProj/jni/gifvideo.cpp @@ -1339,7 +1339,7 @@ extern "C" JNIEXPORT int JNICALL Java_org_telegram_ui_Components_AnimatedFileDra } } -extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview, jfloat start_time, jfloat end_time) { +extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview, jfloat start_time, jfloat end_time, jboolean loop) { if (ptr == NULL || bitmap == nullptr) { return 0; } @@ -1408,18 +1408,19 @@ extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDr LOGE("can't decode packet flushed %s", info->src); return 0; } - if (!preview && got_frame == 0) { - if (info->has_decoded_frames) { - int64_t start_from = 0; - if (start_time > 0) { - start_from = (int64_t)(start_time / av_q2d(info->video_stream->time_base)); - } - if ((ret = av_seek_frame(info->fmt_ctx, info->video_stream_idx, start_from, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME)) < 0) { - LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret)); - return 0; - } else { - avcodec_flush_buffers(info->video_dec_ctx); - } + if (!preview && got_frame == 0 && info->has_decoded_frames) { + if (!loop) { + return 0; + } + int64_t start_from = 0; + if (start_time > 0) { + start_from = (int64_t)(start_time / av_q2d(info->video_stream->time_base)); + } + if ((ret = av_seek_frame(info->fmt_ctx, info->video_stream_idx, start_from, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME)) < 0) { + LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret)); + return 0; + } else { + avcodec_flush_buffers(info->video_dec_ctx); } } } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.cpp b/TMessagesProj/jni/tgnet/ApiScheme.cpp index 5ab7064f93..9093b19c8b 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.cpp +++ b/TMessagesProj/jni/tgnet/ApiScheme.cpp @@ -518,11 +518,15 @@ void TL_user::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &er if ((flags2 & 32) != 0) { stories_max_id = stream->readInt32(&error); } - if ((flags2 & 128) != 0) { - color = stream->readInt32(&error); + if ((flags2 & 256) != 0) { + int magic = stream->readInt32(&error); + color_color = stream->readInt32(&error); + color_background_emoji_id = stream->readInt64(&error); } - if ((flags2 & 64) != 0) { - background_emoji_id = stream->readInt64(&error); + if ((flags2 & 512) != 0) { + int magic = stream->readInt32(&error); + profile_color_color = stream->readInt32(&error); + profile_color_background_emoji_id = stream->readInt64(&error); } } @@ -591,11 +595,15 @@ void TL_user::serializeToStream(NativeByteBuffer *stream) { if ((flags2 & 32) != 0) { stream->writeInt32(stories_max_id); } - if ((flags2 & 128) != 0) { - stream->writeInt32(color); + if ((flags2 & 256) != 0) { + stream->writeInt32(0xba278146); + stream->writeInt32(color_color); + stream->writeInt32(color_background_emoji_id); } - if ((flags2 & 64) != 0) { - stream->writeInt64(background_emoji_id); + if ((flags2 & 512) != 0) { + stream->writeInt32(0xba278146); + stream->writeInt32(profile_color_color); + stream->writeInt32(profile_color_background_emoji_id); } } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 0318c1a647..edee2074f7 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -339,8 +339,10 @@ class User : public TLObject { int32_t emojiStatusMagic; int64_t emojiStatusDocumentId; int32_t emojiStatusUntil; - int32_t color; - int64_t background_emoji_id; + int32_t color_color; + int64_t color_background_emoji_id; + int32_t profile_color_color; + int64_t profile_color_background_emoji_id; static User *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error); }; @@ -357,7 +359,7 @@ class TL_userEmpty : public User { class TL_user : public User { public: - static const uint32_t constructor = 0xeb602f25; + static const uint32_t constructor = 0x215c4438; void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); void serializeToStream(NativeByteBuffer *stream); diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java index d3dde3c6f0..01f4a439fa 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java @@ -21,6 +21,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.BotHelpCell; +import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.ChatGreetingsView; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 4a1672172f..e5c89e1bf3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -473,11 +473,11 @@ public static Activity findActivity(Context context) { return null; } - public static CharSequence premiumText(String str, Runnable runnable) { + public static SpannableStringBuilder premiumText(String str, Runnable runnable) { return replaceSingleTag(str, -1, REPLACING_TAG_TYPE_LINKBOLD, runnable); } - public static CharSequence replaceSingleTag(String str, Runnable runnable) { + public static SpannableStringBuilder replaceSingleTag(String str, Runnable runnable) { return replaceSingleTag(str, -1, 0, runnable); } @@ -535,6 +535,10 @@ public void updateDrawState(TextPaint textPaint) { } public static SpannableStringBuilder replaceSingleLink(String str, int color) { + return replaceSingleLink(str, color, null); + } + + public static SpannableStringBuilder replaceSingleLink(String str, int color, Runnable onClick) { int startIndex = str.indexOf("**"); int endIndex = str.indexOf("**", startIndex + 1); str = str.replace("**", ""); @@ -556,7 +560,9 @@ public void updateDrawState(@NonNull TextPaint ds) { @Override public void onClick(@NonNull View view) { - + if (onClick != null) { + onClick.run(); + } } }, index, index + len, 0); } @@ -1128,7 +1134,7 @@ public static int calcBitmapColor(Bitmap bitmap) { public static int[] calcDrawableColor(Drawable drawable) { if (drawable instanceof ChatBackgroundDrawable) { ChatBackgroundDrawable chatBackgroundDrawable = (ChatBackgroundDrawable) drawable; - return calcDrawableColor(chatBackgroundDrawable.getDrawable()); + return calcDrawableColor(chatBackgroundDrawable.getDrawable(true)); } int bitmapColor = 0xff000000; int[] result = new int[4]; @@ -6049,6 +6055,9 @@ public static void forEachViews(View view, Consumer consumer) { } public static void forEachViews(RecyclerView recyclerView, Consumer consumer) { + if (recyclerView == null) { + return; + } for (int i = 0; i < recyclerView.getChildCount(); i++) { consumer.accept(recyclerView.getChildAt(i)); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index a6d1c96138..7cb7b1dd19 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -2086,4 +2086,34 @@ private void setAspectRatio(float aspectRatio, Call call) { } } } + + public static MessagesController.PeerColor getPeerColorForAvatar(int currentAccount, TLRPC.Chat chat) { +// if (chat != null && chat.profile_color != null && chat.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { +// return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(chat.profile_color.color); +// } + return null; + } + + public static int getColorId(TLRPC.Chat chat) { + if (chat == null) return 0; + if (chat.color != null && (chat.color.flags & 1) != 0) return chat.color.color; + return (int) (chat.id % 7); + } + + public static long getEmojiId(TLRPC.Chat chat) { + if (chat != null && chat.color != null && (chat.color.flags & 2) != 0) return chat.color.background_emoji_id; + return 0; + } + + public static int getProfileColorId(TLRPC.Chat chat) { + if (chat == null) return 0; +// if (chat.profile_color != null && (chat.profile_color.flags & 1) != 0) return chat.profile_color.color; + return -1; + } + + public static long getProfileEmojiId(TLRPC.Chat chat) { +// if (chat != null && chat.profile_color != null && (chat.profile_color.flags & 2) != 0) return chat.profile_color.background_emoji_id; + return -1; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java index 4648b8ba25..cf6795df4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -405,20 +405,59 @@ public void clearCache() { getSharedPreferences().edit().clear().apply(); } + public void processUpdate(TLRPC.TL_updatePeerWallpaper update) { + if (update.peer instanceof TLRPC.TL_peerUser) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(update.peer.user_id); + if (userFull != null) { + if (wallpaperEquals(userFull.wallpaper, update.wallpaper)) { + return; + } + final long dialogId = userFull.id; + userFull.wallpaper_overridden = update.wallpaper_overridden; + userFull.wallpaper = update.wallpaper; + userFull.flags |= 16777216; + getMessagesStorage().updateUserInfo(userFull, false); + saveChatWallpaper(dialogId, null); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + }); + } + } else { + // todo + } + } + + public static boolean wallpaperEquals(TLRPC.WallPaper a, TLRPC.WallPaper b) { + if ((a == null || a instanceof TLRPC.TL_wallPaperNoFile) && (b == null || b instanceof TLRPC.TL_wallPaperNoFile)) { + return true; + } + if (a instanceof TLRPC.TL_wallPaper && b instanceof TLRPC.TL_wallPaper) { + return a.id == b.id; + } + return false; + } + public void clearWallpaper(long dialogId, boolean notify) { + clearWallpaper(dialogId, notify, false); + } + + public void clearWallpaper(long dialogId, boolean notify, boolean onlyRevert) { TLRPC.TL_messages_setChatWallPaper req = new TLRPC.TL_messages_setChatWallPaper(); - if (dialogId > 0) { + if (dialogId >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); req.peer = MessagesController.getInputPeer(user); - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); - if (userFull != null) { - userFull.wallpaper = null; - userFull.flags &= ~16777216; - getMessagesStorage().updateUserInfo(userFull, false); - } - saveChatWallpaper(dialogId, null); - if (notify) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + req.revert = onlyRevert; + if (!onlyRevert) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + userFull.wallpaper = null; + userFull.flags &= ~16777216; + getMessagesStorage().updateUserInfo(userFull, false); + } + saveChatWallpaper(dialogId, null); + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + } } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); @@ -440,6 +479,7 @@ public int setWallpaperToUser(long dialogId, String wallpaperLocalPath, Theme.Ov TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); req.peer = MessagesController.getInputPeer(chat); } + req.for_both = wallpaperInfo.forBoth; boolean applyOnRequest = true; if (serverWallpaper != null && serverWallpaper.messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { applyOnRequest = false; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java index 21aaa43403..fc12553cd0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java @@ -150,7 +150,8 @@ public RemoteViews getViewAt(int position) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); } } else { - avatarDrawable = new AvatarDrawable(chat); + avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), chat); } avatarDrawable.setBounds(0, 0, size, size); avatarDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java index 91c576f8d8..201dfe5c65 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java @@ -420,7 +420,7 @@ private static void matchGrammar(String text, LinkedList tokenList, TokenPattern StringToken wrapped; if (pattern.insideTokenPatterns != null) { - wrapped = new StringToken(pattern.group, tokenize(match.string, pattern.insideTokenPatterns, depth + 1), match.length); + wrapped = new StringToken(pattern.group, tokenize(match.string, pattern.insideTokenPatterns, pattern, depth + 1), match.length); } else if (pattern.insideLanguage != null) { wrapped = new StringToken(pattern.group, tokenize(match.string, compiledPatterns.get(pattern.insideLanguage), pattern, depth + 1), match.length); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java index 675b4852d5..9e564ee544 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java @@ -155,7 +155,8 @@ public RemoteViews getViewAt(int position) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); } } else { - avatarDrawable = new AvatarDrawable(chat); + avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), chat); } avatarDrawable.setBounds(0, 0, size, size); avatarDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index d31fcbbf1a..de7b99fbcf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1119,25 +1119,6 @@ public boolean setBackupImage() { return false; } - private int bufferedFrame; - public void incrementFrames(int inc) { - if (currentMediaDrawable instanceof RLottieDrawable) { -// RLottieDrawable rlottie = (RLottieDrawable) currentMediaDrawable; -// inc = (int) Math.round((float) rlottie.getFramesCount() / rlottie.getDuration() * (1f / 30f)); -// rlottie.setCurrentFrame( -// (rlottie.getCurrentFrame() + inc) % (int) rlottie.getFramesCount() -// ); - } else if (currentMediaDrawable instanceof AnimatedFileDrawable) { - int lastFrame = (int) bufferedFrame; - bufferedFrame += inc; - int currentFrame = (int) bufferedFrame; - while (lastFrame != currentFrame) { - ((AnimatedFileDrawable) currentMediaDrawable).getNextFrame(); - currentFrame--; - } - } - } - public boolean onAttachedToWindow() { if (attachedToWindow) { return false; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 2560f471ac..8b14fc2213 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1282,6 +1282,11 @@ public static String formatPluralStringComma(String key, int plural, char symbol int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); value = ApplicationLoader.applicationContext.getString(resourceId); } + if (value == null) { + int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(key + "_other", "string", ApplicationLoader.applicationContext.getPackageName()); + value = ApplicationLoader.applicationContext.getString(resourceId); + } + value = value.replace("%d", "%1$s"); value = value.replace("%1$d", "%1$s"); if (getInstance().currentLocale != null) { @@ -1812,6 +1817,42 @@ public static String formatSeenDate(long date) { return "LOC_ERR"; } + public static String formatShortDate(long date) { + try { + date *= 1000; + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + long timeInMillis = rightNow.getTimeInMillis(); + rightNow.setTimeInMillis(date); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (timeInMillis - date < 1000 * 60) { + return LocaleController.getString(R.string.ShortNow); + } else if (timeInMillis - date < 1000 * 60 * 60) { + int minutesAgo = (int) ((timeInMillis - date) / (1000 * 60)); + return LocaleController.formatPluralString("ShortMinutesAgo", minutesAgo); + } else if (dateDay == day && year == dateYear) { + if (timeInMillis - date < 12 * 1000 * 60 * 60) { + int hoursAgo = (int) ((timeInMillis - date) / (1000 * 60 * 60)); + return LocaleController.formatPluralString("ShortHoursAgo", hoursAgo); + } else { + return LocaleController.getString(R.string.ShortToday); + } + } else if (dateDay + 1 == day && year == dateYear) { + return LocaleController.getString(R.string.ShortYesterday); + } else if (Math.abs(System.currentTimeMillis() - date) < 31536000000L) { + return getInstance().formatterDayMonth.format(new Date(date)); + } else { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date)), getInstance().formatterDay.format(new Date(date))); + } + } catch (Exception e) { + FileLog.e(e); + } + return "LOC_ERR"; + } + public static String formatStoryDate(long date) { try { date *= 1000; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 80021a01c1..8e01f19d37 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -620,7 +620,7 @@ public SearchImage clone() { public final static int VIDEO_BITRATE_360 = 750_000; public final static String VIDEO_MIME_TYPE = "video/avc"; - public final static String AUIDO_MIME_TYPE = "audio/mp4a-latm"; + public final static String AUDIO_MIME_TYPE = "audio/mp4a-latm"; private final Object videoConvertSync = new Object(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 33e2b6fa0a..3c619f0941 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -408,7 +408,7 @@ public void checkStickers(int type) { public void checkReactions() { if (!isLoadingReactions && Math.abs(System.currentTimeMillis() / 1000 - reactionsUpdateDate) >= 60 * 60) { - loadReactions(true, false); + loadReactions(true, null); } } @@ -645,7 +645,7 @@ public List getReactionsList() { return reactionsList; } - public void loadReactions(boolean cache, boolean force) { + public void loadReactions(boolean cache, Integer lastHash) { isLoadingReactions = true; if (cache) { getMessagesStorage().getStorageQueue().postRunnable(() -> { @@ -685,7 +685,7 @@ public void loadReactions(boolean cache, boolean force) { }); } else { TLRPC.TL_messages_getAvailableReactions req = new TLRPC.TL_messages_getAvailableReactions(); - req.hash = force ? 0 : reactionsUpdateHash; + req.hash = lastHash != null ? lastHash : reactionsUpdateHash; getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { int date = (int) (System.currentTimeMillis() / 1000); if (response instanceof TLRPC.TL_messages_availableReactionsNotModified) { @@ -725,7 +725,7 @@ public void processLoadedReactions(List reactions, i if (!cache) { putReactionsToCache(reactions, hash, date); } else if (Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) { - loadReactions(false, true); + loadReactions(false, hash); } } @@ -6339,6 +6339,9 @@ public ArrayList getEntities(CharSequence[] message, boolea } } else { if (start + 1 != index) { + if (message[0] instanceof Spanned && ((Spanned) message[0]).getSpans(Utilities.clamp(start, message[0].length(), 0), Utilities.clamp(start + 1, message[0].length(), 0), CodeHighlighting.Span.class).length > 0) { + continue; + } message[0] = AndroidUtilities.concat(substring(message[0], 0, start), substring(message[0], start + 1, index), substring(message[0], index + 1, message[0].length())); TLRPC.TL_messageEntityCode entity = new TLRPC.TL_messageEntityCode(); entity.offset = start; @@ -6625,12 +6628,7 @@ public Pair getOneThreadDraft(long dialogId) { if (threads == null || threads.size() <= 0) { return null; } - for (int i = 0; i < threads.size(); ++i) { - if (threads.keyAt(i) != 0) { - return new Pair(threads.keyAt(i), threads.valueAt(i)); - } - } - return null; + return new Pair(threads.keyAt(0), threads.valueAt(0)); } public TLRPC.Message getDraftMessage(long dialogId, int threadId) { @@ -6666,6 +6664,8 @@ public void saveDraft(long dialogId, int threadId, CharSequence message, ArrayLi draftMessage.reply_to.quote_text = quote.getText(); if (draftMessage.reply_to.quote_text != null) { draftMessage.reply_to.flags |= 4; + draftMessage.reply_to.flags |= 16; + draftMessage.reply_to.quote_offset = quote.start; } draftMessage.reply_to.quote_entities = quote.getEntities(); if (draftMessage.reply_to.quote_entities != null && !draftMessage.reply_to.quote_entities.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 5d79621107..b05ffe8ee2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -130,6 +130,7 @@ public class MessageObject { public static final int TYPE_STORY_MENTION = 24; public static final int TYPE_GIFT_PREMIUM_CHANNEL = 25; public static final int TYPE_GIVEAWAY = 26; + public static final int TYPE_JOINED_CHANNEL = 27; // recommendations list public int localType; public String localName; @@ -214,10 +215,15 @@ public class MessageObject { public boolean sponsoredRecommended; public String sponsoredInfo, sponsoredAdditionalInfo; public TLRPC.TL_sponsoredWebPage sponsoredWebPage; + public TLRPC.BotApp sponsoredBotApp; + public String sponsoredButtonText; public boolean replyTextEllipsized; public boolean replyTextRevealed; public int overrideLinkColor = -1; public long overrideLinkEmoji = -1; + public MessagesController.PeerColor overrideProfilePeerColor; + private boolean channelJoined; + public boolean channelJoinedExpanded; public TLRPC.TL_forumTopic replyToForumTopic; // used only for reply message in view all messages @@ -429,6 +435,19 @@ public boolean isWallpaperAction() { return type == TYPE_ACTION_WALLPAPER || (messageOwner != null && messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper); } + public boolean isWallpaperForBoth() { + return isWallpaperAction() && messageOwner != null && messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper && ((TLRPC.TL_messageActionSetChatWallPaper) messageOwner.action).for_both; + } + + public boolean isCurrentWallpaper() { + if (!isWallpaperAction() || messageOwner == null || messageOwner.action == null || messageOwner.action.wallpaper == null) + return false; + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(getDialogId()); + if (userFull == null || userFull.wallpaper == null || !userFull.wallpaper_overridden) + return false; + return messageOwner.action.wallpaper.id == userFull.wallpaper.id; + } + public int getEmojiOnlyCount() { return emojiOnlyCount; } @@ -523,6 +542,9 @@ public void copyStableParams(MessageObject old) { public ArrayList getChoosenReactions() { ArrayList choosenReactions = new ArrayList<>(); TLRPC.ReactionCount newReaction = null; + if (messageOwner.reactions == null) { + return choosenReactions; + } for (int i = 0; i < messageOwner.reactions.results.size(); i++) { if (messageOwner.reactions.results.get(i).chosen) { choosenReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(messageOwner.reactions.results.get(i).reaction)); @@ -808,6 +830,7 @@ private static String capitalizeLanguage(String lng) { case "dockerfile": case "dart": case "java": + case "fift": return capitalizeFirst(lng); case "http": case "html": @@ -831,7 +854,13 @@ private static String capitalizeLanguage(String lng) { case "cobol": case "jsx": case "tsx": + case "tl": return lng.toUpperCase(); + case "tl-b": + case "tlb": + return "TL-B"; + case "func": + return "FunC"; } return lng; } @@ -1789,9 +1818,9 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionParticipantJoin) { if (chat.megagroup) { - messageText = replaceWithLink(LocaleController.getString("EventLogGroupJoined", R.string.EventLogGroupJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogGroupJoined), "un1", fromUser); } else { - messageText = replaceWithLink(LocaleController.getString("EventLogChannelJoined", R.string.EventLogChannelJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChannelJoined), "un1", fromUser); } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionParticipantLeave) { messageOwner = new TLRPC.TL_messageService(); @@ -1815,9 +1844,9 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL } if (messageOwner.from_id instanceof TLRPC.TL_peerUser && peerId == messageOwner.from_id.user_id) { if (chat.megagroup) { - messageText = replaceWithLink(LocaleController.getString("EventLogGroupJoined", R.string.EventLogGroupJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogGroupJoined), "un1", fromUser); } else { - messageText = replaceWithLink(LocaleController.getString("EventLogChannelJoined", R.string.EventLogChannelJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChannelJoined), "un1", fromUser); } } else { messageText = replaceWithLink(LocaleController.getString("EventLogAdded", R.string.EventLogAdded), "un2", whoUser); @@ -3526,11 +3555,12 @@ private void updateMessageText(AbstractMap users, AbstractMap< TLObject fromObject = fromUser != null ? fromUser : fromChat; drawServiceWithDefaultTypeface = false; + channelJoined = false; if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action != null) { if (messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper) { contentType = 1; - type = TYPE_TEXT; + type = TYPE_DATE; TLRPC.TL_messageActionSetSameChatWallPaper action = (TLRPC.TL_messageActionSetSameChatWallPaper) messageOwner.action; TLRPC.User user = getUser(users, sUsers, isOutOwner() ? 0 : getDialogId()); photoThumbs = new ArrayList<>(); @@ -3540,26 +3570,47 @@ private void updateMessageText(AbstractMap users, AbstractMap< } if (user != null) { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { - messageText = LocaleController.formatString("ActionSetSameWallpaperForThisChatSelf", R.string.ActionSetSameWallpaperForThisChatSelf); + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChatSelf); } else { - messageText = LocaleController.formatString("ActionSetSameWallpaperForThisChat", R.string.ActionSetSameWallpaperForThisChat, user.first_name); + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChat, user.first_name); } } } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; - type = TYPE_ACTION_WALLPAPER; TLRPC.TL_messageActionSetChatWallPaper wallPaper = (TLRPC.TL_messageActionSetChatWallPaper) messageOwner.action; + type = TYPE_ACTION_WALLPAPER; photoThumbs = new ArrayList<>(); if (wallPaper.wallpaper.document != null) { photoThumbs.addAll(wallPaper.wallpaper.document.thumbs); photoThumbsObject = wallPaper.wallpaper.document; } TLRPC.User user = getUser(users, sUsers, isOutOwner() ? 0 : getDialogId()); + TLRPC.User partner = getUser(users, sUsers, getDialogId()); if (user != null) { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { - messageText = LocaleController.formatString("ActionSetWallpaperForThisChatSelf", R.string.ActionSetWallpaperForThisChatSelf); + if (wallPaper.same) { + type = TYPE_DATE; + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChatSelf); + } else if (wallPaper.for_both && partner != null) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelfBoth); + CharSequence partnerName = new SpannableString(UserObject.getFirstName(partner)); + ((SpannableString) partnerName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, partnerName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + messageText = AndroidUtilities.replaceCharSequence("%s", messageText, partnerName); + } else { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelf); + } } else { - messageText = LocaleController.formatString("ActionSetWallpaperForThisChat", R.string.ActionSetWallpaperForThisChat, user.first_name); + CharSequence userName = new SpannableString(UserObject.getFirstName(user)); + ((SpannableString) userName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, userName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (wallPaper.same) { + type = TYPE_DATE; + messageText = LocaleController.getString(R.string.ActionSetSameWallpaperForThisChat); + } else if (wallPaper.for_both) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatBoth); + } else { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChat); + } + messageText = AndroidUtilities.replaceCharSequence("%s", messageText, userName); } } } else if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { @@ -3699,6 +3750,7 @@ private void updateMessageText(AbstractMap users, AbstractMap< } if (messageOwner.from_id != null && singleUserId == messageOwner.from_id.user_id) { if (ChatObject.isChannel(chat) && !chat.megagroup) { + channelJoined = true; messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined); } else { if (messageOwner.peer_id.channel_id != 0) { @@ -3748,6 +3800,15 @@ private void updateMessageText(AbstractMap users, AbstractMap< } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayLaunch) { TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; messageText = LocaleController.formatString("BoostingGiveawayJustStarted", R.string.BoostingGiveawayJustStarted, chat != null ? chat.title : ""); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + TLRPC.TL_messageActionGiveawayResults giveawayResults = (TLRPC.TL_messageActionGiveawayResults) messageOwner.action; + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceWinnersSelected", giveawayResults.winners_count)); + if (giveawayResults.unclaimed_count > 0) { + stringBuilder.append("\n"); + stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceUndistributed", giveawayResults.unclaimed_count)); + } + messageText = stringBuilder; } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { messageText = LocaleController.getString("BoostingReceivedGiftNoName", R.string.BoostingReceivedGiftNoName); } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium) { @@ -4457,7 +4518,10 @@ public void setType() { int oldType = type; type = 1000; isRoundVideoCached = 0; - if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) { + if (channelJoined) { + type = TYPE_JOINED_CHANNEL; + channelJoinedExpanded = MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("c" + getDialogId() + "_rec", true); + } else if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) { if (isRestrictedMessage) { type = TYPE_TEXT; } else if (emojiAnimatedSticker != null || emojiAnimatedStickerId != null) { @@ -4466,7 +4530,7 @@ public void setType() { } else { type = TYPE_ANIMATED_STICKER; } - } else if (isMediaEmpty(false) && !isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji && messageOwner != null && !hasNonEmojiEntities()) { + } else if (isMediaEmpty(false) && !isDice() && !isSponsored() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji && messageOwner != null && !hasNonEmojiEntities()) { type = TYPE_EMOJIS; } else if (isMediaEmpty()) { type = TYPE_TEXT; @@ -4540,7 +4604,7 @@ public void setType() { } else if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper) { contentType = 1; - type = TYPE_TEXT; + type = TYPE_DATE; } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; type = TYPE_ACTION_WALLPAPER; @@ -4915,6 +4979,16 @@ public void generateThumbs(boolean update) { } } } + } else if (sponsoredWebPage != null && sponsoredWebPage.photo != null) { + if (!update || photoThumbs == null) { + photoThumbs = new ArrayList<>(sponsoredWebPage.photo.sizes); + } else if (!photoThumbs.isEmpty()) { + updatePhotoSizeLocations(photoThumbs, sponsoredWebPage.photo.sizes); + } + photoThumbsObject = sponsoredWebPage.photo; + if (strippedThumb == null) { + createStrippedThumb(); + } } } @@ -5224,7 +5298,6 @@ public float measureVoiceTranscriptionHeight() { public boolean isVoiceTranscriptionOpen() { return ( - UserConfig.getInstance(currentAccount).isPremium() && messageOwner != null && (isVoice() || isRoundVideo() && TranscribeButton.isVideoTranscriptionOpen(this)) && messageOwner.voiceTranscriptionOpen && @@ -5908,7 +5981,9 @@ public static boolean addEntitiesToText(CharSequence text, ArrayList ranges) final int type = cutToType.get(cutIndex); if (from != cutIndex) { - int to = cutIndex; if (cutIndex - 1 >= 0 && cutIndex - 1 < text.length() && text.charAt(cutIndex - 1) == '\n') { - to--; + cutIndex--; } String lng = null; @@ -9433,7 +9509,7 @@ public static void cutIntoRanges(CharSequence text, ArrayList ranges) codeSpanIndex++; } - ranges.add(new TextRange(from, to, quoteCount > 0, codeCount > 0, lng)); + ranges.add(new TextRange(from, cutIndex, quoteCount > 0, codeCount > 0, lng)); from = cutIndex; if (from + 1 < text.length() && text.charAt(from) == '\n') { from++; @@ -9449,4 +9525,34 @@ public static void cutIntoRanges(CharSequence text, ArrayList ranges) ranges.add(new TextRange(from, text.length(), quoteCount > 0, codeCount > 0, null)); } } + + public void toggleChannelRecommendations() { + expandChannelRecommendations(!channelJoinedExpanded); + } + + public void expandChannelRecommendations(boolean expand) { + MessagesController.getInstance(currentAccount).getMainSettings().edit() + .putBoolean("c" + getDialogId() + "_rec", channelJoinedExpanded = expand) + .apply(); + } + + public static int findQuoteStart(String text, String quote, int quote_offset) { + if (text == null || quote == null) { + return -1; + } + if (quote_offset == -1) { + return text.indexOf(quote); + } + if (quote_offset + quote.length() < text.length() && text.startsWith(quote, quote_offset)) { + return quote_offset; + } + int nextIndex = text.indexOf(quote, quote_offset); + int prevIndex = text.lastIndexOf(quote, quote_offset); + if (nextIndex == -1) return prevIndex; + if (prevIndex == -1) return nextIndex; + if (nextIndex - quote_offset < quote_offset - prevIndex) { + return nextIndex; + } + return prevIndex; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index e2c0eb30c8..f773d449f0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -37,6 +37,7 @@ import androidx.collection.LongSparseArray; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationManagerCompat; +import androidx.core.graphics.ColorUtils; import androidx.core.util.Consumer; import org.telegram.SQLite.SQLiteCursor; @@ -537,6 +538,14 @@ protected boolean useCache(Integer arguments) { public int quoteLengthMax; public boolean giveawayGiftsPurchaseAvailable; public PeerColors peerColors; + public PeerColors profilePeerColors; + public int transcribeAudioTrialWeeklyNumber; + public int transcribeAudioTrialDurationMax; + public int transcribeAudioTrialCooldownUntil; + public int transcribeAudioTrialCurrentNumber; + public int recommendedChannelsLimitDefault; + public int recommendedChannelsLimitPremium; + public int boostsChannelLevelMax; public int channelsLimitDefault; public int channelsLimitPremium; @@ -1516,7 +1525,16 @@ public MessagesController(int num) { channelColorLevelMin = mainPreferences.getInt("channelColorLevelMin", 1); quoteLengthMax = mainPreferences.getInt("quoteLengthMax", 1024); giveawayGiftsPurchaseAvailable = mainPreferences.getBoolean("giveawayGiftsPurchaseAvailable", false); - peerColors = PeerColors.fromString(mainPreferences.getString("peerColors", "")); + peerColors = PeerColors.fromString(PeerColors.TYPE_NAME, mainPreferences.getString("peerColors", "")); + profilePeerColors = PeerColors.fromString(PeerColors.TYPE_PROFILE, mainPreferences.getString("profilePeerColors", "")); + transcribeAudioTrialWeeklyNumber = mainPreferences.getInt("transcribeAudioTrialWeeklyNumber", BuildVars.DEBUG_PRIVATE_VERSION ? 2 : 0); + transcribeAudioTrialCurrentNumber = mainPreferences.getInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialWeeklyNumber); + transcribeAudioTrialDurationMax = mainPreferences.getInt("transcribeAudioTrialDurationMax", 300); + transcribeAudioTrialCooldownUntil = mainPreferences.getInt("transcribeAudioTrialCooldownUntil", 0); + recommendedChannelsLimitDefault = mainPreferences.getInt("recommendedChannelsLimitDefault", 10); + recommendedChannelsLimitPremium = mainPreferences.getInt("recommendedChannelsLimitPremium", 100); + boostsChannelLevelMax = mainPreferences.getInt("boostsChannelLevelMax", 100); + scheduleTranscriptionUpdate(); // BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); if (mainPreferences.contains("dcDomainName2")) { dcDomainName = mainPreferences.getString("dcDomainName2", "apv3.stel.com"); @@ -1657,6 +1675,7 @@ public MessagesController(int num) { } } AndroidUtilities.runOnUIThread(this::loadAppConfig, 2000); + AndroidUtilities.runOnUIThread(() -> checkPeerColors(false), 400); topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); @@ -2289,8 +2308,8 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { boolean keelAliveChanged = false; resetAppConfig(); TLRPC.TL_jsonObject liteAppOptions = null; - TLRPC.TL_jsonObject peer_colors = null, dark_peer_colors = null; - TLRPC.TL_jsonArray peer_colors_available = null; + int transcribeAudioTrialWeeklyNumber = 0; + int transcribeAudioTrialCooldownUntil = 0; for (int a = 0, N = object.value.size(); a < N; a++) { TLRPC.TL_jsonObjectValue value = object.value.get(a); switch (value.key) { @@ -3588,29 +3607,69 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } - case "peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - peer_colors = (TLRPC.TL_jsonObject) value.value; + case "giveaway_gifts_purchase_available": { + if (value.value instanceof TLRPC.TL_jsonBool) { + if (giveawayGiftsPurchaseAvailable != ((TLRPC.TL_jsonBool) value.value).value) { + giveawayGiftsPurchaseAvailable = ((TLRPC.TL_jsonBool) value.value).value; + editor.putBoolean("giveawayGiftsPurchaseAvailable", giveawayGiftsPurchaseAvailable); + changed = true; + } } break; } - case "dark_peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - dark_peer_colors = (TLRPC.TL_jsonObject) value.value; + case "transcribe_audio_trial_weekly_number": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + transcribeAudioTrialWeeklyNumber = (int) num.value; } break; } - case "peer_colors_available": { - if (value.value instanceof TLRPC.TL_jsonArray) { - peer_colors_available = (TLRPC.TL_jsonArray) value.value; + case "transcribe_audio_trial_duration_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (transcribeAudioTrialDurationMax != num.value) { + transcribeAudioTrialDurationMax = (int) num.value; + editor.putInt("transcribeAudioTrialDurationMax", transcribeAudioTrialDurationMax); + changed = true; + } } break; } - case "giveaway_gifts_purchase_available": { - if (value.value instanceof TLRPC.TL_jsonBool) { - if (giveawayGiftsPurchaseAvailable != ((TLRPC.TL_jsonBool) value.value).value) { - giveawayGiftsPurchaseAvailable = ((TLRPC.TL_jsonBool) value.value).value; - editor.putBoolean("giveawayGiftsPurchaseAvailable", giveawayGiftsPurchaseAvailable); + case "transcribe_audio_trial_cooldown_until": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + transcribeAudioTrialCooldownUntil = (int) num.value; + } + break; + } + case "recommended_channels_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (recommendedChannelsLimitDefault != num.value) { + recommendedChannelsLimitDefault = (int) num.value; + editor.putInt("recommendedChannelsLimitDefault", recommendedChannelsLimitDefault); + changed = true; + } + } + break; + } + case "recommended_channels_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (recommendedChannelsLimitPremium != num.value) { + recommendedChannelsLimitPremium = (int) num.value; + editor.putInt("recommendedChannelsLimitPremium", recommendedChannelsLimitPremium); + changed = true; + } + } + break; + } + case "boosts_channel_level_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (boostsChannelLevelMax != num.value) { + boostsChannelLevelMax = (int) num.value; + editor.putInt("boostsChannelLevelMax", boostsChannelLevelMax); changed = true; } } @@ -3619,11 +3678,23 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } } - PeerColors newPeerColors = PeerColors.fromJSON(peer_colors, dark_peer_colors, peer_colors_available); - if (peerColors == null || !TextUtils.equals(peerColors.toString(), newPeerColors.toString())) { - peerColors = newPeerColors; - editor.putString("peerColors", peerColors.toString()); + if (transcribeAudioTrialWeeklyNumber != this.transcribeAudioTrialWeeklyNumber) { + this.transcribeAudioTrialWeeklyNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialWeeklyNumber", transcribeAudioTrialWeeklyNumber); + if (transcribeAudioTrialCurrentNumber <= 0 && (transcribeAudioTrialCooldownUntil == 0 || getConnectionsManager().getCurrentTime() > transcribeAudioTrialCooldownUntil)) { + transcribeAudioTrialCurrentNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber); + } else if (transcribeAudioTrialCurrentNumber > transcribeAudioTrialWeeklyNumber) { + transcribeAudioTrialCurrentNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber); + } + changed = true; + } + if (transcribeAudioTrialCooldownUntil != this.transcribeAudioTrialCooldownUntil) { + this.transcribeAudioTrialCooldownUntil = transcribeAudioTrialCooldownUntil; + editor.putInt("transcribeAudioTrialCooldownUntil", transcribeAudioTrialCooldownUntil); changed = true; + scheduleTranscriptionUpdate(); } if (changed) { @@ -3645,12 +3716,51 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { logDeviceStats(); } + public void updateTranscribeAudioTrialCurrentNumber(int num) { + if (num != transcribeAudioTrialCurrentNumber) { + transcribeAudioTrialCurrentNumber = num; + mainPreferences.edit() + .putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber) + .apply(); + } + } + + public void updateTranscribeAudioTrialCooldownUntil(int until) { + if (until != transcribeAudioTrialCooldownUntil) { + transcribeAudioTrialCooldownUntil = until; + mainPreferences.edit() + .putInt("transcribeAudioTrialCooldownUntil", transcribeAudioTrialCooldownUntil) + .apply(); + scheduleTranscriptionUpdate(); + } + } + + private void scheduleTranscriptionUpdate() { + AndroidUtilities.runOnUIThread(() -> { + AndroidUtilities.cancelRunOnUIThread(notifyTranscriptionAudioCooldownUpdate); + final long wait = transcribeAudioTrialCooldownUntil - getConnectionsManager().getCurrentTime(); + if (wait > 0) { + AndroidUtilities.runOnUIThread(notifyTranscriptionAudioCooldownUpdate, wait); + } + }); + } + private final Runnable notifyTranscriptionAudioCooldownUpdate = () -> getNotificationCenter().postNotificationName(NotificationCenter.updateTranscriptionLock); + public static class PeerColors { + public static final int TYPE_NAME = 0; + public static final int TYPE_PROFILE = 1; + + public final int type; + public final int hash; + public final ArrayList colors = new ArrayList<>(); private final LongSparseArray colorsById = new LongSparseArray<>(); - private PeerColors() {} + private PeerColors(int type, int hash) { + this.type = type; + this.hash = hash; + } @Nullable public PeerColor getColor(int colorId) { @@ -3660,6 +3770,9 @@ public PeerColor getColor(int colorId) { @NonNull public String toString() { StringBuilder sb = new StringBuilder(); + if (hash != 0) { + sb.append("@").append(hash).append("^"); + } for (int i = 0; i < colors.size(); ++i) { PeerColor color = colors.get(i); if (i > 0) sb.append(";"); @@ -3668,15 +3781,24 @@ public String toString() { return sb.toString(); } - public static PeerColors fromString(String str) { + public static PeerColors fromString(int type, String str) { if (str == null) return null; - final PeerColors peerColors = new PeerColors(); + int hash = 0; + if (str.startsWith("@")) { + int index = str.indexOf("^"); + if (index >= 0) { + hash = Utilities.parseInt(str.substring(1, index)); + str = str.substring(index + 1); + } + } + final PeerColors peerColors = new PeerColors(type, hash); final String[] colorParts = str.split(";"); for (int i = 0; i < colorParts.length; ++i) { PeerColor peerColor = PeerColor.fromString(colorParts[i]); if (peerColor == null) continue; - peerColors.colors.add(peerColor); + if (!peerColor.hidden) + peerColors.colors.add(peerColor); peerColors.colorsById.put(peerColor.id, peerColor); } return peerColors; @@ -3685,14 +3807,34 @@ public static PeerColors fromString(String str) { private static int color(String str) { return Integer.parseUnsignedInt("ff" + str, 16); } + + public static PeerColors fromTL(int type, TLRPC.TL_help_peerColors tl) { + if (tl == null) return null; + try { + PeerColors peerColors = new PeerColors(type, tl.hash); + for (int i = 0; i < tl.colors.size(); ++i) { + PeerColor peerColor = PeerColor.fromTL(tl.colors.get(i)); + if (peerColor == null) continue; + if (peerColor.id < 7 && type == TYPE_NAME) continue; + if (!peerColor.hidden) + peerColors.colors.add(peerColor); + peerColors.colorsById.put(peerColor.id, peerColor); + } + return peerColors; + } catch (Exception e) { + FileLog.e(e); + } + return null; + } public static PeerColors fromJSON( + int type, TLRPC.TL_jsonObject peer_colors, TLRPC.TL_jsonObject dark_peer_colors, TLRPC.TL_jsonArray peer_colors_available ) { try { - PeerColors peerColors = new PeerColors(); + PeerColors peerColors = new PeerColors(type, 0); if (peer_colors != null) { for (TLRPC.TL_jsonObjectValue pair : peer_colors.value) { final int id = Utilities.parseInt(pair.key); @@ -3705,14 +3847,13 @@ public static PeerColors fromJSON( PeerColor peerColor = new PeerColor(); try { peerColor.id = id; - peerColor.color1 = peerColor.darkColor1 = color(((TLRPC.TL_jsonString) val.get(0)).value); - peerColor.color2 = peerColor.darkColor2 = val.size() > 1 ? color(((TLRPC.TL_jsonString) val.get(1)).value) : peerColor.color1; - peerColor.color3 = peerColor.darkColor3 = val.size() > 2 ? color(((TLRPC.TL_jsonString) val.get(2)).value) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.colors[i] = peerColor.darkColors[i] = val.size() > i ? color(((TLRPC.TL_jsonString) val.get(i)).value) : peerColor.colors[0]; } catch (Exception e2) { FileLog.e(e2); continue; } - if (peerColor.id < 7) continue; + if (type == TYPE_NAME && peerColor.id < 7) continue; peerColors.colorsById.put(id, peerColor); } } @@ -3729,9 +3870,8 @@ public static PeerColors fromJSON( if (peerColor == null) continue; try { peerColor.id = id; - peerColor.darkColor1 = color(((TLRPC.TL_jsonString) val.get(0)).value); - peerColor.darkColor2 = val.size() > 1 ? color(((TLRPC.TL_jsonString) val.get(1)).value) : peerColor.darkColor1; - peerColor.darkColor3 = val.size() > 2 ? color(((TLRPC.TL_jsonString) val.get(2)).value) : peerColor.darkColor1; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = val.size() > i ? color(((TLRPC.TL_jsonString) val.get(i)).value) : peerColor.darkColors[0]; } catch (Exception e2) { FileLog.e(e2); continue; @@ -3760,16 +3900,44 @@ public static PeerColors fromJSON( public static class PeerColor { public int id; - private int color1, color2, color3; - private int darkColor1, darkColor2, darkColor3; + public boolean hidden; + private final int[] colors = new int[6]; + private final int[] darkColors = new int[6]; + public int getColor1(boolean isDark) { + return (isDark ? darkColors : colors)[0]; + } + public int getColor2(boolean isDark) { + return (isDark ? darkColors : colors)[1]; + } + public int getColor3(boolean isDark) { + return (isDark ? darkColors : colors)[2]; + } + public int getColor4(boolean isDark) { + return (isDark ? darkColors : colors)[3]; + } + public int getColor5(boolean isDark) { + return (isDark ? darkColors : colors)[4]; + } + public int getColor6(boolean isDark) { + return (isDark ? darkColors : colors)[5]; + } public int getColor1() { - return Theme.isCurrentThemeDark() ? darkColor1 : color1; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[0]; } public int getColor2() { - return Theme.isCurrentThemeDark() ? darkColor2 : color2; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[1]; } public int getColor3() { - return Theme.isCurrentThemeDark() ? darkColor3 : color3; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[2]; + } + public int getColor4() { + return (Theme.isCurrentThemeDark() ? darkColors : colors)[3]; + } + public int getColor5() { + return (Theme.isCurrentThemeDark() ? darkColors : colors)[4]; + } + public int getColor6() { + return (Theme.isCurrentThemeDark() ? darkColors : colors)[5]; } public boolean hasColor2() { return getColor2() != getColor1(); @@ -3777,55 +3945,149 @@ public boolean hasColor2() { public boolean hasColor3() { return getColor3() != getColor1(); } + public boolean hasColor2(boolean isDark) { + return getColor2(isDark) != getColor1(isDark); + } + public boolean hasColor3(boolean isDark) { + return getColor3(isDark) != getColor1(isDark); + } + public boolean hasColor6(boolean isDark) { + return getColor6(isDark) != getColor1(isDark); + } + public int getBgColor1(boolean isDark) { + return hasColor6(isDark) ? getColor3(isDark) : getColor2(isDark); + } + public int getBgColor2(boolean isDark) { + return hasColor6(isDark) ? getColor4(isDark) : getColor2(isDark); + } + public int getStoryColor1(boolean isDark) { + return hasColor6(isDark) ? getColor5(isDark) : getColor3(isDark); + } + public int getStoryColor2(boolean isDark) { + return hasColor6(isDark) ? getColor6(isDark) : getColor4(isDark); + } + public int getAvatarColor1() { + return ColorUtils.blendARGB(getBgColor2(false), getStoryColor2(false), .5f); + } + public int getAvatarColor2() { + return ColorUtils.blendARGB(getBgColor1(false), getStoryColor1(false), .5f); + } public void appendString(StringBuilder sb) { sb.append("#"); + if (hidden) sb.append("H"); sb.append(id); sb.append("{"); - sb.append(color1); - if (color2 != color1) { + sb.append(colors[0]); + if (colors[1] != colors[0]) { sb.append(","); - sb.append(color2); - if (color3 != color1) { + sb.append(colors[1]); + if (colors[2] != colors[0] || colors[3] != colors[0]) { sb.append(","); - sb.append(color3); + sb.append(colors[2]); + sb.append(","); + sb.append(colors[3]); + if (colors[4] != colors[0] || colors[5] != colors[0]) { + sb.append(","); + sb.append(colors[4]); + sb.append(","); + sb.append(colors[5]); + } } } - if (darkColor1 != color1 || darkColor2 != color2 || darkColor3 != color3) { + if (darkColors[0] != colors[0] || darkColors[1] != colors[1] || darkColors[2] != colors[2]) { sb.append("@"); - sb.append(darkColor1); - if (darkColor2 != darkColor1) { + sb.append(darkColors[0]); + if (darkColors[1] != darkColors[0]) { sb.append(","); - sb.append(darkColor2); - if (darkColor3 != darkColor1) { + sb.append(darkColors[1]); + if (darkColors[2] != darkColors[0] || darkColors[3] != darkColors[0]) { sb.append(","); - sb.append(darkColor3); + sb.append(darkColors[2]); + sb.append(","); + sb.append(darkColors[3]); + if (darkColors[4] != darkColors[0] || darkColors[5] != darkColors[0]) { + sb.append(","); + sb.append(darkColors[4]); + sb.append(","); + sb.append(darkColors[5]); + } } } } sb.append("}"); } + + public static PeerColor fromTL(TLRPC.TL_help_peerColorOption tl) { + if (tl == null) return null; + + final PeerColor peerColor = new PeerColor(); + peerColor.id = tl.color_id; + peerColor.hidden = tl.hidden; + + System.arraycopy(optionToColors(tl.colors), 0, peerColor.colors, 0, 6); + System.arraycopy(optionToColors(tl.dark_colors), 0, peerColor.darkColors, 0, 6); + return peerColor; + } + + public static int[] optionToColors(TLRPC.help_PeerColorSet set) { + final int[] colors = new int[] {0, 0, 0, 0, 0, 0}; + ArrayList finalColorList = null; + if (set instanceof TLRPC.TL_help_peerColorSet) { + finalColorList = ((TLRPC.TL_help_peerColorSet) set).colors; + } else if (set instanceof TLRPC.TL_help_peerColorProfileSet) { + ArrayList colorList1 = ((TLRPC.TL_help_peerColorProfileSet) set).palette_colors; + ArrayList colorList2 = ((TLRPC.TL_help_peerColorProfileSet) set).bg_colors; + ArrayList colorList3 = ((TLRPC.TL_help_peerColorProfileSet) set).story_colors; + finalColorList = new ArrayList(); + if (colorList1 != null) { + for (int i = 0; i < Math.min(2, colorList1.size()); ++i) + finalColorList.add(colorList1.get(i)); + } + if (colorList2 != null) { + for (int i = 0; i < Math.min(2, colorList2.size()); ++i) + finalColorList.add(colorList2.get(i)); + } + if (colorList3 != null) { + for (int i = 0; i < Math.min(2, colorList3.size()); ++i) + finalColorList.add(colorList3.get(i)); + } + } + if (finalColorList != null) { + if (finalColorList.size() > 0) { + Arrays.fill(colors, 0xFF000000 | finalColorList.get(0)); + } + for (int i = 0; i < Math.min(colors.length, finalColorList.size()); ++i) { + colors[i] = 0xFF000000 | finalColorList.get(i); + } + } + return colors; + } + public static PeerColor fromString(String string) { if (string == null || string.isEmpty() || string.charAt(0) != '#') return null; + int startIndex = 1; + boolean hidden = string.length() > 1 && string.charAt(1) == 'H'; + if (hidden) { + startIndex++; + } int index = string.indexOf('{'); if (index < 0) return null; try { final PeerColor peerColor = new PeerColor(); - peerColor.id = Utilities.parseInt(string.substring(1, index)); + peerColor.id = Utilities.parseInt(string.substring(startIndex, index)); + peerColor.hidden = hidden; final String[] parts = string.substring(index + 1, string.length() - 1).split("@"); String[] colorsString = parts[0].split(","); - peerColor.color1 = Utilities.parseInt(colorsString[0]); - peerColor.color2 = colorsString.length >= 2 ? Utilities.parseInt(colorsString[1]) : peerColor.color1; - peerColor.color3 = colorsString.length >= 3 ? Utilities.parseInt(colorsString[2]) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.colors[i] = colorsString.length >= i + 1 ? Utilities.parseInt(colorsString[i]) : peerColor.colors[0]; if (parts.length >= 2) { colorsString = parts[1].split(","); - peerColor.darkColor1 = Utilities.parseInt(colorsString[0]); - peerColor.darkColor2 = colorsString.length >= 2 ? Utilities.parseInt(colorsString[1]) : peerColor.color1; - peerColor.darkColor3 = colorsString.length >= 3 ? Utilities.parseInt(colorsString[2]) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = colorsString.length >= i + 1 ? Utilities.parseInt(colorsString[i]) : peerColor.darkColors[0]; } else { - peerColor.darkColor1 = peerColor.color1; - peerColor.darkColor2 = peerColor.color2; - peerColor.darkColor3 = peerColor.color3; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = peerColor.colors[i]; } return peerColor; } catch (Exception e) { @@ -3913,9 +4175,9 @@ public void removeSuggestion(long did, String suggestion) { public void updateConfig(final TLRPC.TL_config config) { AndroidUtilities.runOnUIThread(() -> { - // TODO: receive those removed parameters from appconfig getDownloadController().loadAutoDownloadConfig(false); - loadAppConfig(); + loadAppConfig(true); + checkPeerColors(true); thisDc = config.this_dc; remoteConfigLoaded = true; maxMegagroupCount = config.megagroup_size_max; @@ -4286,7 +4548,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } } AndroidUtilities.runOnUIThread(() -> { - if (uploadingWallpaper != null && wallPaper != null) { + if (uploadingWallpaper != null && uploadingWallpaperInfo.requestIds != null && wallPaper != null) { wallPaper.settings = settings; wallPaper.flags |= 4; overrideWallpaperInfo.slug = wallPaper.slug; @@ -4301,7 +4563,7 @@ public void didReceivedNotification(int id, int account, Object... args) { ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForDocument(image, wallPaper.document), false); } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.wallpapersNeedReload, wallPaper.slug); - if (overrideWallpaperInfo.dialogId != 0) { + if (uploadingWallpaperInfo.requestIds != null && overrideWallpaperInfo.dialogId != 0) { uploadingWallpaperInfo.requestIds.add(ChatThemeController.getInstance(currentAccount).setWallpaperToUser(overrideWallpaperInfo.dialogId, uploadingWallpaperFinal, overrideWallpaperInfo, null, null)); } } @@ -5632,6 +5894,7 @@ public void loadFullChat(long chatId, int classGuid, boolean force) { dialog.ttl_period = res.full_chat.ttl_period; getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } + dialog.view_forum_as_messages = res.full_chat.view_forum_as_messages; } }); } else { @@ -14321,14 +14584,18 @@ public void loadPinnedDialogs(final int folderId, long newDialogId, ArrayList { - putUsers(res.users, false); - putChats(res.chats, false); - }); - getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); - - ArrayList pushMessages; - if (createMessage && Math.abs(getConnectionsManager().getCurrentTime() - res.participant.date) < 24 * 60 * 60 && !getMessagesStorage().hasInviteMeMessage(chatId)) { - TLRPC.TL_messageService message = new TLRPC.TL_messageService(); - message.media_unread = true; - message.unread = true; - message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; - message.post = true; - message.local_id = message.id = getUserConfig().getNewMessageId(); - message.date = res.participant.date; - if (selfParticipant.inviter_id != getUserConfig().getClientUserId()) { - message.action = new TLRPC.TL_messageActionChatAddUser(); - } else if (selfParticipant.via_invite) { - message.action = new TLRPC.TL_messageActionChatJoinedByRequest(); - } - message.from_id = new TLRPC.TL_peerUser(); - message.from_id.user_id = res.participant.inviter_id; - message.action.users.add(getUserConfig().getClientUserId()); - message.peer_id = new TLRPC.TL_peerChannel(); - message.peer_id.channel_id = chatId; - message.dialog_id = -chatId; - getUserConfig().saveConfig(false); - - pushMessages = new ArrayList<>(); - ArrayList messagesArr = new ArrayList<>(); - - ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersDict.put(user.id, user); - } + if (chat.megagroup && getMessagesStorage().isMigratedChat(chat.id)) { + return; + } + AndroidUtilities.runOnUIThread(() -> { + putUsers(res.users, false); + putChats(res.chats, false); + }); + getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); - messagesArr.add(message); - MessageObject obj = new MessageObject(currentAccount, message, usersDict, true, false); - pushMessages.add(obj); - getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, true, false, null))); - getMessagesStorage().putMessages(messagesArr, true, true, false, 0, false, 0); + ArrayList pushMessages; + if (createMessage && Math.abs(getConnectionsManager().getCurrentTime() - res.participant.date) < 24 * 60 * 60 && !getMessagesStorage().hasInviteMeMessage(chatId)) { + TLRPC.TL_messageService message = new TLRPC.TL_messageService(); + message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.local_id = message.id = getUserConfig().getNewMessageId(); + message.date = res.participant.date; + message.from_id = new TLRPC.TL_peerUser(); + message.from_id.user_id = res.participant.inviter_id; + message.peer_id = new TLRPC.TL_peerChannel(); + message.peer_id.channel_id = chatId; + message.media_unread = true; + message.unread = true; + message.post = true; + if (!selfParticipant.via_invite || selfParticipant.inviter_id != getUserConfig().getClientUserId()) { + message.action = new TLRPC.TL_messageActionChatAddUser(); } else { - pushMessages = null; + message.action = new TLRPC.TL_messageActionChatJoinedByRequest(); } + message.action.users.add(getUserConfig().getClientUserId()); + message.dialog_id = -chatId; + getUserConfig().saveConfig(false); - getMessagesStorage().saveChatInviter(chatId, res.participant.inviter_id); + pushMessages = new ArrayList<>(); + ArrayList messagesArr = new ArrayList<>(); - AndroidUtilities.runOnUIThread(() -> { - gettingChatInviters.delete(chatId); - if (pushMessages != null) { - updateInterfaceWithMessages(-chatId, pushMessages, false); - getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); - } - getNotificationCenter().postNotificationName(NotificationCenter.didLoadChatInviter, chatId, res.participant.inviter_id); - }); + ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + + messagesArr.add(message); + MessageObject obj = new MessageObject(currentAccount, message, usersDict, true, false); + pushMessages.add(obj); + getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, true, false, null))); + getMessagesStorage().putMessages(messagesArr, true, true, false, 0, false, 0); + } else { + pushMessages = null; } + + getMessagesStorage().saveChatInviter(chatId, res.participant.inviter_id); + + AndroidUtilities.runOnUIThread(() -> { + gettingChatInviters.delete(chatId); + if (pushMessages != null) { + updateInterfaceWithMessages(-chatId, pushMessages, false); + getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); + } + getNotificationCenter().postNotificationName(NotificationCenter.didLoadChatInviter, chatId, res.participant.inviter_id); + }); } }); } @@ -14596,6 +14861,8 @@ public static long getUpdateChannelId(TLRPC.Update update) { return ((TLRPC.TL_updateChannelUserTyping) update).channel_id; } else if (update instanceof TLRPC.TL_updatePinnedChannelMessages) { return ((TLRPC.TL_updatePinnedChannelMessages) update).channel_id; + } else if (update instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + return ((TLRPC.TL_updateChannelViewForumAsMessages) update).channel_id; } else { if (BuildVars.LOGS_ENABLED) { FileLog.e("trying to get unknown update channel_id for " + update); @@ -15651,6 +15918,11 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updatePeerWallpaper) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateUserEmojiStatus) { interfaceUpdateMask |= UPDATE_MASK_EMOJI_STATUS; if (updatesOnMainThread == null) { @@ -16415,6 +16687,11 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -16554,6 +16831,9 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList reactions, Utilities.Callback onError, Runnable onSuccess) { + TLRPC.TL_messages_setChatAvailableReactions req = new TLRPC.TL_messages_setChatAvailableReactions(); + req.peer = getInputPeer(-chatId); + if (type == ChatReactionsEditActivity.SELECT_TYPE_NONE || reactions.isEmpty()) { + req.available_reactions = new TLRPC.TL_chatReactionsNone(); + } else if (type == ChatReactionsEditActivity.SELECT_TYPE_ALL) { + req.available_reactions = new TLRPC.TL_chatReactionsAll(); + } else { + TLRPC.TL_chatReactionsSome someReactions = new TLRPC.TL_chatReactionsSome(); + req.available_reactions = someReactions; + someReactions.reactions.addAll(reactions); + } + getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + TLRPC.ChatFull full = getChatFull(chatId); + if (full != null) { + if (full instanceof TLRPC.TL_chatFull) { + full.flags |= 262144; + } + if (full instanceof TLRPC.TL_channelFull) { + full.flags |= 1073741824; + } + full.available_reactions = req.available_reactions; + getMessagesStorage().updateChatInfo(full, false); + } + AndroidUtilities.runOnUIThread(() -> { + if (onSuccess != null) { + onSuccess.run(); + } + getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + if (onError != null) { + onError.run(error); + } + }); + } + }); + } + public void setChatReactions(long chatId, int type, List reactions) { TLRPC.TL_messages_setChatAvailableReactions req = new TLRPC.TL_messages_setChatAvailableReactions(); req.peer = getInputPeer(-chatId); @@ -19448,4 +19793,85 @@ public boolean storyEntitiesAllowed(TLRPC.User user) { return false; } } + + public static class ChannelRecommendations { + public boolean wasPremium; + public final ArrayList chats = new ArrayList<>(); + public int more; + + public static boolean hasRecommendations(ChannelRecommendations rec) { + return rec != null && !rec.chats.isEmpty(); + } + + public static boolean hasRecommendations(int currentAccount, long chatId) { + return hasRecommendations(MessagesController.getInstance(currentAccount).getChannelRecommendations(chatId)); + } + } + + private HashMap cachedChannelRecommendations; + public ChannelRecommendations getChannelRecommendations(long chatId) { + TLRPC.InputChannel inputChannel = getInputChannel(chatId); + if (inputChannel == null) { + return null; + } + if (cachedChannelRecommendations == null) { + cachedChannelRecommendations = new HashMap<>(); + } + final boolean isPremium = getUserConfig().isPremium(); + ChannelRecommendations rec = null; + if (cachedChannelRecommendations.containsKey(chatId)) { + rec = cachedChannelRecommendations.get(chatId); + if (rec != null && rec.wasPremium == isPremium) { + return rec; + } + } + cachedChannelRecommendations.put(chatId, null); + TLRPC.TL_channels_getChannelRecommendations req = new TLRPC.TL_channels_getChannelRecommendations(); + req.channel = inputChannel; + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.messages_Chats) { + ArrayList chats = ((TLRPC.messages_Chats) res).chats; + putChats(chats, false); + + ChannelRecommendations newrec = new ChannelRecommendations(); + newrec.wasPremium = isPremium; + newrec.chats.addAll(chats); + if (res instanceof TLRPC.TL_messages_chatsSlice) { + newrec.more = Math.max(0, ((TLRPC.TL_messages_chatsSlice) res).count - chats.size()); + } else if (!getUserConfig().isPremium() && BuildVars.DEBUG_PRIVATE_VERSION) { + newrec.more = 90; + } + cachedChannelRecommendations.put(chatId, newrec); + getNotificationCenter().postNotificationName(NotificationCenter.channelRecommendationsLoaded, chatId); + } + })); + return rec; + } + + public void checkPeerColors(boolean force) { + if (peerColors == null || force) { + TLRPC.TL_help_getPeerColors req = new TLRPC.TL_help_getPeerColors(); + req.hash = peerColors != null ? peerColors.hash : 0; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_help_peerColors) { + AndroidUtilities.runOnUIThread(() -> { + peerColors = PeerColors.fromTL(PeerColors.TYPE_NAME, (TLRPC.TL_help_peerColors) res); + mainPreferences.edit().putString("peerColors", peerColors.toString()).apply(); + }); + } + }); + } + if (profilePeerColors == null || force) { + TLRPC.TL_help_getPeerProfileColors req = new TLRPC.TL_help_getPeerProfileColors(); + req.hash = profilePeerColors != null ? profilePeerColors.hash : 0; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_help_peerColors) { + AndroidUtilities.runOnUIThread(() -> { + profilePeerColors = PeerColors.fromTL(PeerColors.TYPE_PROFILE, (TLRPC.TL_help_peerColors) res); + mainPreferences.edit().putString("profilePeerColors", profilePeerColors.toString()).apply(); + }); + } + }); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 32c3ff44bd..479fc4ca3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -2077,6 +2077,7 @@ private TLRPC.messages_Dialogs loadDialogsByIds(String ids, ArrayList user dialog.unread_mentions_count = cursor.intValue(15); int dialog_flags = cursor.intValue(16); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; long flags = cursor.longValue(8); int low_flags = (int) flags; dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); @@ -8425,6 +8426,9 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count data = cursor.byteBufferValue(6); if (data != null) { message.replyStory = TL_stories.StoryItem.TLdeserialize(data, data.readInt32(false), false); + if (message.replyStory != null && message.replyStory.fwd_from != null) { + addLoadPeerInfo(message.replyStory.fwd_from.from, usersToLoad, chatsToLoad); + } data.reuse(); } } @@ -11289,7 +11293,7 @@ private void putMessagesInternal(ArrayList messages, boolean with dids.add(key); if (exists) { - if (messageId >= last_mid || DialogObject.isEncryptedDialog(key)) { + if (message == null || message.date > dialog_date || DialogObject.isEncryptedDialog(key)) { state_dialogs_update.requery(); state_dialogs_update.bindInteger(1, message != null && (!doNotUpdateDialogDate || dialog_date == 0) ? message.date : dialog_date); state_dialogs_update.bindInteger(2, old_unread_count + unread_count); @@ -11586,7 +11590,7 @@ private void createOrEditTopic(long dialogId, TLRPC.Message message) { forumTopic.topicStartMessage = message; forumTopic.top_message = message.id; forumTopic.topMessage = message; - forumTopic.from_id = getMessagesController().getPeer(getUserConfig().clientUserId); + forumTopic.from_id = message.from_id; forumTopic.notify_settings = new TLRPC.TL_peerNotifySettings(); forumTopic.unread_count = 0; @@ -12789,6 +12793,7 @@ private void updateDialogsWithDeletedMessagesInternal(long originalDialogId, lon dialog.pinned = dialog.pinnedNum != 0; int dialog_flags = cursor.intValue(14); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; dialog.folder_id = cursor.intValue(15); dialog.unread_reactions_count = cursor.intValue(17); long groupMessagesId = cursor.longValue(18); @@ -14188,6 +14193,19 @@ public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList< } } } + if (message.media instanceof TLRPC.TL_messageMediaStory && message.media.storyItem != null && message.media.storyItem.fwd_from != null) { + addLoadPeerInfo(message.media.storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } + if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage != null && message.media.webpage.attributes != null) { + for (int i = 0; i < message.media.webpage.attributes.size(); ++i) { + if (message.media.webpage.attributes.get(i) instanceof TLRPC.TL_webPageAttributeStory) { + TLRPC.TL_webPageAttributeStory attr = (TLRPC.TL_webPageAttributeStory) message.media.webpage.attributes.get(i); + if (attr.storyItem != null && attr.storyItem.fwd_from != null) { + addLoadPeerInfo(attr.storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } + } + } + } if (message.media.peer != null) { addLoadPeerInfo(message.media.peer, usersToLoad, chatsToLoad); } @@ -14220,7 +14238,7 @@ public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList< } } - private static void addLoadPeerInfo(TLRPC.Peer peer, ArrayList usersToLoad, ArrayList chatsToLoad) { + public static void addLoadPeerInfo(TLRPC.Peer peer, ArrayList usersToLoad, ArrayList chatsToLoad) { if (peer instanceof TLRPC.TL_peerUser) { if (!usersToLoad.contains(peer.user_id)) { usersToLoad.add(peer.user_id); @@ -14321,6 +14339,7 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe dialog.unread_mentions_count = cursor.intValue(15); int dialog_flags = cursor.intValue(16); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; long flags = cursor.longValue(8); int low_flags = (int) flags; dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); @@ -14829,6 +14848,9 @@ private void putDialogsInternal(TLRPC.messages_Dialogs dialogs, int check) { if (dialog.unread_mark) { flags |= 1; } + if (dialog.view_forum_as_messages) { + flags |= 64; + } state_dialogs.bindInteger(12, flags); state_dialogs.bindInteger(13, dialog.folder_id); NativeByteBuffer data; @@ -15138,6 +15160,46 @@ public void setDialogUnread(long did, boolean unread) { }); } + public void setDialogViewThreadAsMessages(long did, boolean enabled) { + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + int flags = 0; + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT flags FROM dialogs WHERE did = " + did); + if (cursor.next()) { + flags = cursor.intValue(0); + } + } catch (Exception e) { + checkSQLException(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + + if (enabled) { + flags |= 64; + } else { + flags &= ~64; + } + + state = database.executeFast("UPDATE dialogs SET flags = ? WHERE did = ?"); + state.bindInteger(1, flags); + state.bindLong(2, did); + state.step(); + state.dispose(); + } catch (Exception e) { + checkSQLException(e); + } finally { + if (state != null) { + state.dispose(); + } + } + }); + } + public void resetAllUnreadCounters(boolean muted) { for (int a = 0, N = dialogFilters.size(); a < N; a++) { MessagesController.DialogFilter filter = dialogFilters.get(a); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 8c9ed5dc14..dcd1f03d8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -137,6 +137,7 @@ public class NotificationCenter { public static final int animatedEmojiDocumentLoaded = totalEvents++; public static final int recentEmojiStatusesUpdate = totalEvents++; public static final int updateSearchSettings = totalEvents++; + public static final int updateTranscriptionLock = totalEvents++; public static final int messageTranslated = totalEvents++; public static final int messageTranslating = totalEvents++; @@ -221,6 +222,7 @@ public class NotificationCenter { public static final int storiesSendAsUpdate = totalEvents++; public static final int unconfirmedAuthUpdate = totalEvents++; public static final int dialogPhotosUpdate = totalEvents++; + public static final int channelRecommendationsLoaded = totalEvents++; //global public static final int pushMessagesUpdated = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index edacf57d9f..e6560b15ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -155,6 +155,8 @@ public TLRPC.InputReplyTo createReplyInput(TLRPC.InputPeer sendToPeer, int reply replyTo.quote_entities = new ArrayList<>(replyTo.quote_entities); replyTo.flags |= 8; } + replyTo.flags |= 16; + replyTo.quote_offset = replyQuote.start; } } if (replyQuote != null && replyQuote.message != null) { @@ -188,6 +190,10 @@ public TLRPC.InputReplyTo createReplyInput(TLRPC.TL_messageReplyHeader replyHead replyTo.flags |= 8; replyTo.quote_entities = replyHeader.quote_entities; } + if ((replyHeader.flags & 1024) != 0) { + replyTo.flags |= 16; + replyTo.quote_offset = replyHeader.quote_offset; + } } return replyTo; } @@ -3866,6 +3872,8 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (!TextUtils.isEmpty(newMsg.reply_to.quote_text)) { newMsg.reply_to.quote = true; newMsg.reply_to.flags |= 64; + newMsg.reply_to.flags |= 1024; + newMsg.reply_to.quote_offset = replyQuote.start; newMsg.reply_to.quote_entities = replyQuote.getEntities(); if (newMsg.reply_to.quote_entities != null && !newMsg.reply_to.quote_entities.isEmpty()) { newMsg.reply_to.quote_entities = new ArrayList<>(newMsg.reply_to.quote_entities); @@ -3986,6 +3994,8 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (replyQuote.getText() != null) { newMsg.reply_to.flags |= 64; newMsg.reply_to.quote_text = replyQuote.getText(); + newMsg.reply_to.flags |= 1024; + newMsg.reply_to.quote_offset = replyQuote.start; } if (replyQuote.getEntities() != null) { newMsg.reply_to.flags |= 128; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index c07fbd53b1..9f463f7484 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -373,6 +373,7 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { public static int storiesColumnsCount = 3; public static int fastScrollHintCount = 3; public static boolean dontAskManageStorage; + public static boolean multipleReactionsPromoShowed; public static boolean translateChats = true; @@ -1550,6 +1551,7 @@ public static void loadConfig() { useSurfaceInStories = preferences.getBoolean("useSurfaceInStories", Build.VERSION.SDK_INT >= 30); payByInvoice = preferences.getBoolean("payByInvoice", false); photoViewerBlur = preferences.getBoolean("photoViewerBlur", true); + multipleReactionsPromoShowed = preferences.getBoolean("multipleReactionsPromoShowed", false); loadDebugConfig(preferences); @@ -1759,6 +1761,14 @@ public static void clearConfig() { saveConfig(); } + public static void setMultipleReactionsPromoShowed(boolean val) { + multipleReactionsPromoShowed = val; + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("multipleReactionsPromoShowed", multipleReactionsPromoShowed); + editor.apply(); + } + public static void setSuggestStickers(int type) { suggestStickers = type; SharedPreferences preferences = MessagesController.getGlobalMainSettings(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index a52e23562c..5822315adb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -658,6 +658,13 @@ public void toggleShowTopic(long chatId, int topicId, boolean show) { }); } + public void toggleViewForumAsMessages(long channelId, boolean enabled) { + TLRPC.TL_channels_toggleViewForumAsMessages request = new TLRPC.TL_channels_toggleViewForumAsMessages(); + request.channel_id = getMessagesController().getInputChannel(channelId); + request.enabled = enabled; + getConnectionsManager().sendRequest(request, null); + } + public void pinTopic(long chatId, int topicId, boolean pin, BaseFragment fragment) { TLRPC.TL_channels_updatePinnedForumTopic req = new TLRPC.TL_channels_updatePinnedForumTopic(); req.channel = getMessagesController().getInputChannel(chatId); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 8aea32280d..2f3cb2cef5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -280,7 +280,7 @@ private void checkPremiumSelf(TLRPC.User oldUser, TLRPC.User newUser) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.premiumStatusChangedGlobal); getMediaDataController().loadPremiumPromo(false); - getMediaDataController().loadReactions(false, true); + getMediaDataController().loadReactions(false, null); getMessagesController().getStoriesController().invalidateStoryLimit(); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index 0b7ca6b2e9..3a7bcbb195 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -144,4 +144,33 @@ public static Long getEmojiStatusDocumentId(TLRPC.EmojiStatus emojiStatus) { public static boolean isService(long user_id) { return user_id == 333000 || user_id == 777000 || user_id == 42777; } + + public static MessagesController.PeerColor getPeerColorForAvatar(int currentAccount, TLRPC.User user) { + if (user != null && user.profile_color != null && user.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { + return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(user.profile_color.color); + } + return null; + } + + public static int getColorId(TLRPC.User user) { + if (user == null) return 0; + if (user.color != null && (user.color.flags & 1) != 0) return user.color.color; + return (int) (user.id % 7); + } + + public static long getEmojiId(TLRPC.User user) { + if (user != null && user.color != null && (user.color.flags & 2) != 0) return user.color.background_emoji_id; + return 0; + } + + public static int getProfileColorId(TLRPC.User user) { + if (user == null) return 0; + if (user.profile_color != null && (user.profile_color.flags & 1) != 0) return user.profile_color.color; + return -1; + } + + public static long getProfileEmojiId(TLRPC.User user) { + if (user != null && user.profile_color != null && (user.profile_color.flags & 2) != 0) return user.profile_color.background_emoji_id; + return 0; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index 001798c0d4..b8a7e7d38a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -109,11 +109,12 @@ public void serializeToStream(AbstractSerializedData stream) { public static class MediaEntity { - public static final int TYPE_STICKER = 0; - public static final int TYPE_TEXT = 1; - public static final int TYPE_PHOTO = 2; - public static final int TYPE_LOCATION = 3; + public static final byte TYPE_STICKER = 0; + public static final byte TYPE_TEXT = 1; + public static final byte TYPE_PHOTO = 2; + public static final byte TYPE_LOCATION = 3; public static final byte TYPE_REACTION = 4; + public static final byte TYPE_ROUND = 5; public byte type; public byte subType; @@ -152,12 +153,19 @@ public static class MediaEntity { public View view; public Canvas canvas; public AnimatedFileDrawable animatedFileDrawable; + public boolean looped; public Canvas roundRadiusCanvas; + public boolean firstSeek; public TL_stories.MediaArea mediaArea; public TLRPC.MessageMedia mediaGeo; public float density; + public long roundOffset; + public long roundLeft; + public long roundRight; + public long roundDuration; + public int W, H; public ReactionsLayoutInBubble.VisibleReaction visibleReaction; @@ -217,6 +225,12 @@ public MediaEntity(AbstractSerializedData data, boolean full) { if (type == TYPE_REACTION) { mediaArea = TL_stories.MediaArea.TLdeserialize(data, data.readInt32(false), false); } + if (type == TYPE_ROUND) { + roundOffset = data.readInt64(false); + roundLeft = data.readInt64(false); + roundRight = data.readInt64(false); + roundDuration = data.readInt64(false); + } } public void serializeTo(AbstractSerializedData data, boolean full) { @@ -273,6 +287,12 @@ public void serializeTo(AbstractSerializedData data, boolean full) { if (type == TYPE_REACTION) { mediaArea.serializeToStream(data); } + if (type == TYPE_ROUND) { + data.writeInt64(roundOffset); + data.writeInt64(roundLeft); + data.writeInt64(roundRight); + data.writeInt64(roundDuration); + } } public MediaEntity copy() { @@ -320,6 +340,10 @@ public MediaEntity copy() { entity.W = W; entity.H = H; entity.visibleReaction = visibleReaction; + entity.roundOffset = roundOffset; + entity.roundDuration = roundDuration; + entity.roundLeft = roundLeft; + entity.roundRight = roundRight; return entity; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java index e6bcf8e5be..4f80e194c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java @@ -66,6 +66,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.Utilities; @@ -680,6 +681,10 @@ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int hei } } + protected boolean square() { + return false; + } + private void updateCameraInfoSize(int i) { ArrayList cameraInfos = CameraController.getInstance().getCameras(); if (cameraInfos == null) { @@ -709,7 +714,11 @@ private void updateCameraInfoSize(int i) { int photoMaxWidth; int photoMaxHeight; - if (initialFrontface) { + if (square()) { + aspectRatio = new Size(1, 1); + photoMaxWidth = wantedWidth = 720; + photoMaxHeight = wantedHeight = 720; + } else if (initialFrontface) { aspectRatio = new Size(16, 9); photoMaxWidth = wantedWidth = 1280; photoMaxHeight = wantedHeight = 720; @@ -1965,6 +1974,10 @@ private void createCamera(final SurfaceTexture surfaceTexture, int i) { }); } + protected void receivedAmplitude(double amplitude) { + + } + private class VideoRecorder implements Runnable { @@ -2081,7 +2094,17 @@ public void run() { ByteBuffer byteBuffer = buffer.buffer[a]; byteBuffer.rewind(); readResult = audioRecorder.read(byteBuffer, 2048); - + if (readResult > 0 && a % 2 == 0) { + byteBuffer.limit(readResult); + double s = 0; + for (int i = 0; i < readResult / 2; i++) { + short p = byteBuffer.getShort(); + s += p * p; + } + double amplitude = Math.sqrt(s / readResult / 2); + AndroidUtilities.runOnUIThread(() -> receivedAmplitude(amplitude)); + byteBuffer.position(0); + } if (readResult <= 0) { buffer.results = a; if (!running) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java index 931f4281d7..63eb63d16e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java @@ -1,16 +1,12 @@ package org.telegram.messenger.video; import android.media.MediaCodec; -import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Build; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.FileLog; import org.telegram.messenger.MediaController; import org.telegram.messenger.video.audio_input.AudioInput; -import org.telegram.messenger.video.audio_input.GeneralAudioInput; import java.io.IOException; import java.nio.ByteBuffer; @@ -60,12 +56,12 @@ public AudioRecoder(ArrayList audioInputs, long totalDurationUs) thr } } - encoder = MediaCodec.createEncoderByType(MediaController.AUIDO_MIME_TYPE); - format = MediaFormat.createAudioFormat(MediaController.AUIDO_MIME_TYPE, + encoder = MediaCodec.createEncoderByType(MediaController.AUDIO_MIME_TYPE); + format = MediaFormat.createAudioFormat(MediaController.AUDIO_MIME_TYPE, sampleRate, channelCount ); - format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024); + format.setInteger(MediaFormat.KEY_BIT_RATE, DEFAULT_BIT_RATE); encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); encoder.start(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index f6e5495f2f..22d8ec1c27 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -307,8 +307,8 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, } if (!decoderDone) { - outputSurface.drawImage(); long presentationTime = (long) (framesCount / 30.0f * 1000L * 1000L * 1000L); + outputSurface.drawImage(presentationTime); inputSurface.setPresentationTime(presentationTime); inputSurface.swapBuffers(); framesCount++; @@ -532,7 +532,7 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, mediaMuxer = new MP4Builder().createMovie(movie, isSecret, outputMimeType.equals("video/hevc")); if (audioIndex >= 0) { MediaFormat audioFormat = extractor.getTrackFormat(audioIndex); - copyAudioBuffer = convertVideoParams.soundInfos.isEmpty() && audioFormat.getString(MediaFormat.KEY_MIME).equals(MediaController.AUIDO_MIME_TYPE) || audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/mpeg"); + copyAudioBuffer = convertVideoParams.soundInfos.isEmpty() && audioFormat.getString(MediaFormat.KEY_MIME).equals(MediaController.AUDIO_MIME_TYPE) || audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/mpeg"); if (audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/unknown")) { audioIndex = -1; @@ -830,7 +830,7 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, FileLog.e(e); } if (!errorWait) { - outputSurface.drawImage(); + outputSurface.drawImage(info.presentationTimeUs * 1000); inputSurface.setPresentationTime(info.presentationTimeUs * 1000); inputSurface.swapBuffers(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java index 6a9c203c31..140b797cfd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java @@ -148,8 +148,8 @@ public void awaitNewImage() { mSurfaceTexture.updateTexImage(); } - public void drawImage() { - mTextureRender.drawFrame(mSurfaceTexture); + public void drawImage(long time) { + mTextureRender.drawFrame(mSurfaceTexture, time); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 4989e14200..57f8bff827 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -62,6 +62,7 @@ import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.BlurringShader; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextEffects; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; @@ -206,6 +207,12 @@ public class TextureRenderer { private Canvas stickerCanvas; private float videoFps; + private Bitmap roundBitmap; + private Canvas roundCanvas; + private final android.graphics.Rect roundSrc = new android.graphics.Rect(); + private final RectF roundDst = new RectF(); + private Path roundClipPath; + private int imageOrientation; private boolean blendEnabled; @@ -473,7 +480,7 @@ private void drawGradient() { GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } - public void drawFrame(SurfaceTexture st) { + public void drawFrame(SurfaceTexture st, long time) { boolean blurred = false; if (isPhoto) { drawGradient(); @@ -609,13 +616,13 @@ public void drawFrame(SurfaceTexture st) { } if (stickerTexture != null) { for (int a = 0, N = mediaEntities.size(); a < N; a++) { - drawEntity(mediaEntities.get(a), mediaEntities.get(a).color); + drawEntity(mediaEntities.get(a), mediaEntities.get(a).color, time); } } GLES20.glFinish(); } - private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { + private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor, long time) { if (entity.ptr != 0) { if (entity.bitmap == null || entity.W <= 0 || entity.H <= 0) { return; @@ -631,26 +638,102 @@ private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); } else if (entity.animatedFileDrawable != null) { int lastFrame = (int) entity.currentFrame; - entity.currentFrame += entity.framesPerDraw; - int currentFrame = (int) entity.currentFrame; - while (lastFrame != currentFrame) { - entity.animatedFileDrawable.getNextFrame(); - currentFrame--; + float scale = 1f; + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + long vstart, vend; + if (isPhoto) { + vstart = 0; + vend = entity.roundDuration; + } else { + vstart = entity.roundOffset; + vend = entity.roundOffset + (long) (entity.roundRight - entity.roundLeft); + } + final long ms = time / 1_000_000L; + if (ms < vstart) { + scale = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(Utilities.clamp(1f - (vstart - ms) / 400f, 1, 0)); + } else if (ms > vend) { + scale = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(Utilities.clamp(1f - (ms - vend) / 400f, 1, 0)); + } + + if (scale > 0) { + long roundMs; + if (isPhoto) { + roundMs = Utilities.clamp(ms, entity.roundDuration, 0); + } else { + roundMs = Utilities.clamp(ms - entity.roundOffset + entity.roundLeft, entity.roundDuration, 0); + } + while (!entity.looped && entity.animatedFileDrawable.getProgressMs() < Math.min(roundMs, entity.animatedFileDrawable.getDurationMs())) { + int wasProgressMs = entity.animatedFileDrawable.getProgressMs(); + entity.animatedFileDrawable.getNextFrame(false); + if (entity.animatedFileDrawable.getProgressMs() <= wasProgressMs && !(entity.animatedFileDrawable.getProgressMs() == 0 && wasProgressMs == 0)) { + entity.looped = true; + break; + } + } + } + } else { + entity.currentFrame += entity.framesPerDraw; + int currentFrame = (int) entity.currentFrame; + while (lastFrame != currentFrame) { + entity.animatedFileDrawable.getNextFrame(true); + currentFrame--; + } } Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); if (frameBitmap != null) { - if (stickerCanvas == null && stickerBitmap != null) { - stickerCanvas = new Canvas(stickerBitmap); - if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { - stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + Bitmap endBitmap; + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + if (roundBitmap == null) { + final int side = Math.min(frameBitmap.getWidth(), frameBitmap.getHeight()); + roundBitmap = Bitmap.createBitmap(side, side, Bitmap.Config.ARGB_8888); + roundCanvas = new Canvas(roundBitmap); + } + if (roundBitmap != null) { + roundBitmap.eraseColor(Color.TRANSPARENT); + roundCanvas.save(); + if (roundClipPath == null) { + roundClipPath = new Path(); + } + roundClipPath.rewind(); + roundClipPath.addCircle(roundBitmap.getWidth() / 2f, roundBitmap.getHeight() / 2f, roundBitmap.getWidth() / 2f * scale, Path.Direction.CW); + roundCanvas.clipPath(roundClipPath); + if (frameBitmap.getWidth() >= frameBitmap.getHeight()) { + roundSrc.set( + (frameBitmap.getWidth() - frameBitmap.getHeight()) / 2, + 0, + frameBitmap.getWidth() - (frameBitmap.getWidth() - frameBitmap.getHeight()) / 2, + frameBitmap.getHeight() + ); + } else { + roundSrc.set( + 0, + (frameBitmap.getHeight() - frameBitmap.getWidth()) / 2, + frameBitmap.getWidth(), + frameBitmap.getHeight() - (frameBitmap.getHeight() - frameBitmap.getWidth()) / 2 + ); + } + roundDst.set(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight()); + roundCanvas.drawBitmap(frameBitmap, roundSrc, roundDst, null); + roundCanvas.restore(); } + endBitmap = roundBitmap; + } else { + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { + stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + } + } + if (stickerBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + applyRoundRadius(entity, stickerBitmap, (entity.subType & 8) != 0 ? textColor : 0); + } + endBitmap = stickerBitmap; } - if (stickerBitmap != null) { - stickerBitmap.eraseColor(Color.TRANSPARENT); - stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); - applyRoundRadius(entity, stickerBitmap, (entity.subType & 8) != 0 ? textColor : 0); + if (endBitmap != null) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, endBitmap, 0); drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); } } @@ -670,7 +753,7 @@ private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { if (entity1 == null) { continue; } - drawEntity(entity1, entity.color); + drawEntity(entity1, entity.color, time); } } } @@ -1040,7 +1123,11 @@ public void surfaceCreated() { GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); for (int a = 0, N = mediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(a); - if (entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER || entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO) { + if ( + entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER || + entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO || + entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND + ) { initStickerEntity(entity); } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT) { EditTextOutline editText = new EditTextOutline(ApplicationLoader.applicationContext); @@ -1239,10 +1326,14 @@ private void initStickerEntity(VideoEditedInfo.MediaEntity entity) { entity.ptr = RLottieDrawable.create(entity.text, null, entity.W, entity.H, entity.metadata, false, null, false, 0); entity.framesPerDraw = entity.metadata[1] / videoFps; } else if ((entity.subType & 4) != 0) { + entity.looped = false; entity.animatedFileDrawable = new AnimatedFileDrawable(new File(entity.text), true, 0, 0, null, null, null, 0, UserConfig.selectedAccount, true, 512, 512, null); entity.framesPerDraw = entity.animatedFileDrawable.getFps() / videoFps; - entity.currentFrame = 0; - entity.animatedFileDrawable.getNextFrame(); + entity.currentFrame = 1; + entity.animatedFileDrawable.getNextFrame(true); + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + entity.firstSeek = true; + } } else { if (Build.VERSION.SDK_INT >= 19) { BitmapFactory.Options opts = new BitmapFactory.Options(); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index c9cc6405f0..3e9518a2e8 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -11,6 +11,7 @@ import android.graphics.Bitmap; import android.graphics.Path; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.text.TextUtils; @@ -80,7 +81,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 166; + public static final int LAYER = 167; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -5508,30 +5509,65 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_messageInteractionCounters extends TLObject { - public static final int constructor = 0xad4fc9bd; + public static abstract class PostInteractionCounters extends TLObject { - public int msg_id; + public static PostInteractionCounters TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PostInteractionCounters result = null; + switch (constructor) { + case TL_postInteractionCountersStory.constructor: + result = new TL_postInteractionCountersStory(); + break; + case TL_postInteractionCountersMessage.constructor: + result = new TL_postInteractionCountersMessage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PostInteractionCounters", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_postInteractionCountersStory extends PostInteractionCounters { + public final static int constructor = 0x8a480e27; + + public int story_id; public int views; public int forwards; + public int reactions; - public static TL_messageInteractionCounters TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_messageInteractionCounters.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_messageInteractionCounters", constructor)); - } else { - return null; - } - } - TL_messageInteractionCounters result = new TL_messageInteractionCounters(); - result.readParams(stream, exception); - return result; + public void readParams(AbstractSerializedData stream, boolean exception) { + story_id = stream.readInt32(exception); + views = stream.readInt32(exception); + forwards = stream.readInt32(exception); + reactions = stream.readInt32(exception); } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(story_id); + stream.writeInt32(views); + stream.writeInt32(forwards); + stream.writeInt32(reactions); + } + } + + public static class TL_postInteractionCountersMessage extends PostInteractionCounters { + public static final int constructor = 0xe7058e7f; + + public int msg_id; + public int views; + public int forwards; + public int reactions; + public void readParams(AbstractSerializedData stream, boolean exception) { msg_id = stream.readInt32(exception); views = stream.readInt32(exception); forwards = stream.readInt32(exception); + reactions = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -5539,6 +5575,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(msg_id); stream.writeInt32(views); stream.writeInt32(forwards); + stream.writeInt32(reactions); } } @@ -13067,6 +13104,7 @@ public static abstract class ChatFull extends TLObject { public boolean participants_hidden; public boolean translations_disabled; public boolean stories_pinned_available; + public boolean view_forum_as_messages; public ChatReactions available_reactions; public TL_stories.PeerStories stories; @@ -15548,6 +15586,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { participants_hidden = (flags2 & 4) != 0; translations_disabled = (flags2 & 8) != 0; stories_pinned_available = (flags2 & 32) != 0; + view_forum_as_messages = (flags2 & 64) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -15690,6 +15729,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); + flags2 = view_forum_as_messages ? (flags2 | 64) : (flags2 &~ 64); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -19095,9 +19135,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stats_messageStats extends TLObject { - public static final int constructor = 0x8999f295; + public final static int constructor = 0x7fe91c14; public StatsGraph views_graph; + public StatsGraph reactions_by_emotion_graph; public static TL_stats_messageStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_stats_messageStats.constructor != constructor) { @@ -19114,11 +19155,13 @@ public static TL_stats_messageStats TLdeserialize(AbstractSerializedData stream, public void readParams(AbstractSerializedData stream, boolean exception) { views_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); views_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); } } @@ -23784,8 +23827,8 @@ public static abstract class User extends TLObject { public EmojiStatus emoji_status; public ArrayList usernames = new ArrayList<>(); public int stories_max_id; - public int color; - public long background_emoji_id; + public TL_peerColor color; + public TL_peerColor profile_color; public boolean verifiedExtended() { return verified || (ArrayUtil.contains(NekoXConfig.developers, id) && NekoXConfig.isDeveloper()); @@ -23797,8 +23840,8 @@ public static User TLdeserialize(AbstractSerializedData stream, int constructor, case TL_user.constructor: result = new TL_user(); break; - case TL_user_layer165_2.constructor: - result = new TL_user_layer165_2(); + case TL_user_layer166.constructor: + result = new TL_user_layer166(); break; case 0xcab35e18: result = new TL_userContact_old2(); @@ -23943,7 +23986,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_user extends User { - public static final int constructor = 0xeb602f25; + public static final int constructor = 0x215c4438; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -24045,11 +24088,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - if ((flags2 & 128) != 0) { - color = stream.readInt32(exception); + if ((flags2 & 256) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } - if ((flags2 & 64) != 0) { - background_emoji_id = stream.readInt64(exception); + if ((flags2 & 512) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -24135,17 +24178,17 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 32) != 0) { stream.writeInt32(stories_max_id); } - if ((flags2 & 128) != 0) { - stream.writeInt32(color); + if ((flags2 & 256) != 0) { + color.serializeToStream(stream); } - if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); + if ((flags2 & 512) != 0) { + profile_color.serializeToStream(stream); } } } - public static class TL_user_layer165_2 extends User { - public static final int constructor = 0x6fdee0df; + public static class TL_user_layer166 extends TL_user { + public static final int constructor = 0xeb602f25; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -24247,9 +24290,15 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - color = stream.readInt32(exception); + if ((flags2 & 128) != 0) { + color = new TL_peerColor(); + color.color = stream.readInt32(exception); + } if ((flags2 & 64) != 0) { - background_emoji_id = stream.readInt64(exception); + if (color == null) { + color = new TL_peerColor(); + } + color.background_emoji_id = stream.readInt64(exception); } } @@ -24335,9 +24384,11 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 32) != 0) { stream.writeInt32(stories_max_id); } - stream.writeInt32(color); + if ((flags2 & 128) != 0) { + stream.writeInt32(color.color); + } if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); + stream.writeInt64(color.background_emoji_id); } } } @@ -24445,7 +24496,6 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - color = (int) (id % 7); } public void serializeToStream(AbstractSerializedData stream) { @@ -26243,6 +26293,9 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con case 0x332ba9ed: result = new TL_messageActionGiveawayLaunch(); break; + case 0x2a9fadc5: + result = new TL_messageActionGiveawayResults(); + break; case 0xea3948e9: result = new TL_messageActionChannelMigrateFrom(); break; @@ -26283,6 +26336,9 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con result = new TL_messageActionCreatedBroadcastList(); break; case 0xbc44a927: + result = new TL_messageActionSetChatWallPaper_layer166(); + break; + case 0x5060a3f4: result = new TL_messageActionSetChatWallPaper(); break; case 0x55555550: @@ -26991,7 +27047,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_messageActionSetChatWallPaper extends MessageAction { + public static class TL_messageActionSetChatWallPaper_layer166 extends TL_messageActionSetChatWallPaper { public static final int constructor = 0xbc44a927; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -27004,6 +27060,28 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_messageActionSetChatWallPaper extends MessageAction { + public static final int constructor = 0x5060a3f4; + + public boolean same; + public boolean for_both; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + same = (flags & 1) != 0; + for_both = (flags & 2) != 0; + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = same ? (flags | 1) : (flags &~ 1); + flags = for_both ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + wallpaper.serializeToStream(stream); + } + } + public static class TL_messageActionUserJoined extends MessageAction { public static final int constructor = 0x55555550; @@ -29131,6 +29209,7 @@ public static abstract class MessageReplyHeader extends TLObject { public MessageMedia reply_media; public String quote_text; public ArrayList quote_entities = new ArrayList<>(); + public int quote_offset; public long user_id; public int story_id; @@ -29144,6 +29223,9 @@ public static MessageReplyHeader TLdeserialize(AbstractSerializedData stream, in case TL_messageReplyHeader.constructor: result = new TL_messageReplyHeader(); break; + case TL_messageReplyHeader_layer166.constructor: + result = new TL_messageReplyHeader_layer166(); + break; case TL_messageReplyHeader_layer165_2.constructor: result = new TL_messageReplyHeader_layer165_2(); break; @@ -29177,6 +29259,92 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messageReplyHeader extends MessageReplyHeader { + public static final int constructor = 0xafbc09db; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + reply_to_scheduled = (flags & 4) != 0; + forum_topic = (flags & 8) != 0; + quote = (flags & 512) != 0; + if ((flags & 16) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + if ((flags & 1) != 0) { + reply_to_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + reply_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 256) != 0) { + reply_media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + reply_to_top_id = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + quote_text = stream.readString(exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + quote_entities.add(object); + } + } + if ((flags & 1024) != 0) { + quote_offset = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = reply_to_scheduled ? (flags | 4) : (flags &~ 4); + flags = forum_topic ? (flags | 8) : (flags &~ 8); + flags = quote ? (flags | 512) : (flags &~ 512); + stream.writeInt32(flags); + if ((flags & 16) != 0) { + stream.writeInt32(reply_to_msg_id); + } + if ((flags & 1) != 0) { + reply_to_peer_id.serializeToStream(stream); + } + if ((flags & 32) != 0) { + reply_from.serializeToStream(stream); + } + if ((flags & 256) != 0) { + reply_media.serializeToStream(stream); + } + if ((flags & 2) != 0) { + stream.writeInt32(reply_to_top_id); + } + if ((flags & 64) != 0) { + stream.writeString(quote_text); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = quote_entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; ++a) { + quote_entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(quote_offset); + } + } + } + + public static class TL_messageReplyHeader_layer166 extends TL_messageReplyHeader { public static final int constructor = 0x6eebcabd; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -29661,12 +29829,16 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stats_broadcastStats extends TLObject { - public static final int constructor = 0xbdf78394; + public static int constructor = 0x396ca5fc; public TL_statsDateRangeDays period; public TL_statsAbsValueAndPrev followers; public TL_statsAbsValueAndPrev views_per_post; public TL_statsAbsValueAndPrev shares_per_post; + public TL_statsAbsValueAndPrev reactions_per_post; + public TL_statsAbsValueAndPrev views_per_story; + public TL_statsAbsValueAndPrev shares_per_story; + public TL_statsAbsValueAndPrev reactions_per_story; public TL_statsPercentValue enabled_notifications; public StatsGraph growth_graph; public StatsGraph followers_graph; @@ -29677,7 +29849,10 @@ public static class TL_stats_broadcastStats extends TLObject { public StatsGraph views_by_source_graph; public StatsGraph new_followers_by_source_graph; public StatsGraph languages_graph; - public ArrayList recent_message_interactions = new ArrayList<>(); + public StatsGraph reactions_by_emotion_graph; + public StatsGraph story_interactions_graph; + public StatsGraph story_reactions_by_emotion_graph; + public ArrayList recent_posts_interactions = new ArrayList<>(); public static TL_stats_broadcastStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_stats_broadcastStats.constructor != constructor) { @@ -29697,6 +29872,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { followers = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); views_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); shares_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + views_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + shares_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); enabled_notifications = TL_statsPercentValue.TLdeserialize(stream, stream.readInt32(exception), exception); growth_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); followers_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -29707,6 +29886,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { views_by_source_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); new_followers_by_source_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); languages_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + story_interactions_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + story_reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -29716,11 +29898,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - TL_messageInteractionCounters object = TL_messageInteractionCounters.TLdeserialize(stream, stream.readInt32(exception), exception); + PostInteractionCounters object = PostInteractionCounters.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } - recent_message_interactions.add(object); + recent_posts_interactions.add(object); } } @@ -29730,6 +29912,10 @@ public void serializeToStream(AbstractSerializedData stream) { followers.serializeToStream(stream); views_per_post.serializeToStream(stream); shares_per_post.serializeToStream(stream); + reactions_per_post.serializeToStream(stream); + views_per_story.serializeToStream(stream); + shares_per_story.serializeToStream(stream); + reactions_per_story.serializeToStream(stream); enabled_notifications.serializeToStream(stream); growth_graph.serializeToStream(stream); followers_graph.serializeToStream(stream); @@ -29740,11 +29926,14 @@ public void serializeToStream(AbstractSerializedData stream) { views_by_source_graph.serializeToStream(stream); new_followers_by_source_graph.serializeToStream(stream); languages_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); + story_interactions_graph.serializeToStream(stream); + story_reactions_by_emotion_graph.serializeToStream(stream); stream.writeInt32(0x1cb5c415); - int count = recent_message_interactions.size(); + int count = recent_posts_interactions.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { - recent_message_interactions.get(a).serializeToStream(stream); + recent_posts_interactions.get(a).serializeToStream(stream); } } } @@ -33578,324 +33767,330 @@ public static abstract class Update extends TLObject { public static Update TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Update result = null; switch (constructor) { - case 0x24f40e77: + case TL_updateMessagePollVote.constructor: result = new TL_updateMessagePollVote(); break; - case 0x5a73a98c: + case TL_updateMessageExtendedMedia.constructor: result = new TL_updateMessageExtendedMedia(); break; - case 0xaca1657b: + case TL_updateMessagePoll.constructor: result = new TL_updateMessagePoll(); break; - case 0xbb9bb9a5: + case TL_updatePeerHistoryTTL.constructor: result = new TL_updatePeerHistoryTTL(); break; - case 0xf89a6a4e: + case TL_updateChat.constructor: result = new TL_updateChat(); break; - case 0xa20db0e5: + case TL_updateDeleteMessages.constructor: result = new TL_updateDeleteMessages(); break; - case 0x5bb98608: + case TL_updatePinnedChannelMessages.constructor: result = new TL_updatePinnedChannelMessages(); break; - case 0xf2ebdb4e: + case TL_updateGroupCallParticipants.constructor: result = new TL_updateGroupCallParticipants(); break; - case 0x571d2742: + case TL_updateReadFeaturedStickers.constructor: result = new TL_updateReadFeaturedStickers(); break; - case 0x1710f156: + case TL_updateEncryptedChatTyping.constructor: result = new TL_updateEncryptedChatTyping(); break; - case 0xd6b19546: + case TL_updateReadChannelDiscussionInbox.constructor: result = new TL_updateReadChannelDiscussionInbox(); break; - case 0x2f2f21bf: + case TL_updateReadHistoryOutbox.constructor: result = new TL_updateReadHistoryOutbox(); break; - case 0x62ba04d9: + case TL_updateNewChannelMessage.constructor: result = new TL_updateNewChannelMessage(); break; - case 0x1592b79d: + case TL_updateWebViewResultSent.constructor: result = new TL_updateWebViewResultSent(); break; - case 0x6e6fe51c: + case TL_updateDialogPinned.constructor: result = new TL_updateDialogPinned(); break; - case 0x6a7e7366: + case TL_updatePeerSettings.constructor: result = new TL_updatePeerSettings(); break; - case 0x5492a13: + case TL_updateUserPhone.constructor: result = new TL_updateUserPhone(); break; - case 0x4e90bfd6: + case TL_updateMessageID.constructor: result = new TL_updateMessageID(); break; - case 0xb75f99a9: + case TL_updateReadChannelOutbox.constructor: result = new TL_updateReadChannelOutbox(); break; - case 0x8c88c923: + case TL_updateChannelUserTyping.constructor: result = new TL_updateChannelUserTyping(); break; - case 0x1bf335b9: + case TL_updateStoryID.constructor: result = new TL_updateStoryID(); break; - case 0x31c24808: + case TL_updateStickerSets.constructor: result = new TL_updateStickerSets(); break; - case 0x19360dc0: + case TL_updateFolderPeers.constructor: result = new TL_updateFolderPeers(); break; - case 0x1f2b0afd: + case TL_updateNewMessage.constructor: result = new TL_updateNewMessage(); break; - case 0x39a51dfb: + case TL_updateNewScheduledMessage.constructor: result = new TL_updateNewScheduledMessage(); break; - case 0x12bcbd9a: + case TL_updateNewEncryptedMessage.constructor: result = new TL_updateNewEncryptedMessage(); break; - case 0x86fccf85: + case TL_updateMoveStickerSetToTop.constructor: result = new TL_updateMoveStickerSetToTop(); break; - case 0xe5bdf8de: + case TL_updateUserStatus.constructor: result = new TL_updateUserStatus(); break; - case 0x28373599: + case TL_updateUserEmojiStatus.constructor: result = new TL_updateUserEmojiStatus(); break; - case 0xf226ac08: + case TL_updateChannelMessageViews.constructor: result = new TL_updateChannelMessageViews(); break; - case 0xb783982: + case TL_updateGroupCallConnection.constructor: result = new TL_updateGroupCallConnection(); break; - case 0x4d712f2e: + case TL_updateBotCommands.constructor: result = new TL_updateBotCommands(); break; - case 0x871fb939: + case TL_updateGeoLiveViewed.constructor: result = new TL_updateGeoLiveViewed(); break; - case 0xbec268ef: + case TL_updateNotifySettings.constructor: result = new TL_updateNotifySettings(); break; - case 0x985d3abb: + case TL_updateChannelParticipant.constructor: result = new TL_updateChannelParticipant(); break; - case 0x695c9e7c: + case TL_updateReadChannelDiscussionOutbox.constructor: result = new TL_updateReadChannelDiscussionOutbox(); break; - case 0xe32f3d77: + case TL_updateChatParticipantDelete.constructor: result = new TL_updateChatParticipantDelete(); break; - case 0xfb4c496c: + case TL_updateReadFeaturedEmojiStickers.constructor: result = new TL_updateReadFeaturedEmojiStickers(); break; - case 0xe40370a3: + case TL_updateEditMessage.constructor: result = new TL_updateEditMessage(); break; - case 0x6f7863f4: + case TL_updateRecentReactions.constructor: result = new TL_updateRecentReactions(); break; - case 0x7f891213: + case TL_updateWebPage.constructor: result = new TL_updateWebPage(); break; - case 0xe511996d: + case TL_updateFavedStickers.constructor: result = new TL_updateFavedStickers(); break; - case 0x3dda5451: + case TL_updateChatParticipantAdd.constructor: result = new TL_updateChatParticipantAdd(); break; - case 0x83487af0: + case TL_updateChatUserTyping.constructor: result = new TL_updateChatUserTyping(); break; - case 0x564fe691: + case TL_updateLoginToken.constructor: result = new TL_updateLoginToken(); break; - case 0xb4a2e88d: + case TL_updateEncryption.constructor: result = new TL_updateEncryption(); break; - case 0x14b24500: + case TL_updateGroupCall.constructor: result = new TL_updateGroupCall(); break; - case 0x108d941f: + case TL_updateChannelTooLong.constructor: result = new TL_updateChannelTooLong(); break; - case 0xc01e857f: + case TL_updateUserTyping.constructor: result = new TL_updateUserTyping(); break; - case 0xf74e932b: + case TL_stories.TL_updateReadStories.constructor: result = new TL_stories.TL_updateReadStories(); break; - case 0xebe46819: + case TL_updateServiceNotification.constructor: result = new TL_updateServiceNotification(); break; - case 0x56022f4d: + case TL_updateLangPack.constructor: result = new TL_updateLangPack(); break; - case 0xb23fc698: + case TL_updateChannelAvailableMessages.constructor: result = new TL_updateChannelAvailableMessages(); break; - case 0xd7ca61a2: + case TL_updateChatParticipantAdmin.constructor: result = new TL_updateChatParticipantAdmin(); break; - case 0xea29055d: + case TL_updateChannelReadMessagesContents.constructor: result = new TL_updateChannelReadMessagesContents(); break; - case 0xee3b272a: + case TL_updatePrivacy.constructor: result = new TL_updatePrivacy(); break; - case 0xa229dd06: + case TL_updateConfig.constructor: result = new TL_updateConfig(); break; - case 0xe16459c3: + case TL_updateDialogUnreadMark.constructor: result = new TL_updateDialogUnreadMark(); break; - case 0x1b49ec6d: + case TL_updateDraftMessage.constructor: result = new TL_updateDraftMessage(); break; - case 0x8951abef: + case TL_updateNewAuthorization.constructor: result = new TL_updateNewAuthorization(); break; - case 0xa7848924: + case TL_updateUserName.constructor: result = new TL_updateUserName(); break; - case 0x5e1b3cb8: + case TL_updateMessageReactions.constructor: result = new TL_updateMessageReactions(); break; - case 0xab0f6b1e: + case TL_updatePhoneCall.constructor: result = new TL_updatePhoneCall(); break; - case 0x26ffde7d: + case TL_updateDialogFilter.constructor: result = new TL_updateDialogFilter(); break; - case 0xebe07752: + case TL_updatePeerBlocked.constructor: result = new TL_updatePeerBlocked(); break; - case 0xed85eab5: + case TL_updatePinnedMessages.constructor: result = new TL_updatePinnedMessages(); break; - case 0x2661bf09: + case TL_updatePhoneCallSignalingData.constructor: result = new TL_updatePhoneCallSignalingData(); break; - case 0x88617090: + case TL_updateTranscribeAudio.constructor: result = new TL_updateTranscribeAudio(); break; - case 0xfa0f3ca2: + case TL_updatePinnedDialogs.constructor: result = new TL_updatePinnedDialogs(); break; - case 0x74d8be99: + case TL_updateSavedRingtones.constructor: result = new TL_updateSavedRingtones(); break; - case 0x2c084dc1: + case TL_stories.TL_updateStoriesStealthMode.constructor: result = new TL_stories.TL_updateStoriesStealthMode(); break; - case 0x84cd5a: + case TL_updateTranscribedAudio.constructor: result = new TL_updateTranscribedAudio(); break; - case 0xb4afcfb0: + case TL_updatePeerLocated.constructor: result = new TL_updatePeerLocated(); break; - case 0x9a422c20: + case TL_updateRecentStickers.constructor: result = new TL_updateRecentStickers(); break; - case 0x9c974fdf: + case TL_updateReadHistoryInbox.constructor: result = new TL_updateReadHistoryInbox(); break; - case 0xa5d72105: + case TL_updateDialogFilterOrder.constructor: result = new TL_updateDialogFilterOrder(); break; - case 0x9375341e: + case TL_updateSavedGifs.constructor: result = new TL_updateSavedGifs(); break; - case 0x7084a7be: + case TL_updateContactsReset.constructor: result = new TL_updateContactsReset(); break; - case 0x635b4c09: + case TL_updateChannel.constructor: result = new TL_updateChannel(); break; - case 0x2f2ba99f: + case TL_updateChannelWebPage.constructor: result = new TL_updateChannelWebPage(); break; - case 0x90866cee: + case TL_updateDeleteScheduledMessages.constructor: result = new TL_updateDeleteScheduledMessages(); break; - case 0xd29a27f4: + case TL_updateChannelMessageForwards.constructor: result = new TL_updateChannelMessageForwards(); break; - case 0xc32d5b12: + case TL_updateDeleteChannelMessages.constructor: result = new TL_updateDeleteChannelMessages(); break; - case 0x7d627683: + case TL_updateSentStoryReaction.constructor: result = new TL_updateSentStoryReaction(); break; - case 0xf227868c: + case TL_updateUserPhoto.constructor: result = new TL_updateUserPhoto(); break; - case 0x20529438: + case TL_updateUser.constructor: result = new TL_updateUser(); break; - case 0xccf08ad6: + case TL_updateGroupInvitePrivacyForbidden.constructor: result = new TL_updateGroupInvitePrivacyForbidden(); break; - case 0x17b7a20b: + case TL_updateAttachMenuBots.constructor: result = new TL_updateAttachMenuBots(); break; - case 0x3504914f: + case TL_updateDialogFilters.constructor: result = new TL_updateDialogFilters(); break; - case 0x30f443db: + case TL_updateRecentEmojiStatuses.constructor: result = new TL_updateRecentEmojiStatuses(); break; - case 0x75b3b798: + case TL_stories.TL_updateStory.constructor: result = new TL_stories.TL_updateStory(); break; - case 0x7063c3db: + case TL_updatePendingJoinRequests.constructor: result = new TL_updatePendingJoinRequests(); break; - case 0x8e5e9873: + case TL_updateDcOptions.constructor: result = new TL_updateDcOptions(); break; - case 0x1b3f4df7: + case TL_updateEditChannelMessage.constructor: result = new TL_updateEditChannelMessage(); break; - case 0x688a30aa: + case TL_updateNewStickerSet.constructor: result = new TL_updateNewStickerSet(); break; - case 0x8216fba3: + case TL_updateTheme.constructor: result = new TL_updateTheme(); break; - case 0x46560264: + case TL_updateLangPackTooLong.constructor: result = new TL_updateLangPackTooLong(); break; - case 0x38fe25b7: + case TL_updateEncryptedMessagesRead.constructor: result = new TL_updateEncryptedMessagesRead(); break; - case 0xbb2d201: + case TL_updateStickerSetsOrder.constructor: result = new TL_updateStickerSetsOrder(); break; - case 0x922e6e10: + case TL_updateReadChannelInbox.constructor: result = new TL_updateReadChannelInbox(); break; - case 0xf8227181: + case TL_updateReadMessagesContents.constructor: result = new TL_updateReadMessagesContents(); break; - case 0x7761198: + case TL_updateChatParticipants.constructor: result = new TL_updateChatParticipants(); break; - case 0x54c01850: + case TL_updateChatDefaultBannedRights.constructor: result = new TL_updateChatDefaultBannedRights(); break; - case 0x14b85813: + case TL_updateBotMenuButton.constructor: result = new TL_updateBotMenuButton(); break; - case 0xfe198602: + case TL_updateChannelPinnedTopics.constructor: result = new TL_updateChannelPinnedTopics(); break; - case 0x192efbe3: + case TL_updateChannelPinnedTopic.constructor: result = new TL_updateChannelPinnedTopic(); break; + case TL_updateChannelViewForumAsMessages.constructor: + result = new TL_updateChannelViewForumAsMessages(); + break; + case TL_updatePeerWallpaper.constructor: + result = new TL_updatePeerWallpaper(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); @@ -40742,7 +40937,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_sponsoredMessage extends TLObject { - public static final int constructor = 0xdaafff6b; + public static final int constructor = 0xed5383f7; public int flags; public boolean recommended; @@ -40753,9 +40948,11 @@ public static class TL_sponsoredMessage extends TLObject { public String chat_invite_hash; public int channel_post; public String start_param; + public BotApp app; public TL_sponsoredWebPage webpage; public String message; public ArrayList entities = new ArrayList<>(); + public String button_text; public String sponsor_info; public String additional_info; @@ -40795,6 +40992,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 512) != 0) { webpage = TL_sponsoredWebPage.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 1024) != 0) { + app = BotApp.TLdeserialize(stream, stream.readInt32(exception), exception); + } message = stream.readString(exception); if ((flags & 2) != 0) { int magic = stream.readInt32(exception); @@ -40813,6 +41013,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { entities.add(object); } } + if ((flags & 2048) != 0) { + button_text = stream.readString(exception); + } if ((flags & 128) != 0) { sponsor_info = stream.readString(exception); } @@ -40845,6 +41048,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 512) != 0) { webpage.serializeToStream(stream); } + if ((flags & 1024) != 0) { + app.serializeToStream(stream); + } stream.writeString(message); if ((flags & 2) != 0) { stream.writeInt32(0x1cb5c415); @@ -40854,6 +41060,9 @@ public void serializeToStream(AbstractSerializedData stream) { entities.get(a).serializeToStream(stream); } } + if ((flags & 2048) != 0) { + stream.writeString(button_text); + } if ((flags & 128) != 0) { stream.writeString(sponsor_info); } @@ -45530,8 +45739,7 @@ public static abstract class Chat extends TLObject { public boolean stories_hidden_min; public boolean stories_unavailable; public int stories_max_id; - public int color; - public long background_emoji_id; + public TL_peerColor color; public ArrayList usernames = new ArrayList<>(); @@ -45561,8 +45769,8 @@ public static Chat TLdeserialize(AbstractSerializedData stream, int constructor, case TL_channel.constructor: result = new TL_channel(); break; - case TL_channel_layer165_2.constructor: - result = new TL_channel_layer165_2(); + case TL_channel_layer166.constructor: + result = new TL_channel_layer166(); break; case TL_channel_layer165.constructor: result = new TL_channel_layer165(); @@ -46005,7 +46213,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_channel extends Chat { - public static final int constructor = 0x1981ea7e; + public static final int constructor = 0x8e87ccd8; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -46092,11 +46300,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } - if ((flags2 & 64) != 0) { - color = stream.readInt32(exception); - } - if ((flags2 & 32) != 0) { - background_emoji_id = stream.readInt64(exception); + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -46168,17 +46373,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 16) != 0) { stream.writeInt32(stories_max_id); } - if ((flags2 & 64) != 0) { - stream.writeInt32(color); - } - if ((flags2 & 32) != 0) { - stream.writeInt64(background_emoji_id); + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); } } } - public static class TL_channel_layer165 extends TL_channel { - public static final int constructor = 0x2458af8c; + public static class TL_channel_layer166 extends TL_channel { + public static final int constructor = 0x1981ea7e; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -46265,9 +46467,15 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } - color = stream.readInt32(exception); + if ((flags2 & 64) != 0) { + color = new TL_peerColor(); + color.color = stream.readInt32(exception); + } if ((flags2 & 32) != 0) { - background_emoji_id = stream.readInt64(exception); + if (color == null) { + color = new TL_peerColor(); + } + color.background_emoji_id = stream.readInt64(exception); } } @@ -46339,14 +46547,16 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 16) != 0) { stream.writeInt32(stories_max_id); } - stream.writeInt32(color); + if ((flags2 & 64) != 0) { + stream.writeInt32(color.color); + } if ((flags2 & 32) != 0) { - stream.writeInt64(background_emoji_id); + stream.writeInt64(color.background_emoji_id); } } } - public static class TL_channel_layer165_2 extends TL_channel { + public static class TL_channel_layer165 extends TL_channel { public static final int constructor = 0x94f592db; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -46434,6 +46644,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } + color = new TL_peerColor(); + color.color = stream.readInt32(exception); + if ((flags2 & 32) != 0) { + color.background_emoji_id = stream.readInt64(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -46504,6 +46719,10 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 16) != 0) { stream.writeInt32(stories_max_id); } + stream.writeInt32(color == null ? (int) (id % 7) : color.color); + if ((flags2 & 32) != 0) { + stream.writeInt64(color == null ? 0 : color.background_emoji_id); + } } } @@ -50132,6 +50351,7 @@ public static abstract class UserFull extends TLObject { public boolean translations_disabled; public boolean stories_pinned_available; public boolean blocked_my_stories_from; + public boolean wallpaper_overridden; public User user; public String about; public TL_contacts_link_layer101 link; @@ -50222,6 +50442,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { translations_disabled = (flags & 8388608) != 0; stories_pinned_available = (flags & 67108864) != 0; blocked_my_stories_from = (flags & 134217728) != 0; + wallpaper_overridden = (flags & 268435456) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -50299,6 +50520,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); + flags = wallpaper_overridden ? (flags | 268435456) : (flags &~ 268435456); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -51859,6 +52081,7 @@ public static abstract class WallPaper extends TLObject { public WallPaperSettings settings; public String uploadingImage;//custom public Bitmap stripedThumb;//custom + public Drawable thumbDrawable;//custom public static WallPaper TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { WallPaper result = null; @@ -62675,6 +62898,168 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_stats_getStoryPublicForwards extends TLObject { + public static final int constructor = 0xa6437ef6; + + public InputPeer peer; + public int id; + public String offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stats_publicForwards.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(id); + stream.writeString(offset); + stream.writeInt32(limit); + } + } + + public static class TL_stats_publicForwards extends TLObject { + public static final int constructor = 0x93037e20; + + public int flags; + public int count; + public ArrayList forwards = new ArrayList<>(); + public String next_offset; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_stats_publicForwards TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stats_publicForwards.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stats_publicForwards", constructor)); + } else { + return null; + } + } + TL_stats_publicForwards result = new TL_stats_publicForwards(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PublicForward object = PublicForward.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + forwards.add(object); + } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = forwards.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + forwards.get(a).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static abstract class PublicForward extends TLObject { + + public static PublicForward TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PublicForward result = null; + switch (constructor) { + case TL_publicForwardMessage.constructor: + result = new TL_publicForwardMessage(); + break; + case TL_stories.TL_publicForwardStory.constructor: + result = new TL_stories.TL_publicForwardStory(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PublicForward", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_publicForwardMessage extends PublicForward { + public static final int constructor = 0x1f2bf4a; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + } + } + //manually created public static class TL_photoPathSize extends PhotoSize { @@ -66658,6 +67043,7 @@ public static abstract class Dialog extends TLObject { public int flags; public boolean pinned; public boolean unread_mark; + public boolean view_forum_as_messages; public Peer peer; public int top_message; public int read_inbox_max_id; @@ -66706,6 +67092,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); pinned = (flags & 4) != 0; unread_mark = (flags & 8) != 0; + view_forum_as_messages = (flags & 64) != 0; peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); top_message = stream.readInt32(exception); read_inbox_max_id = stream.readInt32(exception); @@ -66732,6 +67119,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = pinned ? (flags | 4) : (flags &~ 4); flags = unread_mark ? (flags | 8) : (flags &~ 8); + flags = view_forum_as_messages ? (flags | 64) : (flags &~ 64); stream.writeInt32(flags); peer.serializeToStream(stream); stream.writeInt32(top_message); @@ -69402,12 +69790,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_transcribedAudio extends TLObject { - public static final int constructor = 0x93752c52; + public static final int constructor = 0xcfb9d957; public int flags; public boolean pending; public long transcription_id; public String text; + public int trial_remains_num; + public int trial_remains_until_date; public static TL_messages_transcribedAudio TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_messages_transcribedAudio.constructor != constructor) { @@ -69427,6 +69817,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { pending = (flags & 1) != 0; transcription_id = stream.readInt64(exception); text = stream.readString(exception); + if ((flags & 2) != 0) { + trial_remains_num = stream.readInt32(exception); + trial_remains_until_date = stream.readInt32(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -69435,6 +69829,10 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(flags); stream.writeInt64(transcription_id); stream.writeString(text); + if ((flags & 2) != 0) { + stream.writeInt32(trial_remains_num); + stream.writeInt32(trial_remains_until_date); + } } } @@ -70759,9 +71157,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_account_updateColor extends TLObject { - public static final int constructor = 0xa001cc43; + public static final int constructor = 0x7cefa15d; public int flags; + public boolean for_profile; public int color; public long background_emoji_id; @@ -70771,8 +71170,11 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_profile ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); - stream.writeInt32(color); + if ((flags & 4) != 0) { + stream.writeInt32(color); + } if ((flags & 1) != 0) { stream.writeInt64(background_emoji_id); } @@ -70794,10 +71196,58 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_updateChannelViewForumAsMessages extends Update { + public static final int constructor = 0x7b68920; + + public long channel_id; + public boolean enabled; + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt64(exception); + enabled = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(channel_id); + stream.writeBool(enabled); + } + } + + public static class TL_updatePeerWallpaper extends Update { + public static final int constructor = 0xae3f101d; + + public int flags; + public boolean wallpaper_overridden; + public Peer peer; + public WallPaper wallpaper; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + wallpaper_overridden = (flags & 2) != 0; + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = wallpaper_overridden ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + wallpaper.serializeToStream(stream); + } + } + } + public static class TL_messages_setChatWallPaper extends TLObject { public static final int constructor = 0x8ffacae1; public int flags; + public boolean for_both; + public boolean revert; public InputPeer peer; public InputWallPaper wallpaper; public WallPaperSettings settings; @@ -70809,6 +71259,8 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_both ? (flags | 8) : (flags &~ 8); + flags = revert ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); peer.serializeToStream(stream); if ((flags & 1) != 0) { @@ -70876,6 +71328,7 @@ public static abstract class InputReplyTo extends TLObject { public InputPeer reply_to_peer_id; public String quote_text; public ArrayList quote_entities = new ArrayList<>(); + public int quote_offset; public InputUser user_id; public int story_id; @@ -70886,6 +71339,9 @@ public static InputReplyTo TLdeserialize(AbstractSerializedData stream, int cons case TL_inputReplyToMessage.constructor: result = new TL_inputReplyToMessage(); break; + case TL_inputReplyToMessage_layer166.constructor: + result = new TL_inputReplyToMessage_layer166(); + break; case TL_inputReplyToStory.constructor: result = new TL_inputReplyToStory(); break; @@ -70901,6 +71357,70 @@ public static InputReplyTo TLdeserialize(AbstractSerializedData stream, int cons } public static class TL_inputReplyToMessage extends InputReplyTo { + public static final int constructor = 0x22c0f6d5; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + reply_to_msg_id = stream.readInt32(exception); + if ((flags & 1) != 0) { + top_msg_id = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + reply_to_peer_id = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + quote_text = stream.readString(exception); + } + if ((flags & 8) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + quote_entities.add(object); + } + } + if ((flags & 16) != 0) { + quote_offset = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(reply_to_msg_id); + if ((flags & 1) != 0) { + stream.writeInt32(top_msg_id); + } + if ((flags & 2) != 0) { + reply_to_peer_id.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeString(quote_text); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = quote_entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; ++a) { + quote_entities.get(a).serializeToStream(stream); + } + } + if ((flags & 16) != 0) { + stream.writeInt32(quote_offset); + } + } + } + + public static class TL_inputReplyToMessage_layer166 extends TL_inputReplyToMessage { public static final int constructor = 0x73ec805; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -71789,7 +72309,377 @@ public void serializeToStream(AbstractSerializedData stream) { } } - //functions + public static class TL_messageActionGiveawayResults extends MessageAction { + public static int constructor = 0x2a9fadc5; + + public int winners_count; + public int unclaimed_count; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + winners_count = stream.readInt32(exception); + unclaimed_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(winners_count); + stream.writeInt32(unclaimed_count); + } + } + + public static class TL_channels_getChannelRecommendations extends TLObject { + public static int constructor = 0x83b70d97; + + public InputChannel channel; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Chats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_toggleViewForumAsMessages extends TLObject { + public static int constructor = 0x9738bb15; + + public InputChannel channel_id; + public boolean enabled; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel_id.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_peerColor extends TLObject { + public static final int constructor = 0xb54b5acf; + + public int flags; + public int color; + public long background_emoji_id; + + public static TL_peerColor TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_peerColor.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_peerColor", constructor)); + } else { + return null; + } + } + TL_peerColor result = new TL_peerColor(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + color = (flags & 1) != 0 ? stream.readInt32(exception) : -1; + if ((flags & 2) != 0) { + background_emoji_id = stream.readInt64(exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(color); + } + if ((flags & 2) != 0) { + stream.writeInt64(background_emoji_id); + } + } + } + + public static class help_PeerColorSet extends TLObject { + public static help_PeerColorSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_PeerColorSet result = null; + switch (constructor) { + case TL_help_peerColorSet.constructor: + result = new TL_help_peerColorSet(); + break; + case TL_help_peerColorProfileSet.constructor: + result = new TL_help_peerColorProfileSet(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_PeerColorSet", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_peerColorSet extends help_PeerColorSet { + public static final int constructor = 0x26219a58; + + public ArrayList colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + colors.add(stream.readInt32(exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(colors.get(i)); + } + } + } + + public static class TL_help_peerColorProfileSet extends help_PeerColorSet { + public static final int constructor = 0x767d61eb; + + public ArrayList palette_colors = new ArrayList<>(); + public ArrayList bg_colors = new ArrayList<>(); + public ArrayList story_colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + palette_colors.add(stream.readInt32(exception)); + } + + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + bg_colors.add(stream.readInt32(exception)); + } + + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + story_colors.add(stream.readInt32(exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = palette_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(palette_colors.get(i)); + } + stream.writeInt32(0x1cb5c415); + count = bg_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(bg_colors.get(i)); + } + stream.writeInt32(0x1cb5c415); + count = story_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(story_colors.get(i)); + } + } + } + + public static class TL_help_peerColorOption extends TLObject { + public static final int constructor = 0x135bd42f; + + public int flags; + public boolean hidden; + public int color_id; + public help_PeerColorSet colors; + public help_PeerColorSet dark_colors; + + public static TL_help_peerColorOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_help_peerColorOption.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_help_peerColorOption", constructor)); + } else { + return null; + } + } + TL_help_peerColorOption result = new TL_help_peerColorOption(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + hidden = (flags & 1) != 0; + color_id = stream.readInt32(exception); + if ((flags & 2) != 0) { + colors = help_PeerColorSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + dark_colors = help_PeerColorSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = hidden ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(color_id); + if ((flags & 2) != 0) { + colors.serializeToStream(stream); + } + if ((flags & 4) != 0) { + dark_colors.serializeToStream(stream); + } + } + } + + public static class help_PeerColors extends TLObject { + public static help_PeerColors TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_PeerColors result = null; + switch (constructor) { + case TL_help_peerColorsNotModified.constructor: + result = new TL_help_peerColorsNotModified(); + break; + case TL_help_peerColors.constructor: + result = new TL_help_peerColors(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_PeerColors", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_peerColorsNotModified extends help_PeerColors { + public static final int constructor = 0x2ba1f5ce; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_peerColors extends help_PeerColors { + public static final int constructor = 0xf8ed08; + + public int hash; + public ArrayList colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + colors.add(TL_help_peerColorOption.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + colors.get(i).serializeToStream(stream); + } + } + } + + public static class TL_help_getPeerColors extends TLObject { + public static final int constructor = 0xda80f42f; + + public int hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_PeerColors.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_help_getPeerProfileColors extends TLObject { + public static final int constructor = 0xabcfa9fd; + + public int hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_PeerColors.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } public static class Vector extends TLObject { public static final int constructor = 0x1cb5c415; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java index dbf55895c8..f2d7899d2b 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java @@ -462,11 +462,12 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_sendStory extends TLObject { - public static final int constructor = 0xbcb73644; + public static final int constructor = 0xe4e6694b; public int flags; public boolean pinned; public boolean noforwards; + public boolean fwd_modified; public TLRPC.InputPeer peer; public TLRPC.InputMedia media; public ArrayList media_areas = new ArrayList<>(); @@ -475,6 +476,8 @@ public static class TL_stories_sendStory extends TLObject { public ArrayList privacy_rules = new ArrayList<>(); public long random_id; public int period; + public TLRPC.InputPeer fwd_from_id; + public int fwd_from_story; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TLRPC.Updates.TLdeserialize(stream, constructor, exception); @@ -484,6 +487,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = pinned ? (flags | 4) : (flags &~ 4); flags = noforwards ? (flags | 16) : (flags &~ 16); + flags = fwd_modified ? (flags | 128) : (flags &~ 128); stream.writeInt32(flags); peer.serializeToStream(stream); media.serializeToStream(stream); @@ -516,6 +520,12 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8) != 0) { stream.writeInt32(period); } + if ((flags & 64) != 0) { + fwd_from_id.serializeToStream(stream); + } + if ((flags & 64) != 0) { + stream.writeInt32(fwd_from_story); + } } } @@ -1755,6 +1765,7 @@ public static abstract class StoryItem extends TLObject { public boolean out; public int id; public int date; + public StoryFwdHeader fwd_from; public int expire_date; public String caption; public boolean edited; @@ -1781,9 +1792,12 @@ public static abstract class StoryItem extends TLObject { public static StoryItem TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StoryItem result = null; switch (constructor) { - case 0x44c457ce: + case 0xaf6365a1: result = new TL_storyItem(); break; + case 0x44c457ce: + result = new TL_storyItem_layer166(); + break; case 0x562aa637: result = new TL_storyItem_layer160(); break; @@ -1959,7 +1973,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = has_viewers ? (flags | 2) : (flags &~ 2); + flags = has_viewers ? (flags | 2) : (flags & ~2); stream.writeInt32(flags); stream.writeInt32(views_count); if ((flags & 4) != 0) { @@ -1987,7 +2001,223 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_publicForwardStory extends TLRPC.PublicForward { + public static final int constructor = 0xedf3add0; + + public TLRPC.Peer peer; + public StoryItem story; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + story.serializeToStream(stream); + } + } + + public static class StoryFwdHeader extends TLObject { + + public int flags; + public boolean modified; + public TLRPC.Peer from; + public String from_name; + public int story_id; + + public static StoryFwdHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryFwdHeader result = null; + switch (constructor) { + case TL_storyFwdHeader.constructor: + result = new TL_storyFwdHeader(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryFwdHeader", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_storyFwdHeader extends StoryFwdHeader { + public static final int constructor = 0xb826e150; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + modified = (flags & 8) != 0; + if ((flags & 1) != 0) { + from = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + from_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + story_id = stream.readInt32(exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = modified ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + from.serializeToStream(stream); + } + if ((flags & 2) != 0) { + stream.writeString(from_name); + } + if ((flags & 4) != 0) { + stream.writeInt32(story_id); + } + } + } + public static class TL_storyItem extends StoryItem { + public static final int constructor = 0xaf6365a1; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 32) != 0; + isPublic = (flags & 128) != 0; + close_friends = (flags & 256) != 0; + min = (flags & 512) != 0; + noforwards = (flags & 1024) != 0; + edited = (flags & 2048) != 0; + contacts = (flags & 4096) != 0; + selected_contacts = (flags & 8192) != 0; + out = (flags & 65536) != 0; + id = stream.readInt32(exception); + date = stream.readInt32(exception); + if ((flags & 131072) != 0) { + fwd_from = TL_storyFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + expire_date = stream.readInt32(exception); + if ((flags & 1) != 0) { + caption = stream.readString(exception); + } + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.MessageEntity object = TLRPC.MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + media = TLRPC.MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 16384) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MediaArea object = MediaArea.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + media_areas.add(object); + } + } + if ((flags & 4) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.PrivacyRule object = TLRPC.PrivacyRule.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + privacy.add(object); + } + } + if ((flags & 8) != 0) { + views = StoryViews.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + sent_reaction = TLRPC.Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 32) : (flags &~ 32); + flags = isPublic ? (flags | 128) : (flags &~ 128); + flags = close_friends ? (flags | 256) : (flags &~ 256); + flags = min ? (flags | 512) : (flags &~ 512); + flags = noforwards ? (flags | 1024) : (flags &~ 1024); + flags = edited ? (flags | 2048) : (flags &~ 2048); + flags = contacts ? (flags | 4096) : (flags &~ 4096); + flags = selected_contacts ? (flags | 8192) : (flags &~ 8192); + flags = out ? (flags | 65536) : (flags &~ 65536); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(date); + if ((flags & 131072) != 0) { + fwd_from.serializeToStream(stream); + } + stream.writeInt32(expire_date); + if ((flags & 1) != 0) { + stream.writeString(caption); + } + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + media.serializeToStream(stream); + if ((flags & 16384) != 0) { + stream.writeInt32(0x1cb5c415); + int count = media_areas.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + media_areas.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + stream.writeInt32(0x1cb5c415); + int count = privacy.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + privacy.get(a).serializeToStream(stream); + } + } + if ((flags & 8) != 0) { + views.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + sent_reaction.serializeToStream(stream); + } + } + } + + public static class TL_storyItem_layer166 extends TL_storyItem { public static final int constructor = 0x44c457ce; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -2459,4 +2689,56 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(date); } } + + public static class TL_stats_storyStats extends TLObject { + public final static int constructor = 0x50cd067c; + + public TLRPC.StatsGraph views_graph; + public TLRPC.StatsGraph reactions_by_emotion_graph; + + public static TL_stats_storyStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stats_storyStats.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stats_storyStats", constructor)); + } else { + return null; + } + } + TL_stats_storyStats result = new TL_stats_storyStats(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + views_graph = TLRPC.StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = TLRPC.StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + views_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); + } + } + + public static class TL_stats_getStoryStats extends TLObject { + public final static int constructor = 0x374fef40; + + public int flags; + public boolean dark; + public TLRPC.InputPeer peer; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stats_storyStats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = dark ? (flags | 1) : (flags & ~1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index d60f5dabc4..94eefbd8c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -64,6 +64,7 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.GroupCallPip; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.StoryViewer; import java.util.ArrayList; @@ -255,10 +256,27 @@ public void setFragmentPanTranslationOffset(int fragmentPanTranslationOffset) { invalidate(); } + float lastY, startY; // for menu buttons to be clicked by hover: private float pressX, pressY; private boolean allowToPressByHover; public void processMenuButtonsTouch(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + startY = event.getY(); + } + if (isInPreviewMode() && previewMenu == null) { + lastY = event.getY(); + if (event.getAction() == MotionEvent.ACTION_UP) { + finishPreviewFragment(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + float dy = startY - lastY; + movePreviewFragment(dy); + if (dy < 0) { + startY = lastY; + } + } + return; + } if (event.getAction() == MotionEvent.ACTION_DOWN) { pressX = event.getX(); pressY = event.getY(); @@ -1246,14 +1264,16 @@ public boolean presentFragment(NavigationParams params) { return false; } BaseFragment lastFragment = getLastFragment(); - if (lastFragment != null && lastFragment.getVisibleDialog() != null) { - if (shouldOpenFragmentOverlay(lastFragment.getVisibleDialog())) { - BaseFragment.BottomSheetParams bottomSheetParams = new BaseFragment.BottomSheetParams(); - bottomSheetParams.transitionFromLeft = true; - bottomSheetParams.allowNestedScroll = false; - lastFragment.showAsSheet(fragment, bottomSheetParams); - return true; - } + Dialog dialog = lastFragment != null ? lastFragment.getVisibleDialog() : null; + if (dialog == null && LaunchActivity.instance != null && LaunchActivity.instance.visibleDialog != null) { + dialog = LaunchActivity.instance.visibleDialog; + } + if (shouldOpenFragmentOverlay(dialog)) { + BaseFragment.BottomSheetParams bottomSheetParams = new BaseFragment.BottomSheetParams(); + bottomSheetParams.transitionFromLeft = true; + bottomSheetParams.allowNestedScroll = false; + lastFragment.showAsSheet(fragment, bottomSheetParams); + return true; } if (BuildVars.LOGS_ENABLED) { FileLog.d("present fragment " + fragment.getClass().getSimpleName() + " args=" + fragment.getArguments()); @@ -2072,7 +2092,7 @@ public void setThemeAnimationValue(float value) { for (int i = 0, N = presentingFragmentDescriptions.size(); i < N; i++) { ThemeDescription description = presentingFragmentDescriptions.get(i); int key = description.getCurrentKey(); - description.setColor(Theme.getColor(key), false, false); + description.setColor(Theme.getColor(key, description.resourcesProvider), false, false); } } if (animationProgressListener != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 01b62d38c9..aea1801ab4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -1882,6 +1882,17 @@ public void hideSubItem(int id) { } } + public boolean hasSubItem(int id) { + Item lazyItem = findLazyItem(id); + if (lazyItem != null) { + return true; + } + if (popupLayout == null) { + return false; + } + return popupLayout.findViewWithTag(id) != null; + } + /** * Hides this menu item if no subitems are available */ diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 10e2dacc5f..7b4a54e115 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -22,6 +22,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; @@ -87,7 +88,7 @@ public abstract class BaseFragment { protected boolean fragmentBeginToShow; private boolean removingFromStack; private PreviewDelegate previewDelegate; - private Theme.ResourcesProvider resourceProvider; + protected Theme.ResourcesProvider resourceProvider; public StoryViewer storyViewer; public StoryViewer overlayStoryViewer; @@ -843,7 +844,8 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams fragment.onTransitionAnimationStart(true, false); bottomSheet[0] = new BottomSheet(getParentActivity(), true, fragment.getResourceProvider()) { { - drawNavigationBar = true; + occupyNavigationBar = params != null && params.occupyNavigationBar; + drawNavigationBar = !occupyNavigationBar; actionBarLayout[0].setFragmentStack(new ArrayList<>()); actionBarLayout[0].addFragmentToStack(fragment); actionBarLayout[0].showLastFragment(); @@ -864,8 +866,13 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); actionBarLayout[0].setWindow(bottomSheet[0].getWindow()); - fixNavigationBar(Theme.getColor(Theme.key_dialogBackgroundGray, fragment.getResourceProvider())); + if (params == null || !params.occupyNavigationBar) { + fixNavigationBar(Theme.getColor(Theme.key_dialogBackgroundGray, fragment.getResourceProvider())); + } else { + AndroidUtilities.setLightNavigationBar(bottomSheet[0].getWindow(), true); + } AndroidUtilities.setLightStatusBar(getWindow(), fragment.isLightStatusBar()); + fragment.onBottomSheetCreated(); } @Override @@ -874,8 +881,17 @@ protected boolean canDismissWithSwipe() { } @Override - protected boolean canSwipeToBack() { - return params != null && params.transitionFromLeft && actionBarLayout[0] != null && actionBarLayout[0].getFragmentStack().size() <= 1; + protected boolean canSwipeToBack(MotionEvent event) { + if (params != null && params.transitionFromLeft && actionBarLayout[0] != null && actionBarLayout[0].getFragmentStack().size() <= 1) { + if (actionBarLayout[0].getFragmentStack().size() == 1) { + BaseFragment lastFragment = actionBarLayout[0].getFragmentStack().get(0); + if (!lastFragment.isSwipeBackEnabled(event)) { + return false; + } + } + return true; + } + return false; } @Override @@ -923,6 +939,7 @@ protected void onInsetsChanged() { bottomSheet[0].transitionFromRight(params.transitionFromLeft); } fragment.setParentDialog(bottomSheet[0]); + bottomSheet[0].setOpenNoDelay(true); bottomSheet[0].show(); return actionBarLayout; @@ -949,7 +966,7 @@ public boolean hasForceLightStatusBar() { } public int getNavigationBarColor() { - int color = Theme.getColor(Theme.key_windowBackgroundGray, resourceProvider); + int color = Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider()); if (storyViewer != null && storyViewer.attachedToParent()) { return storyViewer.getNavigationBarColor(color); } @@ -1114,12 +1131,17 @@ public StoryViewer getOrCreateOverlayStoryViewer() { return overlayStoryViewer; } + public void onBottomSheetCreated() { + + } + public static class BottomSheetParams { public boolean transitionFromLeft; public boolean allowNestedScroll; public Runnable onDismiss; public Runnable onOpenAnimationFinished; public Runnable onPreFinished; + public boolean occupyNavigationBar; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 006d013380..55b4de2f57 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -29,6 +29,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -348,6 +349,7 @@ private void cancelCurrentAnimation() { private float y = 0f; private float swipeBackX = 0f; + private boolean allowedSwipeToBack; public boolean processTouchEvent(MotionEvent ev, boolean intercept) { if (dismissed) { return false; @@ -355,8 +357,9 @@ public boolean processTouchEvent(MotionEvent ev, boolean intercept) { if (onContainerTouchEvent(ev)) { return true; } - if (canSwipeToBack()) { + if (canSwipeToBack(ev) || allowedSwipeToBack) { if (ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && (!startedTracking && !maybeStartTracking && ev.getPointerCount() == 1)) { + allowedSwipeToBack = true; startedTrackingX = (int) ev.getX(); startedTrackingY = (int) ev.getY(); startedTrackingPointerId = ev.getPointerId(0); @@ -424,6 +427,7 @@ public void onAnimationEnd(Animator animation) { maybeStartTracking = false; startedTracking = false; startedTrackingPointerId = -1; + allowedSwipeToBack = false; } } else { if (canDismissWithTouchOutside() && ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && (!startedTracking && !maybeStartTracking && ev.getPointerCount() == 1)) { @@ -440,7 +444,7 @@ public void onAnimationEnd(Animator animation) { if (velocityTracker != null) { velocityTracker.clear(); } - } else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { + } else if (canDismissWithSwipe() && ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } @@ -480,7 +484,7 @@ public void onAnimationEnd(Animator animation) { startedTrackingPointerId = -1; } } - return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack()); + return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack(ev)); } @Override @@ -572,7 +576,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto right -= getRightInset(); if (useSmoothKeyboard) { t = 0; - } else { + } else if (!occupyNavigationBar) { t -= lastInsets.getSystemWindowInsetBottom() * (1f - hideSystemVerticalInsetsProgress) - (drawNavigationBar ? 0 : getBottomInset()); if (Build.VERSION.SDK_INT >= 29) { t -= getAdditionalMandatoryOffsets(); @@ -674,7 +678,7 @@ public void onAnimationEnd(Animator animation) { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (canDismissWithSwipe() || canSwipeToBack()) { + if (canDismissWithSwipe() || canSwipeToBack(event)) { return processTouchEvent(event, true); } return super.onInterceptTouchEvent(event); @@ -764,7 +768,7 @@ protected void onDraw(Canvas canvas) { restore = true; } super.onDraw(canvas); - if (lastInsets != null && keyboardHeight != 0) { + if (drawNavigationBar && lastInsets != null && keyboardHeight != 0) { backgroundPaint.setColor(behindKeyboardColorKey >= 0 ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); } @@ -1121,7 +1125,7 @@ public void fixNavigationBar() { } public void fixNavigationBar(int bgColor) { - drawNavigationBar = true; + drawNavigationBar = !occupyNavigationBar; drawDoubleNavigationBar = true; scrollNavBar = true; navBarColorKey = -1; @@ -1337,7 +1341,10 @@ public void show() { } dismissed = false; cancelSheetAnimation(); - containerView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x + backgroundPaddingLeft * 2, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); + containerView.measure( + View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x + backgroundPaddingLeft * 2, View.MeasureSpec.AT_MOST), + View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST) + ); if (showWithoutAnimation) { backDrawable.setAlpha(dimBehind ? dimBehindAlpha : 0); containerView.setTranslationY(0); @@ -1678,7 +1685,7 @@ public int getContainerViewHeight() { return containerView.getMeasuredHeight(); } - protected boolean canSwipeToBack() { + protected boolean canSwipeToBack(MotionEvent event) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java index f251f6d383..33f6aa6a63 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -373,7 +373,7 @@ protected boolean createLayout(int width) { string = TextUtils.ellipsize(string, textPaint, width, TextUtils.TruncateAt.END); } if (!ellipsizeByGradient && !string.equals(text)) { - fullLayout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, fullTextMaxLines, false); + fullLayout = StaticLayoutEx.createStaticLayout(text, textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, fullTextMaxLines, false); if (fullLayout != null) { int end = fullLayout.getLineEnd(0); int start = fullLayout.getLineStart(1); @@ -392,7 +392,7 @@ protected boolean createLayout(int width) { part = "\u200F" + part; } partLayout = new StaticLayout(part, 0, part.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), getAlignment(), 1.0f, 0.0f, false); - fullLayout = StaticLayoutEx.createStaticLayout(full, 0, full.length(), textPaint, width + AndroidUtilities.dp(8) + fullLayoutAdditionalWidth, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, fullTextMaxLines, false); + fullLayout = StaticLayoutEx.createStaticLayout(full, textPaint, width + AndroidUtilities.dp(8) + fullLayoutAdditionalWidth, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, fullTextMaxLines, false); } } else { layout = new StaticLayout(string, 0, string.length(), textPaint, scrollNonFitText || ellipsizeByGradient ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), getAlignment(), 1.0f, 0.0f, false); @@ -401,7 +401,7 @@ protected boolean createLayout(int width) { firstLineLayout = null; } } else if (maxLines > 1) { - layout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, maxLines, false); + layout = StaticLayoutEx.createStaticLayout(text, textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, maxLines, false); } else { CharSequence string; if (scrollNonFitText || ellipsizeByGradient) { 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 f5ea3582b4..424528fc95 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -129,12 +129,13 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.RoundVideoProgressShadow; import org.telegram.ui.ThemeActivity; -import org.telegram.messenger.support.SparseLongArray; +import org.telegram.ui.ThemePreviewActivity; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; @@ -1460,7 +1461,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -1473,7 +1474,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA if (color == 0) { color = defaultColors[key_chat_outBubble]; } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); int distance1 = AndroidUtilities.getColorDistance(firstColor, newColor); int distance2 = AndroidUtilities.getColorDistance(firstColor, myMessagesGradientAccentColor1); @@ -1515,7 +1516,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -1535,7 +1536,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -2001,7 +2002,9 @@ public static int adaptHue(int color, int hueFromColor) { public static int adaptHSV(int color, float sat, float val) { float[] tempHSV = getTempHsv(5); Color.colorToHSV(color, tempHSV); - tempHSV[1] = MathUtils.clamp(tempHSV[1] + sat, 0, 1); + if (tempHSV[1] > .1f && tempHSV[1] < .9f) { // otherwise, saturation would reveal some random hue there + tempHSV[1] = MathUtils.clamp(tempHSV[1] + sat, 0, 1); + } tempHSV[2] = MathUtils.clamp(tempHSV[2] + val, 0, 1); return Color.HSVToColor(Color.alpha(color), tempHSV); } @@ -2052,6 +2055,7 @@ public static class OverrideWallpaperInfo { public long wallpaperId; public long accessHash; public long dialogId; + public boolean forBoth; public ThemeInfo parentTheme; public ThemeAccent parentAccent; @@ -2982,6 +2986,12 @@ default boolean hasGradientService() { return false; } + default boolean isDark() { + // used only in PeerColorActivity + // support in other implementations to use + return Theme.isCurrentThemeDark(); + } + default void applyServiceShaderMatrix(int w, int h, float translationX, float translationY) { Theme.applyServiceShaderMatrix(w, h, translationX, translationY); } @@ -3083,8 +3093,6 @@ public void run() { private static int serviceSelectedMessageColor; public static int serviceMessageColorBackup; public static int serviceSelectedMessageColorBackup; - private static int serviceMessage2Color; - private static int serviceSelectedMessage2Color; public static int currentColor; private static Drawable wallpaper; private static Drawable themedWallpaper; @@ -3103,7 +3111,7 @@ public void run() { public static Paint avatar_backgroundPaint; public static Drawable listSelector; - public static Drawable[] avatarDrawables = new Drawable[17]; + public static Drawable[] avatarDrawables = new Drawable[18]; public static Drawable moveUpDrawable; @@ -3189,8 +3197,6 @@ public void run() { public static Paint chat_messageBackgroundSelectedPaint; public static Paint chat_actionBackgroundPaint; public static Paint chat_actionBackgroundSelectedPaint; - public static Paint chat_actionBackgroundPaint2; - public static Paint chat_actionBackgroundSelectedPaint2; public static Paint chat_actionBackgroundGradientDarkenPaint; public static Paint chat_timeBackgroundPaint; public static Paint chat_composeBackgroundPaint; @@ -3306,6 +3312,7 @@ public void run() { public static Drawable chat_contextResult_shadowUnderSwitchDrawable; public static Drawable chat_shareIconDrawable; public static Drawable chat_replyIconDrawable; + public static Drawable chat_closeIconDrawable; public static Drawable chat_goIconDrawable; public static Drawable chat_botLinkDrawable; public static Drawable chat_botCardDrawable; @@ -4191,6 +4198,7 @@ public void run() { public static final String key_drawable_msgStickerViews = "drawableMsgStickerViews"; public static final String key_drawable_replyIcon = "drawableReplyIcon"; public static final String key_drawable_shareIcon = "drawableShareIcon"; + public static final String key_drawable_closeIcon = "drawableCloseIcon"; public static final String key_drawable_muteIconDrawable = "drawableMuteIcon"; public static final String key_drawable_lockIconDrawable = "drawableLockIcon"; public static final String key_drawable_chat_pollHintDrawableOut = "drawable_chat_pollHintDrawableOut"; @@ -4200,6 +4208,7 @@ public void run() { private static final HashMap defaultChatDrawableColorKeys = new HashMap<>(); public static final String key_paint_chatActionBackground = "paintChatActionBackground"; + public static final String key_paint_chatActionBackgroundDarken = "paintChatActionBackgroundDarken"; public static final String key_paint_chatActionBackgroundSelected = "paintChatActionBackgroundSelected"; public static final String key_paint_chatMessageBackgroundSelected = "paintChatMessageBackgroundSelected"; public static final String key_paint_chatActionText = "paintChatActionText"; @@ -4219,11 +4228,11 @@ public void run() { private static SparseIntArray animatingColors; private static boolean shouldDrawGradientIcons; - private static ThreadLocal hsvTemp1Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp2Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp3Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp4Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp5Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp1Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp2Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp3Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp4Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp5Local = new ThreadLocal<>(); private static FragmentContextViewWavesDrawable fragmentContextViewWavesDrawable; private static RoundVideoProgressShadow roundPlayDrawable; @@ -4532,7 +4541,7 @@ public void run() { new int[] { 0, 52, 46, 57, 45, 64, 52, 35, 36, 41, 50, 50, 35, 38, 37, 30 } ); sortAccents(themeInfo); - themes.add(currentDayTheme = currentTheme = defaultTheme = themeInfo); + themes.add(currentDayTheme = defaultTheme = themeInfo); themesDict.put("Blue", themeInfo); themeInfo = new ThemeInfo(); @@ -5409,6 +5418,14 @@ public static Drawable createServiceDrawable(int rad, View view, View containerV } public static Drawable createServiceDrawable(int rad, View view, View containerView, Paint backgroundPaint) { + return createServiceDrawable(rad, view, containerView, backgroundPaint, null); + } + + public static Drawable createServiceDrawable(int rad, View view, View containerView, Theme.ResourcesProvider resourcesProvider) { + return createServiceDrawable(rad, view, containerView, null, resourcesProvider); + } + + public static Drawable createServiceDrawable(int rad, View view, View containerView, Paint backgroundPaint, Theme.ResourcesProvider resourcesProvider) { return new Drawable() { private RectF rect = new RectF(); @@ -5418,9 +5435,9 @@ public void draw(@NonNull Canvas canvas) { Rect bounds = getBounds(); rect.set(bounds.left, bounds.top, bounds.right, bounds.bottom); applyServiceShaderMatrixForView(view, containerView); - canvas.drawRoundRect(rect, rad, rad, backgroundPaint); - if (hasGradientService()) { - canvas.drawRoundRect(rect, rad, rad, chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, rad, rad, backgroundPaint != null ? backgroundPaint : Theme.getThemePaint(Theme.key_paint_chatActionBackground, resourcesProvider)); + if (resourcesProvider != null ? resourcesProvider.hasGradientService() : hasGradientService()) { + canvas.drawRoundRect(rect, rad, rad, Theme.getThemePaint(Theme.key_paint_chatActionBackgroundDarken, resourcesProvider)); } } @@ -6661,6 +6678,24 @@ public static void refreshThemeColors(boolean bg, boolean messages) { AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewTheme, false, checkNavigationBarColor)); } + public static boolean hasHue(int color) { + float[] hsvTemp3 = getTempHsv(3); + Color.colorToHSV(color, hsvTemp3); + return hsvTemp3[1] > .1f && hsvTemp3[1] < .9f; + } + + public static int changeColorAccent(int themeBaseAccent, int accent, int color, boolean isDark) { + return changeColorAccent(themeBaseAccent, accent, color, isDark, color); + } + + public static int changeColorAccent(int themeBaseAccent, int accent, int color, boolean isDark, int fallback) { + float[] hsvTemp3 = getTempHsv(3); + float[] hsvTemp4 = getTempHsv(4); + Color.colorToHSV(themeBaseAccent, hsvTemp3); + Color.colorToHSV(accent, hsvTemp4); + return changeColorAccent(hsvTemp3, hsvTemp4, color, isDark, fallback); + } + public static int changeColorAccent(ThemeInfo themeInfo, int accent, int color) { if (accent == 0 || themeInfo.accentBaseColor == 0 || accent == themeInfo.accentBaseColor || themeInfo.firstAccentIsDefault && themeInfo.currentAccentId == DEFALT_THEME_ACCENT_ID) { return color; @@ -6670,7 +6705,7 @@ public static int changeColorAccent(ThemeInfo themeInfo, int accent, int color) Color.colorToHSV(themeInfo.accentBaseColor, hsvTemp3); Color.colorToHSV(accent, hsvTemp4); - return changeColorAccent(hsvTemp3, hsvTemp4, color, themeInfo.isDark()); + return changeColorAccent(hsvTemp3, hsvTemp4, color, themeInfo.isDark(), color); } public static float[] getTempHsv(int num) { @@ -6728,7 +6763,7 @@ private static float abs(float a) { } private static float[] tmpHSV5; - public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int color, boolean isDarkTheme) { + public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int color, boolean isDarkTheme, int fallback) { if (tmpHSV5 == null) { tmpHSV5 = new float[3]; } @@ -6737,7 +6772,7 @@ public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int colo final float diffH = Math.min(abs(colorHsv[0] - baseHsv[0]), abs(colorHsv[0] - baseHsv[0] - 360f)); if (diffH > 30f) { - return color; + return fallback; } float dist = Math.min(1.5f * colorHsv[1] / baseHsv[1], 1f); @@ -8230,6 +8265,7 @@ public static void createCommonResources(Context context) { avatarDrawables[14] = resources.getDrawable(R.drawable.filled_gift_premium); avatarDrawables[15] = resources.getDrawable(R.drawable.filled_unknown); avatarDrawables[16] = resources.getDrawable(R.drawable.filled_unclaimed); + avatarDrawables[17] = resources.getDrawable(R.drawable.large_repost_story); if (dialogs_archiveAvatarDrawable != null) { dialogs_archiveAvatarDrawable.setCallback(null); @@ -8635,7 +8671,7 @@ public static void createCommonChatResources() { chat_unlockExtendedMediaTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_unlockExtendedMediaTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundGradientDarkenPaint.setColor(0x2a000000); + chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); chat_timeBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_contextResult_titleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -8645,13 +8681,12 @@ public static void createCommonChatResources() { chat_radialProgressPausedSeekbarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_messageBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundSelectedPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); addChatPaint(key_paint_chatMessageBackgroundSelected, chat_messageBackgroundSelectedPaint, key_chat_selectedBackground); addChatPaint(key_paint_chatActionBackground, chat_actionBackgroundPaint, key_chat_serviceBackground); + addChatPaint(key_paint_chatActionBackgroundDarken, chat_actionBackgroundGradientDarkenPaint, key_chat_serviceBackground); addChatPaint(key_paint_chatActionBackgroundSelected, chat_actionBackgroundSelectedPaint, key_chat_serviceBackgroundSelected); addChatPaint(key_paint_chatActionText, chat_actionTextPaint, key_chat_serviceText); addChatPaint(key_paint_chatActionText2, chat_actionTextPaint2, key_chat_serviceText); @@ -8779,6 +8814,7 @@ public static void createChatResources(Context context, boolean fontsOnly) { chat_shareIconDrawable = resources.getDrawable(R.drawable.filled_button_share).mutate(); chat_replyIconDrawable = resources.getDrawable(R.drawable.filled_button_reply); + chat_closeIconDrawable = resources.getDrawable(R.drawable.msg_voiceclose).mutate(); chat_goIconDrawable = resources.getDrawable(R.drawable.message_arrow); int rad = AndroidUtilities.dp(2); @@ -8873,6 +8909,7 @@ public static void createChatResources(Context context, boolean fontsOnly) { addChatDrawable(key_drawable_msgStickerReplies, chat_msgStickerRepliesDrawable, key_chat_serviceText); addChatDrawable(key_drawable_msgStickerViews, chat_msgStickerViewsDrawable, key_chat_serviceText); addChatDrawable(key_drawable_replyIcon, chat_replyIconDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_closeIcon, chat_closeIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_shareIcon, chat_shareIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_muteIconDrawable, chat_muteIconDrawable, key_chat_muteIcon); addChatDrawable(key_drawable_lockIconDrawable, chat_lockIconDrawable, key_chat_lockIcon); @@ -9126,6 +9163,18 @@ public static void applyServiceShaderMatrixForView(View view, View background, R int x = viewPos[0]; int y = viewPos[1]; background.getLocationOnScreen(viewPos); + if (background instanceof ThemePreviewActivity.BackgroundView) { + if (serviceBitmap != null) { + float bitmapWidth = serviceBitmap.getWidth(); + float bitmapHeight = serviceBitmap.getHeight(); + float maxScale = Math.max(background.getMeasuredWidth() / bitmapWidth, background.getMeasuredHeight() / bitmapHeight); + float width = bitmapWidth * maxScale; + x += ((background.getMeasuredWidth() - width) / 2) -((ThemePreviewActivity.BackgroundView) background).tx; + } else { + x += -((ThemePreviewActivity.BackgroundView) background).tx; + } + y += -((ThemePreviewActivity.BackgroundView) background).ty; + } if (resourcesProvider != null) { resourcesProvider.applyServiceShaderMatrix(background.getMeasuredWidth(), background.getMeasuredHeight(), x, y - viewPos[1]); } else { @@ -9138,7 +9187,7 @@ public static void applyServiceShaderMatrix(int w, int h, float translationX, fl } public static void applyServiceShaderMatrix(Bitmap bitmap, BitmapShader shader, Matrix matrix, int w, int h, float translationX, float translationY) { - if (shader == null) { + if (shader == null || matrix == null) { return; } @@ -9165,40 +9214,44 @@ public static void applyChatServiceMessageColor(int[] custom, Drawable wallpaper return; } int serviceColor; - int serviceColor2; int servicePressedColor; - int servicePressedColor2; serviceMessageColor = serviceMessageColorBackup; serviceSelectedMessageColor = serviceSelectedMessageColorBackup; if (custom != null && custom.length >= 2) { - serviceColor2 = serviceColor = custom[0]; - servicePressedColor2 = servicePressedColor = custom[1]; + serviceColor = custom[0]; + servicePressedColor = custom[1]; serviceMessageColor = custom[0]; serviceSelectedMessageColor = custom[1]; } else { int serviceIndex = currentColors.indexOfKey(key_chat_serviceBackground); if (serviceIndex >= 0) { - serviceColor2 = serviceColor = currentColors.valueAt(serviceIndex); + serviceColor = currentColors.valueAt(serviceIndex); } else { serviceColor = serviceMessageColor; - serviceColor2 = serviceMessage2Color; } int servicePressedIndex = currentColors.indexOfKey(key_chat_serviceBackgroundSelected); if (servicePressedIndex >= 0) { - servicePressedColor2 = servicePressedColor = currentColors.valueAt(servicePressedIndex); + servicePressedColor = currentColors.valueAt(servicePressedIndex); } else { servicePressedColor = serviceSelectedMessageColor; - servicePressedColor2 = serviceSelectedMessage2Color; } } Drawable drawable = wallpaperOverride != null ? wallpaperOverride : currentWallpaper; - boolean drawServiceGradient = drawable instanceof MotionBackgroundDrawable && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); + boolean drawServiceGradient = (drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); if (drawServiceGradient) { - Bitmap newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + Bitmap newBitmap = null; + if (drawable instanceof MotionBackgroundDrawable) { + newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + } else if (drawable instanceof BitmapDrawable) { + newBitmap = checkBlur(drawable); + } if (serviceBitmap != newBitmap) { serviceBitmap = newBitmap; serviceBitmapShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceBitmapShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } if (serviceBitmapMatrix == null) { serviceBitmapMatrix = new Matrix(); } @@ -9247,26 +9300,83 @@ public static void applyChatServiceMessageColor(int[] custom, Drawable wallpaper chat_actionBackgroundPaint.setColor(serviceColor); chat_actionBackgroundSelectedPaint.setColor(servicePressedColor); - chat_actionBackgroundPaint2.setColor(serviceColor2); currentColor = serviceColor; - if (serviceBitmapShader != null && (currentColors.indexOfKey(key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable)) { + if (serviceBitmapShader != null && (currentColors.indexOfKey(key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable)) { ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(((MotionBackgroundDrawable) drawable).getIntensity() >= 0 ? 1.8f : 0.5f); + if (drawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); + if (intensity >= 0) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? +.12f : -.06f); + } else { + colorMatrix.setSaturation(1.1f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .4f : .8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? +.08f : -.06f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .9f : .84f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? -.04f : +.06f); + } + chat_actionBackgroundPaint.setFilterBitmap(true); chat_actionBackgroundPaint.setShader(serviceBitmapShader); chat_actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); - chat_actionBackgroundPaint.setAlpha(127); + chat_actionBackgroundPaint.setAlpha(0xff); + chat_actionBackgroundSelectedPaint.setFilterBitmap(true); chat_actionBackgroundSelectedPaint.setShader(serviceBitmapShader); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.26f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .92f : .92f); chat_actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); - chat_actionBackgroundSelectedPaint.setAlpha(200); + chat_actionBackgroundSelectedPaint.setAlpha(0xff); + + chat_actionBackgroundGradientDarkenPaint.setAlpha(0); } else { chat_actionBackgroundPaint.setColorFilter(null); chat_actionBackgroundPaint.setShader(null); chat_actionBackgroundSelectedPaint.setColorFilter(null); chat_actionBackgroundSelectedPaint.setShader(null); + + chat_actionBackgroundGradientDarkenPaint.setAlpha(0x15); + } + } + + private static WeakReference lastDrawableToBlur; + private static Bitmap blurredBitmap; + private static Bitmap checkBlur(Drawable d) { + if (lastDrawableToBlur != null && lastDrawableToBlur.get() == d) { + return blurredBitmap; + } + if (lastDrawableToBlur != null) { + lastDrawableToBlur.clear(); + } + lastDrawableToBlur = null; + if (d == null || d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) { + return blurredBitmap = null; + } + lastDrawableToBlur = new WeakReference<>(d); + + final int h = 24; + final int w = (int) ((float) d.getIntrinsicWidth() / d.getIntrinsicHeight() * h); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + d.setBounds(0, 0, w, h); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + final ColorFilter wasColorFilter = d.getColorFilter(); + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(1.3f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .94f); + d.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + d.draw(new Canvas(bitmap)); + d.setColorFilter(wasColorFilter); + } else { + d.draw(new Canvas(bitmap)); } + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + return blurredBitmap = bitmap; } public static void applyChatMessageSelectedBackgroundColor() { @@ -9417,7 +9527,7 @@ public static int getDefaultAccentColor(int key) { float[] hsvTemp2 = getTempHsv(2); Color.colorToHSV(currentTheme.accentBaseColor, hsvTemp1); Color.colorToHSV(accent.accentColor, hsvTemp2); - return changeColorAccent(hsvTemp1, hsvTemp2, color, currentTheme.isDark()); + return changeColorAccent(hsvTemp1, hsvTemp2, color, currentTheme.isDark(), color); } return 0; } @@ -9699,8 +9809,6 @@ private static void calcBackgroundColor(Drawable drawable, int save) { int[] result = AndroidUtilities.calcDrawableColor(drawable); serviceMessageColor = serviceMessageColorBackup = result[0]; serviceSelectedMessageColor = serviceSelectedMessageColorBackup = result[1]; - serviceMessage2Color = result[2]; - serviceSelectedMessage2Color = result[3]; } } @@ -9783,7 +9891,8 @@ private static Drawable loadWallpaperInternal(OverrideWallpaperInfo overrideWall hasPreviousTheme, isApplyingAccent, wallpaperMotion, - finalWallpaperDocument + finalWallpaperDocument, + false ); isWallpaperMotion = settings.isWallpaperMotion != null ? settings.isWallpaperMotion : isWallpaperMotion; isPatternWallpaper = settings.isPatternWallpaper != null ? settings.isPatternWallpaper : isPatternWallpaper; @@ -9792,6 +9901,7 @@ private static Drawable loadWallpaperInternal(OverrideWallpaperInfo overrideWall wallpaper = settings.wallpaper != null ? settings.wallpaper : wallpaper; Drawable drawable = settings.wallpaper; calcBackgroundColor(drawable, 1); + applyChatServiceMessageColor(); return drawable; } @@ -9800,7 +9910,8 @@ public static BackgroundDrawableSettings createBackgroundDrawable( ThemeInfo currentTheme, SparseIntArray currentColors, String wallpaperLink, - int prevoiusPhase + int prevoiusPhase, + boolean local ) { boolean defaultTheme = currentTheme.firstAccentIsDefault && currentTheme.currentAccentId == DEFALT_THEME_ACCENT_ID; ThemeAccent accent = currentTheme.getAccent(false); @@ -9812,7 +9923,7 @@ public static BackgroundDrawableSettings createBackgroundDrawable( : (int) (accent != null ? (accent.patternIntensity * 100) : currentTheme.patternIntensity); int wallpaperFileOffset = currentColorsNoAccent.get(key_wallpaperFileOffset, -1); - return createBackgroundDrawable(currentTheme, overrideWallpaper, currentColors, wallpaperFile, wallpaperLink, wallpaperFileOffset, intensity, prevoiusPhase, defaultTheme, false, false, wallpaperMotion, null); + return createBackgroundDrawable(currentTheme, overrideWallpaper, currentColors, wallpaperFile, wallpaperLink, wallpaperFileOffset, intensity, prevoiusPhase, defaultTheme, false, false, wallpaperMotion, null, local); } public static BackgroundDrawableSettings createBackgroundDrawable( @@ -9828,10 +9939,11 @@ public static BackgroundDrawableSettings createBackgroundDrawable( boolean hasPreviousTheme, boolean isApplyingAccent, boolean wallpaperMotion, - TLRPC.Document wallpaperDocument + TLRPC.Document wallpaperDocument, + boolean local ) { BackgroundDrawableSettings settings = new BackgroundDrawableSettings(); - settings.wallpaper = wallpaper; + settings.wallpaper = local ? null : wallpaper; boolean overrideTheme = (!hasPreviousTheme || isApplyingAccent) && overrideWallpaper != null; if (overrideWallpaper != null) { settings.isWallpaperMotion = overrideWallpaper.isMotion; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java index cff3015529..f7d73b4539 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -1373,7 +1373,7 @@ public static SparseArray createColorKeysMap() { colorKeysMap.put(key_voipgroup_overlayAlertGradientUnmuted, "voipgroup_overlayAlertGradientUnmuted"); colorKeysMap.put(key_voipgroup_overlayAlertGradientUnmuted2, "voipgroup_overlayAlertGradientUnmuted2"); colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin, "voipgroup_overlayAlertMutedByAdmin"); - colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin2, "kvoipgroup_overlayAlertMutedByAdmin2"); + colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin2, "voipgroup_overlayAlertMutedByAdmin2"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient, "voipgroup_mutedByAdminGradient"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient2, "voipgroup_mutedByAdminGradient2"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient3, "voipgroup_mutedByAdminGradient3"); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index e3caa36118..476e528ea5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -114,6 +114,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private Runnable cancelShowMoreAnimation; private ArrayList filterDialogIds; private final DialogsActivity dialogsActivity; + private final Theme.ResourcesProvider resourcesProvider; private int currentAccount = UserConfig.selectedAccount; @@ -165,11 +166,13 @@ public static class CategoryAdapterRecycler extends RecyclerListView.SelectionAd private final int currentAccount; private boolean drawChecked; private boolean forceDarkTheme; + private Theme.ResourcesProvider resourcesProvider; - public CategoryAdapterRecycler(Context context, int account, boolean drawChecked) { + public CategoryAdapterRecycler(Context context, int account, boolean drawChecked, Theme.ResourcesProvider resourcesProvider) { this.drawChecked = drawChecked; mContext = context; currentAccount = account; + this.resourcesProvider = resourcesProvider; } public void setIndex(int value) { @@ -178,7 +181,7 @@ public void setIndex(int value) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - HintDialogCell cell = new HintDialogCell(mContext, drawChecked); + HintDialogCell cell = new HintDialogCell(mContext, drawChecked, resourcesProvider); cell.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(80), AndroidUtilities.dp(86))); return new RecyclerListView.Holder(cell); } @@ -246,9 +249,10 @@ private boolean filter(Object obj) { return false; } - public DialogsSearchAdapter(Context context, DialogsActivity dialogsActivity, int messagesSearch, int type, DefaultItemAnimator itemAnimator, boolean allowGlobalSearch) { + public DialogsSearchAdapter(Context context, DialogsActivity dialogsActivity, int messagesSearch, int type, DefaultItemAnimator itemAnimator, boolean allowGlobalSearch, Theme.ResourcesProvider resourcesProvider) { this.itemAnimator = itemAnimator; this.dialogsActivity = dialogsActivity; + this.resourcesProvider = resourcesProvider; searchAdapterHelper = new SearchAdapterHelper(false) { @Override protected boolean filter(TLObject obj) { @@ -1420,7 +1424,7 @@ public boolean supportsPredictiveItemAnimations() { layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); //horizontalListView.setDisallowInterceptTouchEvents(true); - horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false)); + horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false, resourcesProvider)); horizontalListView.setOnItemClickListener((view1, position) -> { if (delegate != null) { delegate.didPressedOnSubDialog((Long) view1.getTag()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java new file mode 100644 index 0000000000..ef6c0614fb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java @@ -0,0 +1,82 @@ +package org.telegram.ui; + + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.style.ReplacementSpan; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.ImageReceiver; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AvatarDrawable; + +public class AvatarSpan extends ReplacementSpan { + + private final Paint shadowPaint; + private final ImageReceiver imageReceiver; + private final AvatarDrawable avatarDrawable; + private final int sz; + private final int currentAccount; + + public AvatarSpan(View parent, int currentAccount, int sz) { + this.currentAccount = currentAccount; + this.imageReceiver = new ImageReceiver(parent); + this.avatarDrawable = new AvatarDrawable(); + imageReceiver.setRoundRadius(dp(sz)); + this.sz = sz; + + this.shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + shadowPaint.setShadowLayer(dp(1), 0, dp(.66f), 0x33000000); + + if (parent != null && parent.isAttachedToWindow()) { + imageReceiver.onAttachedToWindow(); + } + if (parent != null) { + parent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(@NonNull View v) { + imageReceiver.onAttachedToWindow(); + } + + @Override + public void onViewDetachedFromWindow(@NonNull View v) { + imageReceiver.onDetachedFromWindow(); + } + }); + } + } + + public void setChat(TLRPC.Chat chat) { + avatarDrawable.setInfo(currentAccount, chat); + imageReceiver.setForUserOrChat(chat, avatarDrawable); + } + + public void setUser(TLRPC.User user) { + avatarDrawable.setInfo(currentAccount, user); + imageReceiver.setForUserOrChat(user, avatarDrawable); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return dp(sz); + } + + private float translateX, translateY; + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + canvas.drawCircle(translateX + x + dp(sz) / 2f, translateY + (top + bottom) / 2f, dp(sz) / 2f, shadowPaint); + imageReceiver.setImageCoords(translateX + x, translateY + (top + bottom) / 2f - dp(sz) / 2f, dp(sz), dp(sz)); + imageReceiver.draw(canvas); + } + + public void translate(float x, float y) { + this.translateX = x; + this.translateY = y; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 9ae45b1d84..99cb9dbced 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -3211,7 +3211,7 @@ public boolean equals(Object o) { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - if (cachedMediaLayout != null) { + if (cachedMediaLayout != null && event != null) { cachedMediaLayout.getHitRect(AndroidUtilities.rectTmp2); if (!AndroidUtilities.rectTmp2.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { return true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java index 01dfff8f5d..e0550c8053 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java @@ -21,8 +21,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -124,7 +122,7 @@ public void setObject(TLObject object) { public void setAccount(int account, boolean check) { accountNumber = account; TLRPC.User user = UserConfig.getInstance(accountNumber).getCurrentUser(); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); textView.setText(ContactsController.formatName(user.first_name, user.last_name)); imageView.getImageReceiver().setCurrentAccount(account); imageView.setForUserOrChat(user, avatarDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java index 1bf5dd0bef..21663d3b39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java @@ -88,7 +88,7 @@ public AdminedChannelCell(Context context, OnClickListener onClickListener, bool public void setChannel(TLRPC.Chat channel, boolean last) { final String url = MessagesController.getInstance(currentAccount).linkPrefix + "/"; currentChannel = channel; - avatarDrawable.setInfo(channel); + avatarDrawable.setInfo(currentAccount, channel); nameTextView.setText(channel.title); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(url + ChatObject.getPublicUsername(channel)); stringBuilder.setSpan(new URLSpanNoUnderline(""), url.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -98,7 +98,7 @@ public void setChannel(TLRPC.Chat channel, boolean last) { } public void update() { - avatarDrawable.setInfo(currentChannel); + avatarDrawable.setInfo(currentAccount, currentChannel); avatarImageView.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChannelRecommendationsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChannelRecommendationsCell.java new file mode 100644 index 0000000000..b1438fc894 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChannelRecommendationsCell.java @@ -0,0 +1,872 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.LocaleController.getString; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.graphics.text.LineBreaker; +import android.media.Image; +import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LoadingDrawable; +import org.telegram.ui.Components.Scroller; +import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.Components.Text; + +import java.util.ArrayList; + +public class ChannelRecommendationsCell { + + private ChatMessageCell cell; + public ChannelRecommendationsCell(ChatMessageCell cell) { + this.cell = cell; + this.scroller = new Scroller(cell.getContext()); + this.closeBounce = new ButtonBounce(cell); + + loading = true; + this.loadingAlpha = new AnimatedFloat(cell, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + private int currentAccount; + private long dialogId; + private MessageObject msg; + private TLRPC.Chat currentChat; + public long chatId; + + private final TextPaint serviceTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private StaticLayout serviceText; + private float serviceTextLeft, serviceTextRight; + private int serviceTextHeight; + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path backgroundPath = new Path(); + private float lastBackgroundPathExpandT = -1; + + private int blockWidth = dp(66); + private float scrollX; + private float channelsScrollWidth; + private final ArrayList channels = new ArrayList<>(); + + private final Path loadingPath = new Path(); + private LoadingDrawable loadingDrawable; + + private boolean loading; + private final AnimatedFloat loadingAlpha; + + private Text headerText; + + private final RectF backgroundBounds = new RectF(); + + private final RectF closeBounds = new RectF(); + private final ButtonBounce closeBounce; + private final Paint closePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public void setMessageObject(MessageObject messageObject) { + this.currentAccount = messageObject.currentAccount; + this.msg = messageObject; + this.dialogId = messageObject.getDialogId(); + this.currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + this.chatId = -dialogId; + + serviceTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + serviceTextPaint.setTextSize(dp(14)); + serviceTextPaint.setColor(cell.getThemedColor(Theme.key_chat_serviceText)); + serviceText = new StaticLayout(getString(R.string.ChannelJoined), serviceTextPaint, msg.getMaxMessageTextWidth(), Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); + serviceTextLeft = serviceText.getWidth(); + serviceTextRight = 0; + for (int i = 0; i < serviceText.getLineCount(); ++i) { + serviceTextLeft = Math.min(serviceTextLeft, serviceText.getLineLeft(i)); + serviceTextRight = Math.max(serviceTextRight, serviceText.getLineRight(i)); + } + serviceTextHeight = serviceText.getHeight(); + + closePaint.setStyle(Paint.Style.STROKE); + closePaint.setStrokeCap(Paint.Cap.ROUND); + closePaint.setStrokeJoin(Paint.Join.ROUND); + closePaint.setColor(cell.getThemedColor(Theme.key_dialogEmptyImage)); + + cell.totalHeight = dp(4 + 3.33f + 3.33f + 4) + serviceTextHeight; + + if (headerText == null) { + headerText = new Text(getString(R.string.SimilarChannels), 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)).hackClipBounds(); + } + + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).detach(); + } + channels.clear(); + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(-dialogId); + ArrayList chats = rec == null || rec.chats == null ? new ArrayList<>() : new ArrayList<>(rec.chats); + for (int i = 0; i < chats.size(); ++i) { + if (!ChatObject.isNotInChat(chats.get(i))) { + chats.remove(i); + i--; + } + } + loading = chats.isEmpty() || !UserConfig.getInstance(currentAccount).isPremium() && chats.size() == 1; + if (!loading) { + int count = chats.size(); + if (!UserConfig.getInstance(currentAccount).isPremium() && rec.more > 0) { + count = Math.min(count - 1, MessagesController.getInstance(currentAccount).recommendedChannelsLimitDefault); + } + count = Math.min(count, 10); + for (int i = 0; i < count; ++i) { + channels.add(new ChannelBlock(currentAccount, cell, chats.get(i))); + } + if (count < chats.size()) { + TLRPC.Chat[] _chats = new TLRPC.Chat[3]; + _chats[0] = count >= 0 && count < chats.size() ? chats.get(count) : null; + _chats[1] = count >= 0 && count + 1 < chats.size() ? chats.get(count + 1) : null; + _chats[2] = count >= 0 && count + 2 < chats.size() ? chats.get(count + 2) : null; + channels.add(new ChannelBlock(currentAccount, cell, _chats, (chats.size() + rec.more) - count)); + } + } + + if (isExpanded()) { + cell.totalHeight += dp(6 + 134 + 4); + backgroundPaint.setColor(cell.getThemedColor(Theme.key_chat_inBubble)); + } + + channelsScrollWidth = blockWidth * channels.size() + dp(9) * (channels.size() - 1); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth, 0); + } + + public boolean isExpanded() { + return msg.channelJoinedExpanded && channels.size() > 0; + } + + public void update() { + if (msg == null) { + return; + } + setMessageObject(msg); + cell.invalidateOutbounds(); + } + + public void onAttachedToWindow() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).attach(); + } + } + + public void onDetachedFromWindow() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).detach(); + } + } + +// public void drawText(Canvas canvas) { +// if (msg == null || cell == null) return; +// +// float y = 0; +// if (serviceText != null) { +// y += dp(4 + 3.33f + 3.33f) + serviceTextHeight; +// } +// +// float expandT; +// if (cell.transitionParams.animateRecommendationsExpanded) { +// if (isExpanded()) { +// expandT = cell.transitionParams.animateChangeProgress; +// } else { +// expandT = 1f - cell.transitionParams.animateChangeProgress; +// } +// } else { +// expandT = isExpanded() ? 1f : 0f; +// } +// expandT = Utilities.clamp((expandT - .3f) / .7f, 1, 0); +// if (expandT > 0) { +// int width = (int) Math.min(cell.getWidth() - dp(18), blockWidth * 6.5f); +// backgroundBounds.set( +// (cell.getWidth() - width) / 2f, +// y + dp(4 + 6), +// (cell.getWidth() + width) / 2f, +// y + dp(4 + 134) +// ); +// checkBackgroundPath(expandT); +// +// canvas.save(); +// final float s = .4f + .6f * expandT; +// canvas.scale(s, s, backgroundBounds.centerX(), backgroundBounds.top - dp(6)); +// +// canvas.clipPath(backgroundPath); +// +// if (headerText != null) { +// headerText.draw(canvas, backgroundBounds.left + dp(17), backgroundBounds.top + dp( 20), cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText), expandT); +// } +// +// final float loadingAlpha = this.loadingAlpha.set(loading); +// +// final float xstart = backgroundBounds.left + dp(7) - scrollX; +// final float xi = blockWidth + dp(9); +// int from = (int) Math.floor((backgroundBounds.left - width - xstart) / xi); +// int to = (int) Math.ceil((backgroundBounds.right - xstart) / xi); +// +// if (loadingAlpha < 1) { +// for (int i = Math.max(0, from); i < Math.min(to + 1, channels.size()); ++i) { +// ChannelBlock block = channels.get(i); +// +// canvas.save(); +// canvas.translate(xstart + i * xi, backgroundBounds.bottom - ChannelBlock.height()); +// block.drawText(canvas, blockWidth, expandT * (1f - loadingAlpha)); +// canvas.restore(); +// } +// } +// +// canvas.restore(); +// } +// } + + public void draw(Canvas canvas) { + if (msg == null || cell == null) return; + + computeScroll(); + + float y = 0; + if (serviceText != null) { + canvas.save(); + final float ox = (cell.getWidth() - serviceText.getWidth()) / 2f; + AndroidUtilities.rectTmp.set(ox + serviceTextLeft - dp(8.66f), dp(4), ox + serviceTextRight + dp(8.66f), dp(4 + 3.33f + 3.33f) + serviceTextHeight); + cell.drawServiceBackground(canvas, AndroidUtilities.rectTmp, dp(11), 1f); + canvas.translate(ox, dp(4 + 3.33f)); + serviceText.draw(canvas); + canvas.restore(); + + y += dp(4 + 3.33f + 3.33f) + serviceTextHeight; + } + + float expandT; + if (cell.transitionParams.animateRecommendationsExpanded) { + if (isExpanded()) { + expandT = cell.transitionParams.animateChangeProgress; + } else { + expandT = 1f - cell.transitionParams.animateChangeProgress; + } + } else { + expandT = isExpanded() ? 1f : 0f; + } + expandT = Utilities.clamp((expandT - .3f) / .7f, 1, 0); + + if (expandT > 0) { + final int cellWidth = cell.getWidth() - dp(18); + blockWidth = (int) (cellWidth > dp(66 * 6 + 9 * 5) ? dp(66) : Math.max(cellWidth / 4.5f - dp(9), dp(66))); + channelsScrollWidth = blockWidth * channels.size() + dp(9) * (channels.size() - 1); + final int width = (int) Math.min(cellWidth, blockWidth * 6.5f); + backgroundBounds.set( + (cell.getWidth() - width) / 2f, + y + dp(4 + 6), + (cell.getWidth() + width) / 2f, + y + dp(4 + 134) + ); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + checkBackgroundPath(expandT); + + canvas.save(); + final float s = .4f + .6f * expandT; + canvas.scale(s, s, backgroundBounds.centerX(), backgroundBounds.top - dp(6)); + + backgroundPaint.setAlpha((int) (0xFF * expandT)); + backgroundPaint.setShadowLayer(dpf2(1), 0, dpf2(0.33f), ColorUtils.setAlphaComponent(Color.BLACK, (int) (27 * expandT))); + canvas.drawPath(backgroundPath, backgroundPaint); + + canvas.clipPath(backgroundPath); + + if (headerText != null) { + headerText.draw(canvas, backgroundBounds.left + dp(17), backgroundBounds.top + dp( 20), cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText), expandT); + } + + final float loadingAlpha = this.loadingAlpha.set(loading); + + final float xstart = backgroundBounds.left + dp(7) - scrollX; + final float xi = blockWidth + dp(9); + int from = (int) Math.floor((backgroundBounds.left - width - xstart) / xi); + int to = (int) Math.ceil((backgroundBounds.right - xstart) / xi); + + if (loadingAlpha < 1) { + for (int i = Math.max(0, from); i < Math.min(to + 1, channels.size()); ++i) { + ChannelBlock block = channels.get(i); + + canvas.save(); + canvas.translate(xstart + i * xi, backgroundBounds.bottom - ChannelBlock.height()); + block.draw(canvas, blockWidth, expandT * (1f - loadingAlpha)); + block.drawText(canvas, blockWidth, expandT * (1f - loadingAlpha)); + canvas.restore(); + } + } + if (loadingAlpha > 0) { + loadingPath.rewind(); + for (int i = Math.max(0, from); i < to; ++i) { + ChannelBlock.fillPath(loadingPath, blockWidth, xstart + i * xi); + } + + if (loadingDrawable == null) { + loadingDrawable = new LoadingDrawable(); + loadingDrawable.usePath(loadingPath); + loadingDrawable.setAppearByGradient(false); + } + final int color = cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText); + loadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + loadingDrawable.setGradientScale(1.5f); + loadingDrawable.setAlpha((int) (0xFF * loadingAlpha)); + canvas.save(); + canvas.translate(0, backgroundBounds.bottom - ChannelBlock.height()); + loadingDrawable.draw(canvas); + canvas.restore(); + +// cell.invalidate(); + } + + final float cs = closeBounce.getScale(0.02f); + + final float cx = backgroundBounds.right - dp(16 + 4); + final float cy = backgroundBounds.top + dp(16 + 4); + canvas.save(); + canvas.scale(cs, cs, cx, cy); + closePaint.setStrokeWidth(dp(1.33f)); + canvas.drawLine(cx - dp(4), cy - dp(4), cx + dp(4), cy + dp(4), closePaint); + canvas.drawLine(cx - dp(4), cy + dp(4), cx + dp(4), cy - dp(4), closePaint); + closeBounds.set(cx - dp(12), cy - dp(12), cx + dp(12), cy + dp(12)); + canvas.restore(); + + canvas.restore(); + } + } + + private void checkBackgroundPath(float t) { + if (Math.abs(t - lastBackgroundPathExpandT) < 0.001f) { + return; + } + + final float r = dp(16.66f); + final float d = r * 2; + + final float bottom = backgroundBounds.bottom; + + backgroundPath.rewind(); + AndroidUtilities.rectTmp.set(backgroundBounds.left, backgroundBounds.top, backgroundBounds.left + d, backgroundBounds.top + d); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -90, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.left, bottom - d, backgroundBounds.left + d, bottom); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -180, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.right - d, bottom - d, backgroundBounds.right, bottom); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -270, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.right - d, backgroundBounds.top, backgroundBounds.right, backgroundBounds.top + d); + backgroundPath.arcTo(AndroidUtilities.rectTmp, 0, -90); + backgroundPath.lineTo(backgroundBounds.centerX() + dp(8), backgroundBounds.top); + backgroundPath.lineTo(backgroundBounds.centerX(), backgroundBounds.top - dp(6)); + backgroundPath.lineTo(backgroundBounds.centerX() - dp(8), backgroundBounds.top); + backgroundPath.close(); + } + + private static class ChannelBlock { + public static int height() { return dp(99); }; + public static int avatarSize() { return dp(54); }; + + private final ChatMessageCell cell; + public final AvatarDrawable[] avatarDrawable; + public final ImageReceiver[] avatarImageReceiver; + + private final TextPaint nameTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final CharSequence name; + private StaticLayout nameText; + + public final boolean isLock; + private final Drawable subscribersDrawable; + private final Paint subscribersStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint subscribersBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint subscribersBackgroundDimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private BitmapShader subscribersBackgroundPaintShader; + private int subscribersBackgroundPaintBitmapWidth, subscribersBackgroundPaintBitmapHeight; + private Matrix subscribersBackgroundPaintMatrix; + private final Text subscribersText; + + private boolean subscribersColorSetFromThumb; + private boolean subscribersColorSet; + + public final ButtonBounce bounce; + public final TLRPC.Chat chat; + + public ChannelBlock(int currentAccount, ChatMessageCell cell, TLRPC.Chat[] chats, int moreCount) { + this.cell = cell; + this.chat = chats[0]; + this.bounce = new ButtonBounce(cell) { + @Override + public void invalidate() { + cell.invalidateOutbounds(); + } + }; + final int count = 3; + avatarImageReceiver = new ImageReceiver[count]; + avatarDrawable = new AvatarDrawable[count]; + for (int i = 0; i < count; ++i) { + avatarImageReceiver[i] = new ImageReceiver(cell); + avatarImageReceiver[i].setParentView(cell); + avatarImageReceiver[i].setRoundRadius(avatarSize()); + avatarDrawable[i] = new AvatarDrawable(); + if (i < chats.length && chats[i] != null) { + avatarDrawable[i].setInfo(currentAccount, chats[i]); + avatarImageReceiver[i].setForUserOrChat(chats[i], avatarDrawable[i]); + } else { +// int resId = i == 1 ? R.drawable.widget_avatar_5 : R.drawable.widget_avatar_4; +// Drawable avatar = cell.getContext().getResources().getDrawable(resId).mutate(); +// avatarImageReceiver[i].setImageBitmap(avatar); + final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + final int color = Theme.blendOver(cell.getThemedColor(Theme.key_chat_inBubble), Theme.multAlpha(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText), .50f)); + paint.setColor(color); + avatarImageReceiver[i].setImageBitmap(new Drawable() { + @Override + public void draw(@NonNull Canvas canvas) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), getBounds().width() / 2f, paint); + } + @Override + public void setAlpha(int alpha) { + paint.setAlpha(Theme.multAlpha(color, alpha / 255f)); + } + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + }); + } + } + if (cell.isCellAttachedToWindow()) { + attach(); + } + + nameTextPaint.setTextSize(dp(11)); + final boolean isPremium = UserConfig.getInstance(cell.currentAccount).isPremium(); + name = LocaleController.getString(isPremium ? R.string.MoreSimilar : R.string.UnlockSimilar); + + subscribersStrokePaint.setStyle(Paint.Style.STROKE); + isLock = true; + subscribersDrawable = isPremium ? null : cell.getContext().getResources().getDrawable(R.drawable.mini_switch_lock).mutate(); + if (chat == null || chat.participants_count <= 1) { + subscribersText = null; + } else { + subscribersText = new Text("+" + moreCount, 9.33f, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + } + + private void checkNameText(int width) { + if (nameText != null && nameText.getWidth() == width) + return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + nameText = StaticLayout.Builder.obtain(name, 0, name.length(), nameTextPaint, width) + .setMaxLines(2) + .setEllipsize(TextUtils.TruncateAt.END) + .setBreakStrategy(LineBreaker.BREAK_STRATEGY_SIMPLE) + .setAlignment(Layout.Alignment.ALIGN_CENTER) + .build(); + } else { + nameText = StaticLayoutEx.createStaticLayout(name, nameTextPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false, TextUtils.TruncateAt.END, width - dp(16), 2, false); + } + } + + public ChannelBlock(int currentAccount, ChatMessageCell cell, TLRPC.Chat chat) { + this.cell = cell; + this.chat = chat; + this.bounce = new ButtonBounce(cell) { + @Override + public void invalidate() { + cell.invalidateOutbounds(); + } + }; + avatarImageReceiver = new ImageReceiver[1]; + avatarImageReceiver[0] = new ImageReceiver(cell); + avatarImageReceiver[0].setParentView(cell); + avatarImageReceiver[0].setRoundRadius(avatarSize()); + if (cell.isCellAttachedToWindow()) { + attach(); + } + + avatarDrawable = new AvatarDrawable[1]; + avatarDrawable[0] = new AvatarDrawable(); + avatarDrawable[0].setInfo(currentAccount, chat); + avatarImageReceiver[0].setForUserOrChat(chat, avatarDrawable[0]); + + nameTextPaint.setTextSize(dp(11)); + CharSequence title = chat != null ? chat.title : ""; + try { + title = Emoji.replaceEmoji(title, nameTextPaint.getFontMetricsInt(), false); + } catch (Exception ignore) {} + name = title; + + subscribersStrokePaint.setStyle(Paint.Style.STROKE); + isLock = false; + subscribersDrawable = cell.getContext().getResources().getDrawable(R.drawable.mini_reply_user).mutate(); + if (chat == null || chat.participants_count <= 1) { + subscribersText = null; + } else { + subscribersText = new Text(chat != null ? LocaleController.formatShortNumber(chat.participants_count, null) : "", 9.33f, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + } + + public void drawText(Canvas canvas, int width, float alpha) { + canvas.save(); + final float s = bounce.getScale(0.075f); + canvas.scale(s, s, width / 2f, height() / 2f); + + checkNameText(width); + if (nameText != null) { + canvas.save(); + canvas.translate((width - nameText.getWidth()) / 2f, dp(66.33f)); + if (avatarImageReceiver.length <= 1) { + nameTextPaint.setColor(cell.getThemedColor(Theme.key_chat_messageTextIn)); + } else { + nameTextPaint.setColor(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText)); + } + nameTextPaint.setAlpha((int) (nameTextPaint.getAlpha() * alpha)); + nameText.draw(canvas); + canvas.restore(); + } + + if (subscribersText != null) { + subscribersText.ellipsize(width - dp(32)); + final float subscribersTextWidth = dp(subscribersDrawable != null ? 17 : 8) + subscribersText.getWidth(); + float left = (width - subscribersTextWidth) / 2f; + final float cy = dp(11 - 14.33f / 2f + .33f) + avatarSize(); + final float sc = .625f; + if (subscribersDrawable != null) { + subscribersDrawable.setBounds( + (int) (left + (isLock ? subscribersText.getWidth() + dp(1.33f) : 0) + dp(3)), + (int) (cy - subscribersDrawable.getIntrinsicHeight() / 2f * sc), + (int) (left + (isLock ? subscribersText.getWidth() + dp(1.33f) : 0) + dp(3) + subscribersDrawable.getIntrinsicWidth() * sc), + (int) (cy + subscribersDrawable.getIntrinsicHeight() / 2f * sc) + ); + subscribersDrawable.draw(canvas); + } + subscribersText.draw(canvas, left + dp(!isLock ? 12.66f : 4), cy, Color.WHITE, alpha); + } + + canvas.restore(); + } + + private Path subscribersBackgroundPath; + + public void draw(Canvas canvas, int width, float alpha) { + canvas.save(); + final float s = bounce.getScale(0.075f); + canvas.scale(s, s, width / 2f, height() / 2f); + + subscribersStrokePaint.setStrokeWidth(dp(2.66f)); + subscribersStrokePaint.setColor(cell.getThemedColor(Theme.key_chat_inBubble)); + for (int i = avatarImageReceiver.length - 1; i >= 0; --i) { + final float x = width / 2f - dp(7) * (avatarImageReceiver.length - 1) / 2f + i * dp(7); + final float y = dp(10) + avatarSize() / 2f; + if (avatarImageReceiver.length > 1) { + canvas.drawCircle(x, y, avatarSize() / 2f, subscribersStrokePaint); + } + avatarImageReceiver[i].setImageCoords( + x - avatarSize() / 2f, + y - avatarSize() / 2f, + avatarSize(), + avatarSize() + ); + avatarImageReceiver[i].setAlpha(alpha); + avatarImageReceiver[i].draw(canvas); + } + + if (subscribersText != null) { + subscribersText.ellipsize(width - dp(32)); + final float subscribersTextWidth = dp(subscribersDrawable != null ? 17 : 8) + subscribersText.getWidth(); + + final float bottom = dp(10) + avatarSize() + dp(1); + AndroidUtilities.rectTmp.set((width - subscribersTextWidth) / 2f, bottom - dp(14.33f), (width + subscribersTextWidth) / 2f, bottom); + + if (!subscribersColorSet && isLock) { + subscribersBackgroundPaint.setColor(Theme.blendOver(cell.getThemedColor(Theme.key_chat_inBubble), Theme.multAlpha(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText), .85f))); + subscribersColorSet = true; + } else if (!subscribersColorSet && avatarImageReceiver[0].getStaticThumb() instanceof BitmapDrawable) { + final Bitmap bitmap = ((BitmapDrawable) avatarImageReceiver[0].getStaticThumb()).getBitmap(); + try { + final int bitmapColor = bitmap.getPixel(bitmap.getWidth() / 2, bitmap.getHeight() - 2); + float[] hsl = new float[3]; + ColorUtils.colorToHSL(bitmapColor, hsl); + if (hsl[1] <= .05f || hsl[1] >= .95f || hsl[2] <= .02f || hsl[2] >= .98f) { + hsl[1] = 0; + hsl[2] = Theme.isCurrentThemeDark() ? .38f : .70f; + } else { + hsl[1] = .25f; + hsl[2] = Theme.isCurrentThemeDark() ? .35f : .65f; + } + subscribersBackgroundPaint.setColor(ColorUtils.HSLToColor(hsl)); + } catch (Exception e) { + FileLog.e(e); + } + subscribersColorSet = true; + } else if (!subscribersColorSet && !subscribersColorSetFromThumb) { + try { + final int color = ColorUtils.blendARGB(avatarDrawable[0].getColor(), avatarDrawable[0].getColor2(), .5f); + float[] hsl = new float[3]; + ColorUtils.colorToHSL(color, hsl); + if (hsl[1] <= .05f || hsl[1] >= .95f) { + hsl[2] = Utilities.clamp(hsl[2] - .1f, .6f, .3f); + } else { + hsl[1] = Utilities.clamp(hsl[1] - .06f, .4f, 0); + hsl[2] = Utilities.clamp(hsl[2] - .08f, .5f, .2f); + } + subscribersBackgroundPaint.setColor(ColorUtils.HSLToColor(hsl)); + } catch (Exception e) { + FileLog.e(e); + } + subscribersColorSetFromThumb = true; + } + if (subscribersBackgroundPaintShader != null) { + subscribersBackgroundPaintMatrix.reset(); + subscribersBackgroundPaintMatrix.postScale(avatarSize() / (float) subscribersBackgroundPaintBitmapWidth, avatarSize() / (float) subscribersBackgroundPaintBitmapHeight); + subscribersBackgroundPaintMatrix.postTranslate(width / 2f - avatarSize() / 2f, AndroidUtilities.rectTmp.bottom - avatarSize()); + subscribersBackgroundPaintShader.setLocalMatrix(subscribersBackgroundPaintMatrix); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundDimPaint); + } else { + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundPaint); + } + + AndroidUtilities.rectTmp.inset(-dp(1) / 2f, -dp(1) / 2f); + subscribersStrokePaint.setStrokeWidth(dp(1)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersStrokePaint); + } + + canvas.restore(); + } + + public static void fillPath(Path path, int width, float x) { + path.addCircle(x + width / 2f, dp(10) + avatarSize() / 2f, avatarSize() / 2f, Path.Direction.CW); + + final float nameWidth = width * .4f; + AndroidUtilities.rectTmp.set(x + (width - nameWidth) / 2f, dp(74 - 5), x + (width + nameWidth) / 2f, dp(74 + 5)); + path.addRoundRect(AndroidUtilities.rectTmp, dp(3), dp(3), Path.Direction.CW); + + final float subWidth = width * .35f; + AndroidUtilities.rectTmp.set(x + (width - subWidth) / 2f, dp(87 - 4), x + (width + subWidth) / 2f, dp(87 + 4)); + path.addRoundRect(AndroidUtilities.rectTmp, dp(2.5f), dp(2.5f), Path.Direction.CW); + } + + public void attach() { + for (int i = 0; i < avatarImageReceiver.length; ++i) { + avatarImageReceiver[i].onAttachedToWindow(); + } + } + + public void detach() { + for (int i = 0; i < avatarImageReceiver.length; ++i) { + avatarImageReceiver[i].onDetachedFromWindow(); + } + } + } + + private boolean maybeScrolling; + private boolean scrolling; + private float lx, ly; + private VelocityTracker velocityTracker; + private final Scroller scroller; + + private ChannelBlock longPressedBlock; + private Runnable longPressRunnable; + + public boolean checkTouchEvent(MotionEvent ev) { + if (msg == null || cell == null) return false; + + final int a = ev.getAction(); + ChannelBlock block = null; + float x = backgroundBounds.left + dp(7) - scrollX; + for (int i = 0; i < channels.size(); ++i) { + ChannelBlock b = channels.get(i); + if (ev.getX() >= x && ev.getX() <= x + blockWidth && ev.getY() >= backgroundBounds.bottom - ChannelBlock.height() && ev.getY() < backgroundBounds.bottom) { + block = b; + break; + } + x += blockWidth + dp(9); + } + + final boolean clickClose = closeBounds.contains(ev.getX(), ev.getY()); + + if (a == MotionEvent.ACTION_DOWN) { + scroller.abortAnimation(); + maybeScrolling = !loading && backgroundBounds.contains(lx = ev.getX(), ly = ev.getY()); + if (maybeScrolling && cell.getParent() != null) { + cell.getParent().requestDisallowInterceptTouchEvent(true); + } + scrolling = false; + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + velocityTracker = VelocityTracker.obtain(); + if (block != null) { + block.bounce.setPressed(true); + } + if (clickClose) { + closeBounce.setPressed(true); + } + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + final ChannelBlock finalBlock = block; + longPressedBlock = block; + if (longPressedBlock != null) { + AndroidUtilities.runOnUIThread(longPressRunnable = () -> { + if (finalBlock == longPressedBlock) { + longPressedBlock.bounce.setPressed(false); + if (longPressedBlock.isLock) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressMoreChannelRecommendations(cell); + } + } else { + didClickChannel(longPressedBlock.chat, true); + } + } + longPressedBlock = null; + longPressRunnable = null; + scrolling = false; + maybeScrolling = false; + closeBounce.setPressed(false); + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + }, ViewConfiguration.getLongPressTimeout()); + } + return maybeScrolling; + } else if (a == MotionEvent.ACTION_MOVE) { + if (velocityTracker != null) { + velocityTracker.addMovement(ev); + } + if (maybeScrolling && Math.abs(ev.getX() - lx) >= AndroidUtilities.touchSlop || scrolling) { + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + scrolling = true; + scroll(lx - ev.getX()); + lx = ev.getX(); + unselectBlocks(); + return true; + } + } else if (a == MotionEvent.ACTION_UP || a == MotionEvent.ACTION_CANCEL) { + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + + if (velocityTracker != null) { + velocityTracker.addMovement(ev); + } + final boolean wasScrolling = scrolling; + scrolling = false; + if (a == MotionEvent.ACTION_UP) { + if (!wasScrolling && block != null && block.bounce.isPressed()) { + if (block.isLock) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressMoreChannelRecommendations(cell); + } + } else { + didClickChannel(block.chat, false); + } + } else if (wasScrolling && velocityTracker != null) { + velocityTracker.computeCurrentVelocity(500); + int velocity = (int) -velocityTracker.getXVelocity(); + scroller.fling((int) scrollX, 0, velocity, 0, -Integer.MAX_VALUE, Integer.MAX_VALUE, 0, 0); + } else if (closeBounce.isPressed()) { + didClickClose(); + } + } + + closeBounce.setPressed(false); + + maybeScrolling = false; + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + unselectBlocks(); + return wasScrolling; + } + return false; + } + + public void didClickClose() { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressChannelRecommendationsClose(cell); + } + } + + public void didClickChannel(TLRPC.Chat chat, boolean longPress) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressChannelRecommendation(cell, chat, longPress); + } + } + + private void unselectBlocks() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).bounce.setPressed(false); + } + } + + public void computeScroll() { + if (scroller.computeScrollOffset()) { + scrollX = scroller.getCurrX(); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + cell.invalidateOutbounds(); + } + } + + private void scroll(float dx) { + scrollX = Utilities.clamp(scrollX + dx, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + cell.invalidateOutbounds(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 13d8d5e050..c442f3ee52 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; @@ -23,6 +25,7 @@ import android.os.Build; import android.text.Layout; import android.text.Spannable; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; @@ -39,12 +42,15 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.DownloadController; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; @@ -86,6 +92,8 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.PhotoViewer; import org.telegram.ui.Stories.StoriesUtilities; +import org.telegram.ui.Stories.UploadingDotsSpannable; +import org.telegram.ui.Stories.recorder.HintView2; import tw.nekomimi.nekogram.NekoConfig; import xyz.nextalone.nagram.NaConfig; @@ -161,6 +169,9 @@ public interface ChatActionCellDelegate { default void didClickImage(ChatActionCell cell) { } + default void didClickButton(ChatActionCell cell) { + } + default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, boolean animateConfetti) { } @@ -236,6 +247,7 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { TextPaint textPaint; private float viewTop; + private float viewTranslationX; private int backgroundHeight; private boolean visiblePartSet; @@ -270,8 +282,10 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { private int stickerSize; private int giftRectSize; private StaticLayout giftPremiumTitleLayout; + private int giftPremiumSubtitleWidth; private StaticLayout giftPremiumSubtitleLayout; private StaticLayout giftPremiumButtonLayout; + private boolean buttonClickableAsImage = true; TextPaint settingWallpaperPaint; private StaticLayout settingWallpaperLayout; private float settingWallpaperProgress; @@ -346,7 +360,7 @@ public ChatActionCell(Context context, boolean canDrawInParent, Theme.ResourcesP giftSubtitlePaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics())); rippleView = new View(context); - rippleView.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Color.WHITE, .07f), Theme.RIPPLE_MASK_ROUNDRECT_6DP, AndroidUtilities.dp(16))); + rippleView.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Color.BLACK, .1f), Theme.RIPPLE_MASK_ROUNDRECT_6DP, dp(16))); rippleView.setVisibility(GONE); addView(rippleView); @@ -426,7 +440,7 @@ public void setMessageObject(MessageObject messageObject) { } public void setMessageObject(MessageObject messageObject, boolean force) { - if (currentMessageObject == messageObject && (textLayout == null || TextUtils.equals(textLayout.getText(), messageObject.messageText)) && (hasReplyMessage || messageObject.replyMessageObject == null) && !force && messageObject.type != MessageObject.TYPE_SUGGEST_PHOTO) { + if (currentMessageObject == messageObject && (textLayout == null || TextUtils.equals(textLayout.getText(), messageObject.messageText)) && (hasReplyMessage || messageObject.replyMessageObject == null) && !force && messageObject.type != MessageObject.TYPE_SUGGEST_PHOTO && !messageObject.forceUpdate) { return; } if (BuildVars.DEBUG_PRIVATE_VERSION && Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { @@ -435,6 +449,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { accessibilityText = null; boolean messageIdChanged = currentMessageObject == null || currentMessageObject.stableId != messageObject.stableId; currentMessageObject = messageObject; + messageObject.forceUpdate = false; hasReplyMessage = messageObject.replyMessageObject != null; DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); previousWidth = 0; @@ -442,7 +457,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { imageReceiver.clearDecorators(); if (messageObject.isStoryMention()) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.media.user_id); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); TL_stories.StoryItem storyItem = messageObject.messageOwner.media.storyItem; if (storyItem != null && storyItem.noforwards) { imageReceiver.setForUserOrChat(user, avatarDrawable, null, true, 0, true); @@ -524,7 +539,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { forceWasUnread = messageObject.wasUnread; imageReceiver.setAllowStartLottieAnimation(false); imageReceiver.setDelegate(giftStickerDelegate); - imageReceiver.setImageBitmap(new RLottieDrawable(R.raw.premium_gift, messageObject.getId() + "_" + R.raw.premium_gift, AndroidUtilities.dp(160), AndroidUtilities.dp(160))); + imageReceiver.setImageBitmap(new RLottieDrawable(R.raw.premium_gift, messageObject.getId() + "_" + R.raw.premium_gift, dp(160), dp(160))); } else { TLRPC.TL_messages_stickerSet set; TLRPC.Document document = null; @@ -675,6 +690,20 @@ public void setVisiblePart(float visibleTop, int parentH) { visiblePartSet = true; backgroundHeight = parentH; viewTop = visibleTop; + viewTranslationX = 0; + } + + private float dimAmount; + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public void setVisiblePart(float visibleTop, float tx, int parentH, float dimAmount) { + visiblePartSet = true; + backgroundHeight = parentH; + viewTop = visibleTop; + viewTranslationX = tx; + + this.dimAmount = dimAmount; + dimPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (0xFF * dimAmount))); + invalidate(); } @Override @@ -755,7 +784,7 @@ public boolean onTouchEvent(MotionEvent event) { imagePressed = true; result = true; } - if (isButtonLayout(messageObject) && (giftButtonRect.contains(x, y) || backgroundRect.contains(x, y))) { + if (isButtonLayout(messageObject) && giftPremiumButtonLayout != null && (giftButtonRect.contains(x, y) || buttonClickableAsImage && backgroundRect.contains(x, y))) { rippleView.setPressed(giftButtonPressed = true); bounce.setPressed(true); result = true; @@ -783,7 +812,11 @@ public boolean onTouchEvent(MotionEvent event) { } else { ImageUpdater imageUpdater = MessagesController.getInstance(currentAccount).photoSuggestion.get(messageObject.messageOwner.local_id); if (imageUpdater == null) { - delegate.didClickImage(this); + if (buttonClickableAsImage) { + delegate.didClickImage(this); + } else { + delegate.didClickButton(this); + } } } } @@ -949,7 +982,7 @@ private void openLink(CharacterStyle link) { } private void createLayout(CharSequence text, int width) { - int maxWidth = width - AndroidUtilities.dp(30); + int maxWidth = width - dp(30); if (maxWidth < 0) { return; } @@ -987,7 +1020,7 @@ private void createLayout(CharSequence text, int width) { FileLog.e(e); } textX = (width - textWidth) / 2; - textY = AndroidUtilities.dp(7); + textY = dp(7); textXLeft = (width - textLayout.getWidth()) / 2; spoilersPool.addAll(spoilers); @@ -1002,22 +1035,22 @@ private void createLayout(CharSequence text, int width) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MessageObject messageObject = currentMessageObject; if (messageObject == null && customText == null) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + dp(14)); return; } if (isButtonLayout(messageObject)) { - giftRectSize = Math.min((int) (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() * 0.6f : AndroidUtilities.displaySize.x * 0.62f - AndroidUtilities.dp(34)), AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(64)); + giftRectSize = Math.min((int) (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() * 0.6f : AndroidUtilities.displaySize.x * 0.62f - dp(34)), AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight - dp(64)); if (!AndroidUtilities.isTablet() && messageObject.type == MessageObject.TYPE_GIFT_PREMIUM) { giftRectSize = (int) (giftRectSize * 1.2f); } - stickerSize = giftRectSize - AndroidUtilities.dp(106); + stickerSize = giftRectSize - dp(106); if (isNewStyleButtonLayout()) { imageReceiver.setRoundRadius(stickerSize / 2); } else { imageReceiver.setRoundRadius(0); } } - int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec)); + int width = Math.max(dp(30), MeasureSpec.getSize(widthMeasureSpec)); if (previousWidth != width) { wasLayout = true; previousWidth = width; @@ -1026,9 +1059,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int additionalHeight = 0; if (messageObject != null) { if (messageObject.type == MessageObject.TYPE_ACTION_PHOTO) { - additionalHeight = AndroidUtilities.roundMessageSize + AndroidUtilities.dp(10); + additionalHeight = AndroidUtilities.roundMessageSize + dp(10); } else if (isButtonLayout(messageObject)) { - additionalHeight = giftRectSize + AndroidUtilities.dp(12); + additionalHeight = giftRectSize + dp(12); } } @@ -1038,36 +1071,36 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int imageSize = getImageSize(messageObject); float y; if (isNewStyleButtonLayout()) { - y = textY + textHeight + AndroidUtilities.dp(4) + AndroidUtilities.dp(16) * 2 + imageSize + giftPremiumSubtitleLayout.getHeight() + AndroidUtilities.dp(4); + y = textY + textHeight + dp(4) + dp(16) * 2 + imageSize + giftPremiumSubtitleLayout.getHeight() + dp(4); } else { - y = textY + textHeight + giftRectSize * 0.075f + imageSize + AndroidUtilities.dp(4) + AndroidUtilities.dp(4) + giftPremiumSubtitleLayout.getHeight(); + y = textY + textHeight + giftRectSize * 0.075f + imageSize + dp(4) + dp(4) + giftPremiumSubtitleLayout.getHeight(); } giftPremiumAdditionalHeight = 0; if (giftPremiumTitleLayout != null) { y += giftPremiumTitleLayout.getHeight(); - y += AndroidUtilities.dp(isGiftChannel ? 6 : 0); + y += dp(isGiftChannel ? 6 : 0); } else { - y -= AndroidUtilities.dp(12); - giftPremiumAdditionalHeight -= AndroidUtilities.dp(30); + y -= dp(12); + giftPremiumAdditionalHeight -= dp(30); } if (giftPremiumSubtitleLayout.getLineCount() > 2) { giftPremiumAdditionalHeight += (giftPremiumSubtitleLayout.getLineBottom(0) - giftPremiumSubtitleLayout.getLineTop(0)) * giftPremiumSubtitleLayout.getLineCount() - 2; } - giftPremiumAdditionalHeight -= AndroidUtilities.dp(isGiftChannel ? 14 : 0); + giftPremiumAdditionalHeight -= dp(isGiftChannel ? 14 : 0); additionalHeight += giftPremiumAdditionalHeight; - int h = textHeight + additionalHeight + AndroidUtilities.dp(14); + int h = textHeight + additionalHeight + dp(14); if (giftPremiumButtonLayout != null) { - y += (h - y - (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) - AndroidUtilities.dp(8)) / 2f; + y += (h - y - (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) - dp(8)) / 2f; float rectX = (previousWidth - giftPremiumButtonWidth) / 2f; - giftButtonRect.set(rectX - AndroidUtilities.dp(18), y - AndroidUtilities.dp(8), rectX + giftPremiumButtonWidth + AndroidUtilities.dp(18), y + (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) + AndroidUtilities.dp(8)); + giftButtonRect.set(rectX - dp(18), y - dp(8), rectX + giftPremiumButtonWidth + dp(18), y + (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) + dp(8)); } else { - additionalHeight -= AndroidUtilities.dp(40); - giftPremiumAdditionalHeight -= AndroidUtilities.dp(40); + additionalHeight -= dp(40); + giftPremiumAdditionalHeight -= dp(40); } int sizeInternal = getMeasuredWidth() << 16 + getMeasuredHeight(); starParticlesDrawable.rect.set(giftButtonRect); @@ -1078,25 +1111,25 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } if (isNewStyleButtonLayout()) { - exactlyHeight = textY + textHeight + AndroidUtilities.dp(4); + exactlyHeight = textY + textHeight + dp(4); backgroundRectHeight = 0; - backgroundRectHeight += AndroidUtilities.dp(16) * 2 + imageSize; + backgroundRectHeight += dp(16) * 2 + imageSize; backgroundRectHeight += giftPremiumSubtitleLayout.getHeight(); if (giftPremiumButtonLayout != null) { - backgroundButtonTop = exactlyHeight + backgroundRectHeight + AndroidUtilities.dp(10); + backgroundButtonTop = exactlyHeight + backgroundRectHeight + dp(10); float rectX = (previousWidth - giftPremiumButtonWidth) / 2f; - giftButtonRect.set(rectX - AndroidUtilities.dp(18), backgroundButtonTop, rectX + giftPremiumButtonWidth + AndroidUtilities.dp(18), backgroundButtonTop + giftPremiumButtonLayout.getHeight() + AndroidUtilities.dp(8) * 2); - backgroundRectHeight += AndroidUtilities.dp(10) + giftButtonRect.height(); + giftButtonRect.set(rectX - dp(18), backgroundButtonTop, rectX + giftPremiumButtonWidth + dp(18), backgroundButtonTop + giftPremiumButtonLayout.getHeight() + dp(8) * 2); + backgroundRectHeight += dp(10) + giftButtonRect.height(); } - backgroundRectHeight += AndroidUtilities.dp(16); + backgroundRectHeight += dp(16); exactlyHeight += backgroundRectHeight; - exactlyHeight += AndroidUtilities.dp(6); + exactlyHeight += dp(6); } } if (messageObject != null && (isNewStyleButtonLayout())) { setMeasuredDimension(width, exactlyHeight); } else { - setMeasuredDimension(width, textHeight + additionalHeight + AndroidUtilities.dp(14)); + setMeasuredDimension(width, textHeight + additionalHeight + dp(14)); } } @@ -1107,7 +1140,7 @@ private boolean isNewStyleButtonLayout() { private int getImageSize(MessageObject messageObject) { int imageSize = stickerSize; if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO || isNewStyleButtonLayout()) { - imageSize = AndroidUtilities.dp(78);//Math.max(, (int) (stickerSize * 0.7f)); + imageSize = dp(78);//Math.max(, (int) (stickerSize * 0.7f)); } return imageSize; } @@ -1130,9 +1163,9 @@ private void buildLayout() { if (text == null) { if (messageObject.messageOwner != null && messageObject.messageOwner.media != null && messageObject.messageOwner.media.ttl_seconds != 0) { if (messageObject.messageOwner.media.photo != null) { - text = LocaleController.getString("AttachPhotoExpired", R.string.AttachPhotoExpired); + text = LocaleController.getString(R.string.AttachPhotoExpired); } else if (messageObject.messageOwner.media.document instanceof TLRPC.TL_documentEmpty || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && messageObject.messageOwner.media.document == null) { - text = LocaleController.getString("AttachVideoExpired", R.string.AttachVideoExpired); + text = LocaleController.getString(R.string.AttachVideoExpired); } else { text = AnimatedEmojiSpan.cloneSpans(messageObject.messageText); } @@ -1159,11 +1192,11 @@ private void buildLayout() { createLayout(text, previousWidth); if (messageObject != null) { if (messageObject.type == MessageObject.TYPE_ACTION_PHOTO) { - imageReceiver.setImageCoords((previousWidth - AndroidUtilities.roundMessageSize) / 2f, textHeight + AndroidUtilities.dp(19), AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize); + imageReceiver.setImageCoords((previousWidth - AndroidUtilities.roundMessageSize) / 2f, textHeight + dp(19), AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL) { createGiftPremiumChannelLayouts(); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM) { - createGiftPremiumLayouts(LocaleController.getString(R.string.ActionGiftPremiumTitle), LocaleController.formatString(R.string.ActionGiftPremiumSubtitle, LocaleController.formatPluralString("Months", messageObject.messageOwner.action.months)), LocaleController.getString(R.string.ActionGiftPremiumView), giftRectSize); + createGiftPremiumLayouts(LocaleController.getString(R.string.ActionGiftPremiumTitle), LocaleController.formatString(R.string.ActionGiftPremiumSubtitle, LocaleController.formatPluralString("Months", messageObject.messageOwner.action.months)), LocaleController.getString(R.string.ActionGiftPremiumView), giftRectSize, true); } else if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { TLRPC.TL_messageActionSuggestProfilePhoto actionSuggestProfilePhoto = (TLRPC.TL_messageActionSuggestProfilePhoto) messageObject.messageOwner.action; String description; @@ -1172,24 +1205,24 @@ private void buildLayout() { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(messageObject.getDialogId()); if (isVideo) { - description = LocaleController.formatString("ActionSuggestVideoFromYouDescription", R.string.ActionSuggestVideoFromYouDescription, user2.first_name); + description = LocaleController.formatString(R.string.ActionSuggestVideoFromYouDescription, user2.first_name); } else { - description = LocaleController.formatString("ActionSuggestPhotoFromYouDescription", R.string.ActionSuggestPhotoFromYouDescription, user2.first_name); + description = LocaleController.formatString(R.string.ActionSuggestPhotoFromYouDescription, user2.first_name); } } else { if (isVideo) { - description = LocaleController.formatString("ActionSuggestVideoToYouDescription", R.string.ActionSuggestVideoToYouDescription, user.first_name); + description = LocaleController.formatString(R.string.ActionSuggestVideoToYouDescription, user.first_name); } else { - description = LocaleController.formatString("ActionSuggestPhotoToYouDescription", R.string.ActionSuggestPhotoToYouDescription, user.first_name); + description = LocaleController.formatString(R.string.ActionSuggestPhotoToYouDescription, user.first_name); } } String action; if (actionSuggestProfilePhoto.video || (actionSuggestProfilePhoto.photo.video_sizes != null && !actionSuggestProfilePhoto.photo.video_sizes.isEmpty())) { - action = LocaleController.getString("ViewVideoAction", R.string.ViewVideoAction); + action = LocaleController.getString(R.string.ViewVideoAction); } else { - action = LocaleController.getString("ViewPhotoAction", R.string.ViewPhotoAction); + action = LocaleController.getString(R.string.ViewPhotoAction); } - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, true); textLayout = null; textHeight = 0; textY = 0; @@ -1197,13 +1230,18 @@ private void buildLayout() { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.isOutOwner() ? 0 : messageObject.getDialogId()); CharSequence description; String action = null; - if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { + boolean actionClickableAsImage = true; + if (!messageObject.isOutOwner() && messageObject.isWallpaperForBoth() && messageObject.isCurrentWallpaper()) { + description = messageObject.messageText; + action = LocaleController.getString(R.string.RemoveWallpaperAction); + actionClickableAsImage = false; + } else if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { description = messageObject.messageText; } else { description = messageObject.messageText; - action = LocaleController.getString("ViewWallpaperAction", R.string.ViewWallpaperAction); + action = LocaleController.getString(R.string.ViewWallpaperAction); } - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, actionClickableAsImage); textLayout = null; textHeight = 0; textY = 0; @@ -1218,9 +1256,9 @@ private void buildLayout() { } else { description = AndroidUtilities.replaceTags(LocaleController.formatString("StoryMentionedTitle", R.string.StoryMentionedTitle, user.first_name)); } - action = LocaleController.getString("StoryMentionedAction", R.string.StoryMentionedAction); + action = LocaleController.getString(R.string.StoryMentionedAction); - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, true); textLayout = null; textHeight = 0; textY = 0; @@ -1230,9 +1268,9 @@ private void buildLayout() { private void createGiftPremiumChannelLayouts() { int width = giftRectSize; - width -= AndroidUtilities.dp(16); - giftTitlePaint.setTextSize(AndroidUtilities.dp(14)); - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(13)); + width -= dp(16); + giftTitlePaint.setTextSize(dp(14)); + giftSubtitlePaint.setTextSize(dp(13)); TLRPC.TL_messageActionGiftCode gifCodeAction = (TLRPC.TL_messageActionGiftCode) currentMessageObject.messageOwner.action; int months = gifCodeAction.months; TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(gifCodeAction.boost_peer)); @@ -1265,18 +1303,20 @@ private void createGiftPremiumChannelLayouts() { titleBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, titleBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumTitleLayout = new StaticLayout(titleBuilder, giftTitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.1f, 0.0f, false); + giftPremiumSubtitleWidth = width; giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.1f, 0.0f, false); SpannableStringBuilder buttonBuilder = SpannableStringBuilder.valueOf(btnText); buttonBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, buttonBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumButtonLayout = new StaticLayout(buttonBuilder, (TextPaint) getThemedPaint(Theme.key_paint_chatActionText), width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + buttonClickableAsImage = true; giftPremiumButtonWidth = measureLayoutWidth(giftPremiumButtonLayout); } - private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, CharSequence button, int width) { - width -= AndroidUtilities.dp(16); + private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, CharSequence button, int width, boolean buttonClickableAsImage) { + width -= dp(16); if (title != null) { - giftTitlePaint.setTextSize(AndroidUtilities.dp(16)); + giftTitlePaint.setTextSize(dp(16)); SpannableStringBuilder titleBuilder = SpannableStringBuilder.valueOf(title); titleBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, titleBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumTitleLayout = new StaticLayout(titleBuilder, giftTitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); @@ -1284,18 +1324,30 @@ private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, giftPremiumTitleLayout = null; } if (currentMessageObject != null && isNewStyleButtonLayout()) { - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(13)); + giftSubtitlePaint.setTextSize(dp(13)); } else { - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(15)); + giftSubtitlePaint.setTextSize(dp(15)); + } + int subtitleWidth = giftPremiumSubtitleWidth = width; + if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { + final int recommendedWidthForTwoLines = HintView2.cutInFancyHalf(subtitle, giftSubtitlePaint); + if (recommendedWidthForTwoLines < subtitleWidth && recommendedWidthForTwoLines > subtitleWidth / 5f) { + subtitleWidth = recommendedWidthForTwoLines; + } } - giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + try { + subtitle = Emoji.replaceEmoji(subtitle, giftSubtitlePaint.getFontMetricsInt(), false); + } catch (Exception ignore) {} + giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, subtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, dp(1.66f), false); if (button != null) { SpannableStringBuilder buttonBuilder = SpannableStringBuilder.valueOf(button); buttonBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, buttonBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumButtonLayout = new StaticLayout(buttonBuilder, (TextPaint) getThemedPaint(Theme.key_paint_chatActionText), width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + this.buttonClickableAsImage = buttonClickableAsImage; giftPremiumButtonWidth = measureLayoutWidth(giftPremiumButtonLayout); } else { giftPremiumButtonLayout = null; + this.buttonClickableAsImage = false; giftPremiumButtonWidth = 0; } } @@ -1311,6 +1363,10 @@ private float measureLayoutWidth(Layout layout) { return maxWidth; } + public boolean showingCancelButton() { + return radialProgress != null && radialProgress.getIcon() == MediaActionDrawable.ICON_CANCEL; + } + public int getCustomDate() { return customDate; } @@ -1320,10 +1376,10 @@ protected void onDraw(Canvas canvas) { MessageObject messageObject = currentMessageObject; int imageSize = stickerSize; if (isButtonLayout(messageObject)) { - stickerSize = giftRectSize - AndroidUtilities.dp(106); + stickerSize = giftRectSize - dp(106); if (isNewStyleButtonLayout()) { imageSize = getImageSize(messageObject); - int top = textY + textHeight + AndroidUtilities.dp(4) + AndroidUtilities.dp(16); + int top = textY + textHeight + dp(4) + dp(16); float x = (previousWidth - imageSize) / 2f; float y = top; if (messageObject.isStoryMention()) { @@ -1335,10 +1391,10 @@ protected void onDraw(Canvas canvas) { imageReceiver.setImageCoords((previousWidth - stickerSize) / 2f, textY + textHeight + giftRectSize * 0.075f, stickerSize, stickerSize); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL) { imageSize = (int) (stickerSize * (AndroidUtilities.isTablet() ? 1.0f : 1.2f)); - imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - AndroidUtilities.dp(22), imageSize, imageSize); + imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - dp(22), imageSize, imageSize); } else { imageSize = (int) (stickerSize * 1f); - imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - AndroidUtilities.dp(4), imageSize, imageSize); + imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - dp(4), imageSize, imageSize); } textPaint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); if (textPaint != null) { @@ -1373,7 +1429,7 @@ protected void onDraw(Canvas canvas) { if (imageUpdater != null) { radialProgress.setProgress(imageUpdater.getCurrentImageProgress(), true); radialProgress.setCircleRadius((int) (imageReceiver.getImageWidth() * 0.5f) + 1); - radialProgress.setMaxIconSize(AndroidUtilities.dp(24)); + radialProgress.setMaxIconSize(dp(24)); radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); if (imageUpdater.getCurrentImageProgress() == 1f) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, true, true); @@ -1385,8 +1441,8 @@ protected void onDraw(Canvas canvas) { } else if (messageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { float progress = getUploadingInfoProgress(messageObject); radialProgress.setProgress(progress, true); - radialProgress.setCircleRadius(AndroidUtilities.dp(26)); - radialProgress.setMaxIconSize(AndroidUtilities.dp(24)); + radialProgress.setCircleRadius(dp(26)); + radialProgress.setMaxIconSize(dp(24)); radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); if (progress == 1f) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, true, true); @@ -1421,18 +1477,18 @@ protected void onDraw(Canvas canvas) { if (isButtonLayout(messageObject)) { canvas.save(); - float x = (previousWidth - giftRectSize) / 2f + AndroidUtilities.dp(8); + float x = (previousWidth - giftRectSize) / 2f + dp(8); float y; if (isNewStyleButtonLayout()) { - float top = backgroundRect != null ? backgroundRect.top : (textY + textHeight + AndroidUtilities.dp(4)); - y = top + AndroidUtilities.dp(16) * 2 + imageSize; + float top = backgroundRect != null ? backgroundRect.top : (textY + textHeight + dp(4)); + y = top + dp(16) * 2 + imageSize; } else { - y = textY + textHeight + giftRectSize * 0.075f + (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO ? imageSize : stickerSize) + AndroidUtilities.dp(4); + y = textY + textHeight + giftRectSize * 0.075f + (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO ? imageSize : stickerSize) + dp(4); if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { - y += AndroidUtilities.dp(16); + y += dp(16); } if (giftPremiumButtonLayout == null) { - y -= AndroidUtilities.dp(24); + y -= dp(24); } } @@ -1440,26 +1496,40 @@ protected void onDraw(Canvas canvas) { if (giftPremiumTitleLayout != null) { giftPremiumTitleLayout.draw(canvas); y += giftPremiumTitleLayout.getHeight(); - y += AndroidUtilities.dp(messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL ? 6 : 0); + y += dp(messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL ? 6 : 0); } else { - y -= AndroidUtilities.dp(4); + y -= dp(4); } canvas.restore(); - y += AndroidUtilities.dp(4); + y += dp(4); canvas.save(); canvas.translate(x, y); if (messageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { if (radialProgress.getTransitionProgress() != 1f || radialProgress.getIcon() != MediaActionDrawable.ICON_NONE) { if (settingWallpaperLayout == null) { settingWallpaperPaint = new TextPaint(); - settingWallpaperPaint.setTextSize(AndroidUtilities.dp(13)); - settingWallpaperLayout = new StaticLayout("Setting new wallpaper...", settingWallpaperPaint, giftPremiumSubtitleLayout.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + settingWallpaperPaint.setTextSize(dp(13)); + SpannableStringBuilder cs = new SpannableStringBuilder(LocaleController.getString(R.string.ActionSettingWallpaper)); + int index = cs.toString().indexOf("..."), len = 3; + if (index < 0) { + index = cs.toString().indexOf("…"); + len = 1; + } + if (index >= 0) { + SpannableString loading = new SpannableString("…"); + UploadingDotsSpannable loadingDots = new UploadingDotsSpannable(); + loadingDots.fixTop = true; + loadingDots.setParent(ChatActionCell.this, false); + loading.setSpan(loadingDots, 0, loading.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + cs.replace(index, index + len, loading); + } + settingWallpaperLayout = new StaticLayout(cs, settingWallpaperPaint, giftPremiumSubtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } float progressLocal = getUploadingInfoProgress(messageObject); if (settingWallpaperProgressTextLayout == null || settingWallpaperProgress != progressLocal) { settingWallpaperProgress = progressLocal; - settingWallpaperProgressTextLayout = new StaticLayout((int) (progressLocal * 100) + "%", giftSubtitlePaint, giftPremiumSubtitleLayout.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + settingWallpaperProgressTextLayout = new StaticLayout((int) (progressLocal * 100) + "%", giftSubtitlePaint, giftPremiumSubtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } settingWallpaperPaint.setColor(giftSubtitlePaint.getColor()); @@ -1471,7 +1541,8 @@ protected void onDraw(Canvas canvas) { float s = 0.8f + 0.2f * p; canvas.save(); - canvas.scale(s, s, giftPremiumSubtitleLayout.getWidth() / 2f, giftPremiumSubtitleLayout.getHeight() / 2f); + canvas.scale(s, s, giftPremiumSubtitleWidth / 2f, giftPremiumSubtitleLayout.getHeight() / 2f); + canvas.translate((giftPremiumSubtitleWidth -giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); canvas.restore(); @@ -1483,7 +1554,7 @@ protected void onDraw(Canvas canvas) { canvas.restore(); canvas.save(); - canvas.translate(0, settingWallpaperLayout.getHeight() + AndroidUtilities.dp(4)); + canvas.translate(0, settingWallpaperLayout.getHeight() + dp(4)); canvas.scale(s, s, settingWallpaperProgressTextLayout.getWidth() / 2f, settingWallpaperProgressTextLayout.getHeight() / 2f); settingWallpaperProgressTextLayout.draw(canvas); canvas.restore(); @@ -1493,30 +1564,36 @@ protected void onDraw(Canvas canvas) { } else { settingWallpaperLayout.draw(canvas); canvas.save(); - canvas.translate(0, settingWallpaperLayout.getHeight() + AndroidUtilities.dp(4)); + canvas.translate(0, settingWallpaperLayout.getHeight() + dp(4)); settingWallpaperProgressTextLayout.draw(canvas); canvas.restore(); } } else { + canvas.save(); + canvas.translate((giftPremiumSubtitleWidth - giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); + canvas.restore(); } } else if (giftPremiumSubtitleLayout != null) { + canvas.save(); + canvas.translate((giftPremiumSubtitleWidth - giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); + canvas.restore(); } canvas.restore(); if (giftPremiumTitleLayout == null) { - y -= AndroidUtilities.dp(8); + y -= dp(8); } y += giftPremiumSubtitleLayout.getHeight(); int buttonH = giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0; - y += (getHeight() - y - buttonH - AndroidUtilities.dp(8)) / 2f; + y += (getHeight() - y - buttonH - dp(8)) / 2f; if (themeDelegate != null) { - themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } else { - Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } final float S = bounce.getScale(0.02f); @@ -1524,16 +1601,18 @@ protected void onDraw(Canvas canvas) { canvas.scale(S, S, giftButtonRect.centerX(), giftButtonRect.centerY()); if (giftPremiumButtonLayout != null) { - Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); - canvas.drawRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), backgroundPaint); - + Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundSelected); + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), backgroundPaint); if (hasGradientService()) { - canvas.drawRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + if (dimAmount > 0) { + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), dimPaint); } if (getMessageObject().type != MessageObject.TYPE_SUGGEST_PHOTO && getMessageObject().type != MessageObject.TYPE_ACTION_WALLPAPER && getMessageObject().type != MessageObject.TYPE_STORY_MENTION) { starsPath.rewind(); - starsPath.addRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Path.Direction.CW); + starsPath.addRoundRect(giftButtonRect, dp(16), dp(16), Path.Direction.CW); canvas.save(); canvas.clipPath(starsPath); @@ -1558,7 +1637,7 @@ protected void onDraw(Canvas canvas) { if (progressView == null) { progressView = new RadialProgressView(getContext()); } - int rad = AndroidUtilities.dp(16); + int rad = dp(16); canvas.save(); canvas.scale(progressToProgress, progressToProgress, giftButtonRect.centerX(), giftButtonRect.centerY()); progressView.setSize(rad); @@ -1570,7 +1649,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); float s = 1f - progressToProgress; canvas.scale(s, s, giftButtonRect.centerX(), giftButtonRect.centerY()); - canvas.translate(x, giftButtonRect.top + AndroidUtilities.dp(8)); + canvas.translate(x, giftButtonRect.top + dp(8)); giftPremiumButtonLayout.draw(canvas); canvas.restore(); } @@ -1586,7 +1665,7 @@ protected void onDraw(Canvas canvas) { Theme.multAlpha(Color.WHITE, .2f), Theme.multAlpha(Color.WHITE, .7f) ); - loadingDrawable.strokePaint.setStrokeWidth(AndroidUtilities.dp(1)); + loadingDrawable.strokePaint.setStrokeWidth(dp(1)); } loadingDrawable.resetDisappear(); loadingDrawable.setBounds(giftButtonRect); @@ -1606,6 +1685,19 @@ protected void onDraw(Canvas canvas) { } } + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == rippleView) { + final float S = bounce.getScale(0.02f); + canvas.save(); + canvas.scale(S, S, child.getX() + child.getMeasuredWidth() / 2f, child.getY() + child.getMeasuredHeight() / 2f); + final boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } + return super.drawChild(canvas, child, drawingTime); + } + public void drawBackground(Canvas canvas, boolean fromParent) { if (canDrawInParent) { if (hasGradientService() && !fromParent) { @@ -1616,6 +1708,7 @@ public void drawBackground(Canvas canvas, boolean fromParent) { } } Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); + Paint darkenBackgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); textPaint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); if (overrideBackground >= 0) { int color = getThemedColor(overrideBackground); @@ -1624,7 +1717,7 @@ public void drawBackground(Canvas canvas, boolean fromParent) { overrideBackgroundPaint.setColor(color); overrideTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); overrideTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); - overrideTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + overrideTextPaint.setTextSize(dp(Math.max(16, SharedConfig.fontSize) - 2)); overrideTextPaint.setColor(getThemedColor(overrideText)); } backgroundPaint = overrideBackgroundPaint; @@ -1634,8 +1727,8 @@ public void drawBackground(Canvas canvas, boolean fromParent) { invalidatePath = false; lineWidths.clear(); final int count = textLayout == null ? 0 : textLayout.getLineCount(); - final int corner = AndroidUtilities.dp(11); - final int cornerIn = AndroidUtilities.dp(8); + final int corner = dp(11); + final int cornerIn = dp(8); int prevLineWidth = 0; for (int a = 0; a < count; a++) { @@ -1659,12 +1752,12 @@ public void drawBackground(Canvas canvas, boolean fromParent) { prevLineWidth = lineWidth; } - int y = AndroidUtilities.dp(4); + int y = dp(4); int x = getMeasuredWidth() / 2; int previousLineBottom = 0; - final int cornerOffset = AndroidUtilities.dp(3); - final int cornerInSmall = AndroidUtilities.dp(6); + final int cornerOffset = dp(3); + final int cornerInSmall = dp(6); final int cornerRest = corner - cornerOffset; lineHeights.clear(); @@ -1678,10 +1771,10 @@ public void drawBackground(Canvas canvas, boolean fromParent) { int height = lineBottom - previousLineBottom; if (a == 0 || lineWidth > prevLineWidth) { - height += AndroidUtilities.dp(3); + height += dp(3); } if (a == count - 1 || lineWidth > nextLineWidth) { - height += AndroidUtilities.dp(3); + height += dp(3); } previousLineBottom = lineBottom; @@ -1705,12 +1798,12 @@ public void drawBackground(Canvas canvas, boolean fromParent) { y += height; int yOffset = y; if (a != count - 1 && lineWidth < nextLineWidth) { - y -= AndroidUtilities.dp(3); - height -= AndroidUtilities.dp(3); + y -= dp(3); + height -= dp(3); } if (a != 0 && lineWidth < prevLineWidth) { - y -= AndroidUtilities.dp(3); - height -= AndroidUtilities.dp(3); + y -= dp(3); + height -= dp(3); } lineHeights.add(height); @@ -1763,22 +1856,35 @@ public void drawBackground(Canvas canvas, boolean fromParent) { backgroundHeight = parent.getMeasuredHeight(); } if (themeDelegate != null) { - themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } else { - Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } int oldAlpha = -1; int oldAlpha2 = -1; - if (fromParent && getAlpha() != 1f) { + if (fromParent && (getAlpha() != 1f || isFloating())) { + oldAlpha = backgroundPaint.getAlpha(); + oldAlpha2 = darkenBackgroundPaint.getAlpha(); + backgroundPaint.setAlpha((int) (oldAlpha * getAlpha() * (isFloating() ? .75f : 1f))); + darkenBackgroundPaint.setAlpha((int) (oldAlpha2 * getAlpha() * (isFloating() ? .75f : 1f))); + } else if (isFloating()) { oldAlpha = backgroundPaint.getAlpha(); - oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - backgroundPaint.setAlpha((int) (oldAlpha * getAlpha())); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * getAlpha())); + oldAlpha2 = darkenBackgroundPaint.getAlpha(); + backgroundPaint.setAlpha((int) (oldAlpha * (isFloating() ? .75f : 1f))); + darkenBackgroundPaint.setAlpha((int) (oldAlpha2 * (isFloating() ? .75f : 1f))); } canvas.drawPath(backgroundPath, backgroundPaint); if (hasGradientService()) { - canvas.drawPath(backgroundPath, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawPath(backgroundPath, darkenBackgroundPaint); + } + if (dimAmount > 0) { + int wasAlpha = dimPaint.getAlpha(); + if (fromParent) { + dimPaint.setAlpha((int) (wasAlpha * getAlpha())); + } + canvas.drawPath(backgroundPath, dimPaint); + dimPaint.setAlpha(wasAlpha); } MessageObject messageObject = currentMessageObject; @@ -1786,26 +1892,26 @@ public void drawBackground(Canvas canvas, boolean fromParent) { float x = (getWidth() - giftRectSize) / 2f; float y = textY + textHeight; if (isNewStyleButtonLayout()) { - y += AndroidUtilities.dp(4); + y += dp(4); AndroidUtilities.rectTmp.set(x, y, x + giftRectSize, y + backgroundRectHeight); } else { - y += AndroidUtilities.dp(12); + y += dp(12); AndroidUtilities.rectTmp.set(x, y, x + giftRectSize, y + giftRectSize + giftPremiumAdditionalHeight); } if (backgroundRect == null) { backgroundRect = new RectF(); } backgroundRect.set(AndroidUtilities.rectTmp); - canvas.drawRoundRect(backgroundRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), backgroundPaint); + canvas.drawRoundRect(backgroundRect, dp(16), dp(16), backgroundPaint); if (hasGradientService()) { - canvas.drawRoundRect(backgroundRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(backgroundRect, dp(16), dp(16), darkenBackgroundPaint); } } if (oldAlpha >= 0) { backgroundPaint.setAlpha(oldAlpha); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + darkenBackgroundPaint.setAlpha(oldAlpha2); } } @@ -1944,6 +2050,10 @@ public void invalidate(int l, int t, int r, int b) { } } + public boolean isFloating() { + return false; + } + private ColorFilter adaptiveEmojiColorFilter; private int adaptiveEmojiColor; private ColorFilter getAdaptiveEmojiColorFilter(int color) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java index 9bca14fc9a..c34e19cd4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java @@ -8,8 +8,13 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; +import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -29,19 +34,58 @@ public ChatLoadingCell(Context context, View parent, Theme.ResourcesProvider res super(context); this.resourcesProvider = resourcesProvider; - frameLayout = new FrameLayout(context); - frameLayout.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(18), frameLayout, parent, getThemedPaint(Theme.key_paint_chatActionBackground))); + frameLayout = new FrameLayout(context) { + private final RectF rect = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + applyServiceShaderMatrix(); + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackground)); + if (hasGradientService()) { + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + + super.dispatchDraw(canvas); + } + }; + frameLayout.setWillNotDraw(false); addView(frameLayout, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); progressBar = new RadialProgressView(context, resourcesProvider); - progressBar.setSize(AndroidUtilities.dp(28)); + progressBar.setSize(dp(28)); progressBar.setProgressColor(getThemedColor(Theme.key_chat_serviceText)); frameLayout.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); } + public boolean hasGradientService() { + return resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService(); + } + + private float viewTop; + private int backgroundHeight; + public void applyServiceShaderMatrix() { + applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop); + } + + private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, float x, float viewTop) { + if (resourcesProvider != null) { + resourcesProvider.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } else { + Theme.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } + } + + public void setVisiblePart(float viewTop, int backgroundHeight) { + if (this.viewTop != viewTop) { + invalidate(); + } + this.viewTop = viewTop; + this.backgroundHeight = backgroundHeight; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(44), MeasureSpec.EXACTLY)); } public void setProgressVisible(boolean value) { 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 5ea7ba3796..11ccd2a029 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -196,7 +196,6 @@ import tw.nekomimi.nekogram.NekoXConfig; import xyz.nextalone.nagram.NaConfig; -import xyz.nextalone.nagram.helper.PeerColorHelper; import static xyz.nextalone.nagram.helper.MessageHelper.showForwardDate; @@ -215,6 +214,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public ExpiredStoryView expiredStoryView; private boolean skipFrameUpdate; + public ChannelRecommendationsCell channelRecommendationsCell; + public RadialProgress2 getRadialProgress() { return radialProgress; } @@ -279,7 +280,7 @@ public void setAvatar(MessageObject messageObject) { } else { currentPhoto = null; } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, LiteMode.isEnabled(LiteMode.FLAGS_CHAT), VectorAvatarThumbDrawable.TYPE_SMALL, false); } else if (currentChat != null) { if (currentChat.photo != null) { @@ -287,7 +288,7 @@ public void setAvatar(MessageObject messageObject) { } else { currentPhoto = null; } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); avatarImage.setForUserOrChat(currentChat, avatarDrawable); } else if (messageObject.isSponsored()) { if (messageObject.sponsoredWebPage != null) { @@ -297,10 +298,10 @@ public void setAvatar(MessageObject messageObject) { avatarImage.setImage(ImageLocation.getForPhoto(FileLoader.getClosestPhotoSizeWithSize(photo.sizes, AndroidUtilities.dp(50), false, null, true), photo), "50_50", avatarDrawable, null, null, 0); } } else if (messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { - avatarDrawable.setInfo(messageObject.sponsoredChatInvite.chat); + avatarDrawable.setInfo(currentAccount, messageObject.sponsoredChatInvite.chat); avatarImage.setForUserOrChat(messageObject.sponsoredChatInvite.chat, avatarDrawable); } else { - avatarDrawable.setInfo(messageObject.sponsoredChatInvite); + avatarDrawable.setInfo(currentAccount, messageObject.sponsoredChatInvite); if (messageObject.sponsoredChatInvite != null) { TLRPC.Photo photo = messageObject.sponsoredChatInvite.photo; if (photo != null) { @@ -510,6 +511,18 @@ default void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBloc } + default void didPressChannelRecommendation(ChatMessageCell cell, TLRPC.Chat chat, boolean longPress) { + + } + + default void didPressMoreChannelRecommendations(ChatMessageCell cell) { + + } + + default void didPressChannelRecommendationsClose(ChatMessageCell cell) { + + } + default void needOpenWebView(MessageObject message, String url, String title, String description, String originalUrl, int w, int h) { } @@ -759,7 +772,7 @@ public static class PollButton { private int unmovedTextX; private int linkPreviewY; public int textY; - private int totalHeight; + public int totalHeight; private int additionalTimeOffsetY; private int keyboardHeight; private int linkBlockNum; @@ -861,6 +874,7 @@ public boolean isCellAttachedToWindow() { private boolean drawInstantView; private boolean pollInstantViewTouchesBottom; public int drawInstantViewType; + public String instantViewButtonText; private int imageBackgroundColor; private float imageBackgroundIntensity; private int imageBackgroundGradientColor1; @@ -956,6 +970,8 @@ public boolean isCellAttachedToWindow() { private RectF deleteProgressRect = new RectF(); private RectF rect = new RectF(); private TLObject photoParentObject; + private ImageLocation currentPhotoLocation; + private ImageLocation currentPhotoThumbLocation; private TLRPC.PhotoSize currentPhotoObject; private TLRPC.PhotoSize currentPhotoObjectThumb; private BitmapDrawable currentPhotoObjectThumbStripped; @@ -1003,7 +1019,7 @@ class LoadingDrawableLocation { private int seekBarY; private boolean useTranscribeButton; - private TranscribeButton transcribeButton; + public TranscribeButton transcribeButton; private float transcribeX, transcribeY; private StaticLayout durationLayout; @@ -1224,8 +1240,6 @@ class LoadingDrawableLocation { private boolean drawName; private boolean drawNameLayout; - private Paint closeSponsoredPaint; - private Path closeSponsoredPath; private ButtonBounce closeSponsoredBounce; private RectF closeSponsoredBounds; @@ -2175,7 +2189,7 @@ private boolean checkLinkPreviewMotionEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); - if (x >= unmovedTextX && x <= unmovedTextX + backgroundWidth && y >= linkPreviewY && y <= linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(8 + (drawInstantView ? 46 : 0))) { + if (x >= unmovedTextX && x <= unmovedTextX + backgroundWidth - dp(14) && y >= linkPreviewY && y <= linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(8 + (drawInstantView ? 46 : 0))) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (descriptionLayout != null && y >= descriptionY && !currentMessageObject.preview) { try { @@ -3293,6 +3307,12 @@ public boolean onTouchEvent(MotionEvent event) { if (!result) { result = checkTextBlockMotionEvent(event); } + if (!result && channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + result = channelRecommendationsCell.checkTouchEvent(event); + if (result) { + disallowLongPress = true; + } + } if (!result) { result = checkNameMotionEvent(event); } @@ -3437,7 +3457,11 @@ public boolean onTouchEvent(MotionEvent event) { } else if (drawNameLayout && nameLayout != null && viaWidth != 0 && x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - AndroidUtilities.dp(4) && y <= nameY + AndroidUtilities.dp(20)) { forwardBotPressed = true; result = true; - } else if (drawSideButton != 0 && x >= sideStartX && x <= sideStartX + AndroidUtilities.dp(40) && y >= sideStartY && y <= sideStartY + AndroidUtilities.dp(32 + (drawSideButton == 3 && commentLayout != null ? 18 : 0))) { + } else if ( + drawSideButton != 0 && + x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && + y >= sideStartY - dp(24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)) + ) { if (currentMessageObject.isSent()) { sideButtonPressed = true; } @@ -3651,7 +3675,9 @@ public boolean onTouchEvent(MotionEvent event) { sideButtonPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (drawSideButton == 3) { + if (drawSideButton == 4) { + delegate.didPressSponsoredClose(); + } else if (drawSideButton == 3) { delegate.didPressCommentButton(this); } else { delegate.didPressSideButton(this); @@ -3660,7 +3686,10 @@ public boolean onTouchEvent(MotionEvent event) { } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { sideButtonPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= sideStartX && x <= sideStartX + AndroidUtilities.dp(40) && y >= sideStartY && y <= sideStartY + AndroidUtilities.dp(32 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)))) { + if (!( + x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && + y >= sideStartY - dp(24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)) + )) { sideButtonPressed = false; } } @@ -3958,7 +3987,7 @@ public void setVisiblePart(int position, int height, int parent, float parentOff this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; - if (!botButtons.isEmpty() && viewTop != visibleTop) { + if ((!botButtons.isEmpty() || channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) && viewTop != visibleTop) { invalidate(); } viewTop = visibleTop; @@ -4415,6 +4444,9 @@ protected void onDetachedFromWindow() { if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.detach(this); } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onDetachedFromWindow(); + } } @Override @@ -4501,6 +4533,9 @@ public void onAttachedToWindow() { mediaSpoilerEffect2.attach(this); } } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onAttachedToWindow(); + } } boolean imageReceiversAttachState; @@ -4791,7 +4826,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe drawVideoSize = false; canStreamVideo = false; animatingNoSound = 0; - if (MessagesController.getInstance(currentAccount).isChatNoForwardsWithOverride(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards && !NekoXConfig.disableFlagSecure)) { + if (messageObject.isSponsored()) { + drawSideButton = 4; + } else if (MessagesController.getInstance(currentAccount).isChatNoForwardsWithOverride(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards && !NekoXConfig.disableFlagSecure)) { drawSideButton = 0; } else { drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) && (currentPosition == null || currentPosition.last) && !needHide ? 1 : 0; @@ -4881,6 +4918,8 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe docTitleLayout = null; drawImageButton = false; drawVideoImageButton = false; + currentPhotoLocation = null; + currentPhotoThumbLocation = null; currentPhotoObject = null; photoParentObject = null; currentPhotoObjectThumb = null; @@ -4902,6 +4941,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe useTranscribeButton = false; drawInstantView = false; drawInstantViewType = 0; + instantViewButtonText = null; drawForwardedName = false; drawCommentButton = false; photoImage.setSideClip(0); @@ -5014,10 +5054,10 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe final int A = a; post(() -> { if (user != null) { - commentAvatarDrawables[A].setInfo(user); + commentAvatarDrawables[A].setInfo(currentAccount, user); commentAvatarImages[A].setForUserOrChat(user, commentAvatarDrawables[A]); } else if (chat != null) { - commentAvatarDrawables[A].setInfo(chat); + commentAvatarDrawables[A].setInfo(currentAccount, chat); commentAvatarImages[A].setForUserOrChat(chat, commentAvatarDrawables[A]); } else { commentAvatarDrawables[A].setInfo(id, "", ""); @@ -5073,11 +5113,24 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe drawCommentNumber = false; } - if (messageObject.isExpiredStory()) { + if (messageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + drawBackground = true; + drawForwardedName = false; + hasReplyQuote = false; + isReplyQuote = false; + replyNameLayout = null; + replyTextLayout = null; + forwardedNameLayout[0] = null; + forwardedNameLayout[1] = null; + drawName = false; + if (channelRecommendationsCell == null) { + channelRecommendationsCell = new ChannelRecommendationsCell(this); + } + channelRecommendationsCell.setMessageObject(messageObject); + } else if (messageObject.isExpiredStory()) { if (!messageIdChanged) { requestLayout(); } - // currentTimeString = null; drawBackground = true; if (expiredStoryView == null) { expiredStoryView = new ExpiredStoryView(); @@ -5096,7 +5149,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; drawName = false; - } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveaway()) { + } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveaway() || messageObject.isSponsored()) { drawForwardedName = !isRepliesChat; int maxWidth; @@ -5149,7 +5202,27 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } if (!drawInstantView) { - if (messageObject.isGiveaway()) { + if (messageObject.isSponsored()) { + drawInstantView = true; + hasLinkPreview = true; + instantViewButtonText = messageObject.sponsoredButtonText; + if (messageObject.sponsoredBotApp != null) { + drawInstantViewType = 15; + } else if (messageObject.sponsoredWebPage != null) { + drawInstantViewType = 16; + } else if (messageObject.sponsoredChannelPost != 0) { + drawInstantViewType = 12; + } else { + drawInstantViewType = 1; + long id = MessageObject.getPeerId(messageObject.messageOwner.from_id); + if (id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); + if (user != null && user.bot) { + drawInstantViewType = 10; + } + } + } + } else if (messageObject.isGiveaway()) { drawInstantView = true; drawInstantViewType = 19; } else if ("telegram_channel_boost".equals(webpageType)) { @@ -5342,7 +5415,11 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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 (messageObject.isSponsored()) { + totalHeight = AndroidUtilities.dp(22.5f); + } else { + totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset; + } if (!reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(messageObject.isGiveaway() ? giveawayMessageCell.getMeasuredWidth() : maxWidth, Gravity.LEFT); @@ -5389,6 +5466,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe String title; CharSequence author; String description; + TLObject peerPhoto = null; TLRPC.Photo photo; TLRPC.Document document; WebFile webDocument; @@ -5396,7 +5474,43 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe boolean smallImage; String type; final int smallImageSide = AndroidUtilities.dp(48), smallSideMargin = AndroidUtilities.dp(10); - if (drawInstantViewType == 19) { + CharSequence overrideDescrption = null; + if (messageObject.isSponsored()) { + site_name = LocaleController.getString(messageObject.sponsoredRecommended ? R.string.SponsoredMessage2Recommended : R.string.SponsoredMessage2); + title = messageObject.customName != null ? messageObject.customName : getAuthorName(); + webDocument = null; + overrideDescrption = messageObject.messageText; + description = overrideDescrption != null ? overrideDescrption.toString() : null; + photo = null; + author = null; + document = null; + if (messageObject.sponsoredBotApp != null) { + photo = messageObject.sponsoredBotApp.photo; + } else if (messageObject.sponsoredWebPage != null) { + photo = messageObject.sponsoredWebPage.photo; + } else if (messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { + peerPhoto = messageObject.sponsoredChatInvite.chat; + currentPhotoLocation = ImageLocation.getForChat(messageObject.sponsoredChatInvite.chat, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForChat(messageObject.sponsoredChatInvite.chat, ImageLocation.TYPE_SMALL); + } else if (messageObject.sponsoredShowPeerPhoto) { + peerPhoto = messageObject.getFromPeerObject(); + if (peerPhoto instanceof TLRPC.User) { + currentPhotoLocation = ImageLocation.getForUser((TLRPC.User) peerPhoto, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForUser((TLRPC.User) peerPhoto, ImageLocation.TYPE_SMALL); + } else if (peerPhoto instanceof TLRPC.Chat) { + currentPhotoLocation = ImageLocation.getForChat((TLRPC.Chat) peerPhoto, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForChat((TLRPC.Chat) peerPhoto, ImageLocation.TYPE_SMALL); + } + } + if (photo == null && messageObject.sponsoredChatInvite != null) { + photo = messageObject.sponsoredChatInvite.photo; + } + duration = 0; + type = null; + isSmallImage = true; + linkPreviewAbove = false; + smallImage = true; + } else if (drawInstantViewType == 19) { site_name = null; title = null; webDocument = null; @@ -5676,12 +5790,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } int restLines = 0; boolean allowAllLines = site_name != null && site_name.toString().toLowerCase().equals("twitter"); - boolean isRTL = AndroidUtilities.isRTL(messageObject.linkDescription); + CharSequence text = overrideDescrption != null ? overrideDescrption : messageObject.linkDescription; + boolean isRTL = AndroidUtilities.isRTL(text); if (restLinesCount == 3 && !isSmallImage) { - descriptionLayout = StaticLayoutEx.createStaticLayout(messageObject.linkDescription, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, allowAllLines ? 100 : 6); + descriptionLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, allowAllLines ? 100 : 6); } else { restLines = restLinesCount; - descriptionLayout = generateStaticLayout(messageObject.linkDescription, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide : 0), linkPreviewMaxWidth - smallImageSide - (isRTL ? 0 : smallSideMargin), restLinesCount, allowAllLines ? 100 : 6); + descriptionLayout = generateStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide : 0), linkPreviewMaxWidth - smallImageSide - (isRTL ? 0 : smallSideMargin), restLinesCount, allowAllLines ? 100 : 6); } animatedEmojiDescriptionStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiDescriptionStack, descriptionLayout); @@ -5693,7 +5808,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe descriptionLayoutLeft = descriptionLayout.getWidth(); for (int a = 0; a < descriptionLayout.getLineCount(); a++) { descriptionLayoutLeft = (int) Math.min(descriptionLayoutLeft, descriptionLayout.getLineLeft(a)); - float width = descriptionLayout.getLineWidth(a); + float width = Math.min(descriptionLayout.getWidth(), descriptionLayout.getLineWidth(a)); if (a < restLines || restLines != 0 && descriptionLayoutLeft != 0 && isSmallImage) { width += smallImageSide + smallSideMargin; } @@ -5948,6 +6063,17 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } } + } else if (peerPhoto != null) { + checkOnlyButtonPressed = false; + if (peerPhoto instanceof TLRPC.User) { + TLRPC.UserProfilePhoto userProfilePhoto = ((TLRPC.User) peerPhoto).photo; + photoParentObject = userProfilePhoto; + currentPhotoObjectThumbStripped = userProfilePhoto.strippedBitmap; + } else if (peerPhoto instanceof TLRPC.Chat) { + TLRPC.ChatPhoto chatPhoto = ((TLRPC.Chat) peerPhoto).photo; + photoParentObject = chatPhoto; + currentPhotoObjectThumbStripped = chatPhoto.strippedBitmap; + } } else if (photo != null) { boolean isPhoto = type != null && type.equals("photo"); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, isPhoto || !smallImage ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !isPhoto); @@ -5969,7 +6095,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } if (documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { - if (currentPhotoObject != null || webDocument != null || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { + if (currentPhotoObject != null || currentPhotoLocation != null || webDocument != null || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { drawImageButton = photo != null && !smallImage || type != null && (type.equals("photo") || type.equals("document") && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER || type.equals("gif") || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER); if (isSmallImage) { drawImageButton = false; @@ -6178,9 +6304,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } else { boolean photoExist = messageObject.mediaExists; String fileName = FileLoader.getAttachFileName(currentPhotoObject); - if (hasGamePreview || photoExist || DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + if (hasGamePreview || photoExist || DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || currentMessageObject.isSponsored()) { photoNotSet = false; - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + if (currentPhotoLocation != null) { + photoImage.setImage(currentPhotoLocation, currentPhotoFilter, currentPhotoThumbLocation, currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + } else { + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + } } else { photoNotSet = true; if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { @@ -6265,11 +6395,11 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } - if (!hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveaway()) { linkPreviewHeight += AndroidUtilities.dp(6); totalHeight += AndroidUtilities.dp(6); } - if (!hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway() && ( + if (!hasInvoicePreview && !currentMessageObject.isGiveaway() && ( currentPhotoObject != null || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO ) && (authorLayout != null || descriptionLayout != null || titleLayout != null || siteNameLayout != null)) { linkPreviewHeight += AndroidUtilities.dp(2.66f); @@ -6381,7 +6511,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } boolean hasName; if (user != null) { - contactAvatarDrawable.setInfo(user); + contactAvatarDrawable.setInfo(currentAccount, user); hasName = true; } else if (!TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).first_name) || !TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).last_name)) { contactAvatarDrawable.setInfo(0, MessageObject.getMedia(messageObject.messageOwner).first_name, MessageObject.getMedia(messageObject.messageOwner).last_name); @@ -6662,7 +6792,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe TLRPC.Peer id = media.results.recent_voters.get(a); TLObject user = MessagesController.getInstance(currentAccount).getUserOrChat(DialogObject.getPeerDialogId(id)); if (user != null) { - pollAvatarDrawables[a].setInfo(user); + pollAvatarDrawables[a].setInfo(currentAccount, user); pollAvatarImages[a].setForUserOrChat(user, pollAvatarDrawables[a]); } else { pollAvatarDrawables[a].setInfo(DialogObject.getPeerDialogId(id), "", ""); @@ -7035,13 +7165,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe updateCurrentUserAndChat(); if (currentUser != null) { - contactAvatarDrawable.setInfo(currentUser); + contactAvatarDrawable.setInfo(currentAccount, currentUser); locationImageReceiver.setForUserOrChat(currentUser, contactAvatarDrawable); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; } - contactAvatarDrawable.setInfo(currentChat); + contactAvatarDrawable.setInfo(currentAccount, currentChat); locationImageReceiver.setForUserOrChat(currentChat, contactAvatarDrawable); } else { locationImageReceiver.setImage(null, null, contactAvatarDrawable, null, null, 0); @@ -7211,7 +7341,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe photoWidth = Math.max(512, photoWidth); photoHeight = Math.max(512, photoHeight); if (MessageObject.isTextColorEmoji(messageObject.getDocument())) { - photoImage.setColorFilter(Theme.chat_animatedEmojiTextColorFilter); + photoImage.setColorFilter(getAdaptiveEmojiColorFilter(0, getThemedColor(Theme.key_windowBackgroundWhiteBlackText))); } } float maxHeight; @@ -8215,25 +8345,6 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } - if (messageObject.isSponsored()) { - drawInstantView = true; - if (messageObject.sponsoredWebPage != null) { - drawInstantViewType = 16; - } else if (messageObject.sponsoredChannelPost != 0) { - drawInstantViewType = 12; - } else { - drawInstantViewType = 1; - } - long id = MessageObject.getPeerId(messageObject.messageOwner.from_id); - if (id > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); - if (user != null && user.bot) { - drawInstantViewType = 10; - } - } - createInstantViewButton(); - } - botButtons.clear(); if (messageIdChanged) { botButtonsByData.clear(); @@ -8548,6 +8659,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe if (transcribeButton != null) { transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), !messageIdChanged); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), !messageIdChanged); + transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), !messageIdChanged); } updateWaveform(); updateButtonState(false, !messageIdChanged && !messageObject.cancelEditing, true); @@ -8684,7 +8796,7 @@ public void invalidate() { } if (replySelector != null) { replySelectorPressed = false; - replySelector.setState(new int[]{}); + replySelector.setState(StateSet.NOTHING); invalidate(); } if (nameStatusSelector != null) { @@ -9026,11 +9138,23 @@ private void updateWaveform() { currentMessageObject != null && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && ( - UserConfig.getInstance(currentAccount).isPremium() || + UserConfig.getInstance(currentAccount).isPremium() + || + MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber > 0 && + currentMessageObject.getDuration() <= MessagesController.getInstance(currentAccount).transcribeAudioTrialDurationMax && ( + currentMessageObject.messageOwner != null && ( + !TextUtils.isEmpty(currentMessageObject.messageOwner.voiceTranscription) || + currentMessageObject.messageOwner.voiceTranscriptionFinal + ) || + TranscribeButton.canTranscribeTrial(currentMessageObject) || true + ) + || + MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber <= 0 && + !MessagesController.getInstance(currentAccount).premiumLocked && !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && !currentMessageObject.isOutOwner() && ( currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60 - ) && !MessagesController.getInstance(currentAccount).premiumLocked + ) ) && ( currentMessageObject.isVoice() && useSeekBarWaveform || currentMessageObject.isRoundVideo() @@ -9252,7 +9376,7 @@ private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) totalHeight += AndroidUtilities.dp(14); } } else { - newLineForTime = !linkPreviewAbove && (hasLinkPreview || hasOldCaptionPreview || hasGamePreview || hasInvoicePreview) || maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; + newLineForTime = !linkPreviewAbove && (hasLinkPreview && !currentMessageObject.isSponsored() || hasOldCaptionPreview || hasGamePreview || hasInvoicePreview) || maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; } int newLineForTimeDp = 14; @@ -9281,9 +9405,9 @@ private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) } public boolean setHighlightedText(String text) { - return setHighlightedText(text, false); + return setHighlightedText(text, false, -1); } - public boolean setHighlightedText(String text, boolean quote) { + public boolean setHighlightedText(String text, boolean quote, int quote_offset) { if (highlightedQuote && !quote && TextUtils.isEmpty(text)) { return false; } @@ -9323,7 +9447,7 @@ public boolean setHighlightedText(String text, boolean quote) { int start = -1, length = -1; String punctuationsChars = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"; if (quote) { - start = message.indexOf(text); + start = MessageObject.findQuoteStart(message, text, quote_offset); length = text.length(); } else { for (int a = 0, N1 = message.length(); a < N1; a++) { @@ -9718,7 +9842,9 @@ private void createInstantViewButton() { if (drawInstantView && instantViewLayout == null) { String str; instantWidth = AndroidUtilities.dp(12 + 9 + 12); - if (drawInstantViewType == 12) { + if (instantViewButtonText != null) { + str = instantViewButtonText; + } else if (drawInstantViewType == 12) { str = LocaleController.getString("OpenChannelPost", R.string.OpenChannelPost); } else if (drawInstantViewType == 1) { str = LocaleController.getString("OpenChannel", R.string.OpenChannel); @@ -9955,14 +10081,16 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto if (currentMessageObject.type == MessageObject.TYPE_TEXT) { textY = AndroidUtilities.dp(10) + namesOffset; - if (linkPreviewAbove) { + if (currentMessageObject.isSponsored()) { + linkPreviewY = textY + AndroidUtilities.dp(14); + } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveaway()) { textY += AndroidUtilities.dp(44); } } else { - linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(!currentMessageObject.isSponsored() ? 10 : 0); + linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(10); } } if (isRoundVideo) { @@ -10774,6 +10902,7 @@ protected void onOpen() { }; transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), false); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), false); + transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), false); } if (drawSideButton != 0) { transcribeX = AndroidUtilities.lerp( @@ -10919,7 +11048,7 @@ protected void onOpen() { canvas.save(); canvas.translate(linkX + AndroidUtilities.dp(10) + descriptionX, descriptionY); SpoilerEffect.layoutDrawMaybe(descriptionLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); } drawTime = true; @@ -11236,9 +11365,6 @@ public void drawLinkPreview(Canvas canvas, float alpha) { linkX = unmovedTextX + AndroidUtilities.dp(1); } else if (currentMessageObject.isSponsored()) { startY = this.linkPreviewY - AndroidUtilities.dp(2); - if (hasNewLineForTime) { - startY += AndroidUtilities.dp(12); - } linkX = unmovedTextX + AndroidUtilities.dp(1); } else { if (currentMessageObject.isOutOwner()) { @@ -11281,7 +11407,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { boolean restore = false; boolean drawInstantButtonInside = false; boolean loading = delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_INSTANT); - if (!hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveaway()) { drawInstantButtonInside = true; if (linkPreviewBounce == null) { @@ -11294,7 +11420,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { AndroidUtilities.rectTmp.set(linkX, linkPreviewY - AndroidUtilities.dp(6), linkX + width, linkPreviewY + linkPreviewHeight + (drawInstantButtonInside && drawInstantView ? AndroidUtilities.dp(42) : 0)); linkLine.setLoading(loading); - float rad = (float) Math.floor(SharedConfig.bubbleRadius / 3); + float rad = (float) Math.floor(SharedConfig.bubbleRadius / (currentMessageObject.isSponsored() ? 2f : 3f)); linkLine.drawBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); int rippleColor = linkLine.getBackgroundColor(); @@ -11553,7 +11679,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { paint.setAlpha((int) (wasAlpha * alpha)); descriptionLayout.draw(canvas); paint.setAlpha(wasAlpha); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); paint.linkColor = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); @@ -11983,14 +12109,16 @@ public void layoutTextXY(boolean parent) { textY += AndroidUtilities.dp(5); } } - if (linkPreviewAbove) { + if (currentMessageObject.isSponsored()) { + linkPreviewY = textY + AndroidUtilities.dp(14); + } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveaway()) { textY += AndroidUtilities.dp(44); } } else { - linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(!currentMessageObject.isSponsored() ? 10 : 0); + linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(10); } unmovedTextX = textX; if (currentMessageObject.textXOffset != 0 && replyNameLayout != null) { @@ -12005,7 +12133,7 @@ public void layoutTextXY(boolean parent) { } public void drawMessageText(Canvas canvas) { - if (currentMessageObject == null) { + if (currentMessageObject == null || currentMessageObject.isSponsored()) { return; } float textY = this.textY; @@ -13601,11 +13729,7 @@ private void measureTime(MessageObject messageObject) { } } if (currentMessageObject.isSponsored()) { - if (currentMessageObject.sponsoredRecommended) { - timeString = LocaleController.getString("SponsoredMessageRecommended", R.string.SponsoredMessageRecommended); - } else { - timeString = LocaleController.getString("SponsoredMessage", R.string.SponsoredMessage); - } + timeString = ""; } else if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE) { timeString = ""; } else if (edited) { @@ -14534,6 +14658,9 @@ private boolean isNeedAuthorName() { if (currentMessageObject.forceAvatar) { return true; } + if (currentMessageObject.isSponsored()) { + return false; + } if (currentMessageObject.isGiveaway()) { return false; } @@ -14550,6 +14677,9 @@ private String getAuthorName() { } else if (currentChat != null) { return currentChat.title; } else if (currentMessageObject != null && currentMessageObject.isSponsored()) { + if (currentMessageObject.sponsoredBotApp != null) { + return currentMessageObject.sponsoredBotApp.title; + } if (currentMessageObject.sponsoredWebPage != null) { return currentMessageObject.sponsoredWebPage.site_name; } @@ -14624,7 +14754,7 @@ public boolean isDrawPinnedBottom() { } public void drawCheckBox(Canvas canvas) { - if (currentMessageObject != null && !currentMessageObject.isSending() && !currentMessageObject.isSendError() && checkBox != null && (checkBoxVisible || checkBoxAnimationInProgress) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { + if (currentMessageObject != null && !currentMessageObject.isSending() && currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL && !currentMessageObject.isSendError() && checkBox != null && (checkBoxVisible || checkBoxAnimationInProgress) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { canvas.save(); float y = getY(); if (currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { @@ -14735,6 +14865,14 @@ protected void onDraw(Canvas canvas) { return; } + if (channelRecommendationsCell != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + if (delegate == null || delegate.canDrawOutboundsContent()) { + channelRecommendationsCell.draw(canvas); + } + transitionParams.recordDrawingState(); + return; + } + setupTextColors(); if (documentAttach != null) { @@ -15379,6 +15517,50 @@ public boolean drawBackgroundInParent() { return false; } + public void drawServiceBackground(Canvas canvas, RectF rect, float radius, float alpha) { + applyServiceShaderMatrix(); + if (alpha != 1f) { + int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); + canvas.drawRoundRect(rect, radius, radius, getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + } else { + canvas.drawRoundRect(rect, radius, radius, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); + } + if (hasGradientService()) { + if (alpha != 1f) { + int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); + canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } else { + canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); + } + } + } + + public void drawServiceBackground(Canvas canvas, Path path, float alpha) { + applyServiceShaderMatrix(); + if (alpha != 1f) { + int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); + canvas.drawPath(path, getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + } else { + canvas.drawPath(path, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); + } + if (hasGradientService()) { + if (alpha != 1f) { + int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); + canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } else { + canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); + } + } + } + public void drawCommentButton(Canvas canvas, float alpha) { if (drawSideButton != 3) { return; @@ -15453,6 +15635,9 @@ private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, f } public boolean hasOutboundsContent() { + if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + return true; + } if (getAlpha() != 1f) { return false; } @@ -15470,6 +15655,10 @@ public boolean hasOutboundsContent() { } public void drawOutboundsContent(Canvas canvas) { + if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + channelRecommendationsCell.draw(canvas); + return; + } if (!enterTransitionInProgress) { drawAnimatedEmojis(canvas, 1f); } @@ -15513,12 +15702,11 @@ public void drawOutboundsContent(Canvas canvas) { } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = currentMessageObject.sponsoredChatInvite.color; } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite != null && currentMessageObject.sponsoredChatInvite.chat != null) { - colorId = (currentMessageObject.sponsoredChatInvite.chat.flags2 & 64) != 0 ? currentMessageObject.sponsoredChatInvite.chat.color : (int) (currentMessageObject.sponsoredChatInvite.chat.id % 7); + colorId = ChatObject.getColorId(currentMessageObject.sponsoredChatInvite.chat); } else if (currentMessageObject.isFromUser() && currentUser != null) { - colorId = (currentUser.flags2 & 128) != 0 ? currentUser.color : (int) (currentUser.id % 7); - if (currentUser.self) colorId = PeerColorHelper.replaceColor(colorId); + colorId = UserObject.getColorId(currentUser); } else { - colorId = (currentChat.flags2 & 64) != 0 ? currentChat.color : (int) (currentChat.id % 7); + colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { color = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]); @@ -15526,7 +15714,7 @@ public void drawOutboundsContent(Canvas canvas) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - color = peerColor.getColor1(); + color = peerColor.getColor1(isDark()); } else { color = getThemedColor(Theme.key_chat_inForwardedNameText); } @@ -15602,6 +15790,9 @@ public void drawAnimatedEmojis(Canvas canvas, float alpha) { } private void drawAnimatedEmojiMessageText(Canvas canvas, float alpha) { + if (currentMessageObject == null || currentMessageObject.isSponsored()) { + return; + } float textY = this.textY; if (transitionParams.animateText) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; @@ -15631,7 +15822,7 @@ private void drawAnimatedEmojiMessageText(Canvas canvas, float alpha) { } private void drawAnimatedEmojiMessageText(float textX, float textY, Canvas canvas, ArrayList textLayoutBlocks, AnimatedEmojiSpan.EmojiGroupedSpans stack, boolean origin, float alpha, float rtlOffset, boolean drawAllBlocks) { - if (textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { + if (currentMessageObject == null || textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } int firstVisibleBlockNum; @@ -15664,7 +15855,11 @@ private void drawAnimatedEmojiMessageText(float textX, float textY, Canvas canva if (transitionParams.messageEntering) { top = bottom = 0; } - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, block.textLayout, stack, 0, block.spoilers, top, bottom, drawingYOffset, alpha, currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + int textColorKey = currentMessageObject.isOutOwner() ? Theme.key_chat_messageTextOut : Theme.key_chat_messageTextIn; + if (currentMessageObject.shouldDrawWithoutBackground()) { + textColorKey = Theme.key_windowBackgroundWhiteBlackText; + } + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, block.textLayout, stack, 0, block.spoilers, top, bottom, drawingYOffset, alpha, getAdaptiveEmojiColorFilter(0, getThemedColor(textColorKey))); canvas.restore(); } } @@ -15709,23 +15904,30 @@ private void drawSideButton(Canvas canvas) { sideStartX += currentMessagesGroup.transitionParams.offsetRight - animationOffsetX; } } - sideStartY = layoutHeight + transitionParams.deltaBottom - AndroidUtilities.dp(41); - if (currentMessageObject.type == MessageObject.TYPE_EMOJIS && currentMessageObject.textWidth < timeTextWidth) { - sideStartY -= AndroidUtilities.dp(22); - } - if (currentMessagesGroup != null) { - sideStartY += currentMessagesGroup.transitionParams.offsetBottom; - if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { - sideStartY -= getTranslationY(); + if (drawSideButton == 4) { + sideStartY = AndroidUtilities.dp(6); + } else { + sideStartY = layoutHeight + transitionParams.deltaBottom - AndroidUtilities.dp(41); + if (currentMessageObject.type == MessageObject.TYPE_EMOJIS && currentMessageObject.textWidth < timeTextWidth) { + sideStartY -= AndroidUtilities.dp(22); } - } - if (!reactionsLayoutInBubble.isSmall) { - if (isRoundVideo) { - sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); - } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { - sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); + if (currentMessagesGroup != null) { + sideStartY += currentMessagesGroup.transitionParams.offsetBottom; + if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { + sideStartY -= getTranslationY(); + } + } + if (!reactionsLayoutInBubble.isSmall) { + if (isRoundVideo) { + sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); + } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { + sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); + } } } + if (drawSideButton != 4 && sideStartY < (layoutHeight - AndroidUtilities.dp(32)) / 2f) { + sideStartY = (layoutHeight - AndroidUtilities.dp(32)) / 2f; + } if (!currentMessageObject.isOutOwner() && isRoundVideo && !hasLinkPreview) { float offsetSize = isAvatarVisible ? ((AndroidUtilities.roundPlayingMessageSize - AndroidUtilities.roundMessageSize) * 0.7f) : AndroidUtilities.dp(50); float offsetX = isPlayingRound ? offsetSize * (1f - getVideoTranscriptionProgress()) : 0; @@ -15762,6 +15964,16 @@ private void drawSideButton(Canvas canvas) { if (currentMessageObject.isOutOwner()) { canvas.restore(); } + } else if (drawSideButton == 4) { + final int scx = (int) (sideStartX + AndroidUtilities.dp(16)), scy = (int) (sideStartY + AndroidUtilities.dp(16)); + Drawable drawable = getThemedDrawable(Theme.key_drawable_closeIcon); + final int shw = drawable.getIntrinsicWidth() / 2, shh = drawable.getIntrinsicHeight() / 2; + drawable.setBounds(scx - shw, scy - shh, scx + shw, scy + shh); + setDrawableBounds(drawable, sideStartX + AndroidUtilities.dp(4), sideStartY + AndroidUtilities.dp(4)); + canvas.save(); + canvas.scale(.65f, .65f, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + drawable.draw(canvas); + canvas.restore(); } else { final int scx = (int) (sideStartX + AndroidUtilities.dp(16)), scy = (int) (sideStartY + AndroidUtilities.dp(16)); Drawable drawable = getThemedDrawable(Theme.key_drawable_shareIcon); @@ -16044,12 +16256,11 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = currentMessageObject.sponsoredChatInvite.color; } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite != null && currentMessageObject.sponsoredChatInvite.chat != null) { - colorId = (currentMessageObject.sponsoredChatInvite.chat.flags2 & 64) != 0 ? currentMessageObject.sponsoredChatInvite.chat.color : (int) (currentMessageObject.sponsoredChatInvite.chat.id % 7); + colorId = ChatObject.getColorId(currentMessageObject.sponsoredChatInvite.chat); } else if (currentMessageObject.isFromUser() && currentUser != null) { - colorId = (currentUser.flags2 & 128) != 0 ? currentUser.color : (int) (currentUser.id % 7); - if (currentUser.self) colorId = PeerColorHelper.replaceColor(colorId); + colorId = UserObject.getColorId(currentUser); } else { - colorId = (currentChat.flags2 & 64) != 0 ? currentChat.color : (int) (currentChat.id % 7); + colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { Theme.chat_namePaint.setColor(getThemedColor(Theme.keys_avatar_nameInMessage[colorId])); @@ -16057,7 +16268,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_namePaint.setColor(peerColor.getColor1()); + Theme.chat_namePaint.setColor(peerColor.getColor1(isDark())); } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_inForwardedNameText)); } @@ -16178,38 +16389,6 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } adminLayout.draw(canvas); canvas.restore(); - } else if (currentMessageObject.isSponsored()) { - if (closeSponsoredBounce == null) { - closeSponsoredBounce = new ButtonBounce(this); - } - if (closeSponsoredPaint == null) { - closeSponsoredPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - } - if (closeSponsoredPath == null) { - closeSponsoredPath = new Path(); - closeSponsoredPaint.setStrokeCap(Paint.Cap.ROUND); - closeSponsoredPaint.setStyle(Paint.Style.STROKE); - } else { - closeSponsoredPath.rewind(); - } - if (closeSponsoredBounds == null) { - closeSponsoredBounds = new RectF(); - } - closeSponsoredPath.moveTo(0, 0); - closeSponsoredPath.lineTo(dp(8), dp(8)); - closeSponsoredPath.moveTo(0, dp(8)); - closeSponsoredPath.lineTo(dp(8), 0); - closeSponsoredPaint.setStrokeWidth(AndroidUtilities.dpf2(1.33f)); - closeSponsoredPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), .28f)); - canvas.save(); - closeSponsoredBounds.set(0, 0, dp(8), dp(8)); - closeSponsoredBounds.inset(-dp(16), -dp(16)); - closeSponsoredBounds.offset(end - AndroidUtilities.dp(22), nameY + AndroidUtilities.dp(5)); - canvas.translate(end - AndroidUtilities.dp(22), nameY + AndroidUtilities.dp(5)); - final float s = closeSponsoredBounce.getScale(.09f); - canvas.scale(s, s, dp(4), dp(4)); - canvas.drawPath(closeSponsoredPath, closeSponsoredPaint); - canvas.restore(); } } @@ -16313,12 +16492,12 @@ public void drawNamesLayout(Canvas canvas, float alpha) { if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + colorId = ChatObject.getColorId(chat); } } else { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + colorId = UserObject.getColorId(user); } } if (colorId < 7) { @@ -16327,7 +16506,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_forwardNamePaint.setColor(peerColor.getColor1()); + Theme.chat_forwardNamePaint.setColor(peerColor.getColor1(isDark())); } } } @@ -16519,7 +16698,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_outReplyMessageText); - if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { + if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outReplyMediaMessageSelectedText : Theme.key_chat_outReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } @@ -16531,7 +16710,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_inReplyMessageText); - if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { + if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inReplyMediaMessageSelectedText : Theme.key_chat_inReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } @@ -16723,7 +16902,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (1f - transitionParams.animateChangeProgress))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, transitionParams.animateReplyTextLayout, replySpoilers, canvas, false); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } @@ -16744,7 +16923,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (transitionParams.animateReplyTextLayout != null ? transitionParams.animateChangeProgress : 1))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, replyTextLayout, replySpoilers, canvas, false); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } @@ -17407,7 +17586,7 @@ private boolean findProgressLoadingLink(LoadingDrawableLocation location, LinkPa } public boolean needDrawTime() { - return !forceNotDrawTime; + return !forceNotDrawTime && (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL); } public boolean shouldDrawTimeOnMedia() { @@ -17421,6 +17600,9 @@ public void drawTime(Canvas canvas, float alpha, boolean fromParent) { if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this) && shouldDrawTimeOnMedia()) { return; } + if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + return; + } for (int i = 0; i < 2; i++) { float currentAlpha = alpha; if (i == 0 && isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 1f && !shouldDrawTimeOnMedia()) { @@ -17557,7 +17739,7 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl } alpha = AndroidUtilities.lerp(0.35f, 1f, progress); } - paint.setAlpha((int) (oldAlpha * timeAlpha * alpha)); + paint.setAlpha((int) (oldAlpha * timeAlpha * alpha * .6f)); int r; if (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { @@ -20823,6 +21005,10 @@ public class TransitionParams { public int lastReplyTextXOffset; public float animateReplyTextOffset; + public boolean lastDrawingRecommendationsExpanded; + public boolean animateRecommendationsExpanded; + public boolean animateFromRecommendationsExpanded; + public void recordDrawingState() { wasDraw = true; lastDrawingImageX = photoImage.getImageX(); @@ -20849,6 +21035,8 @@ public void recordDrawingState() { lastDrawingLinkPreviewHeight = linkPreviewHeight; lastDrawingLinkAbove = linkPreviewAbove; + lastDrawingRecommendationsExpanded = currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); + if (commentLayout != null) { lastCommentsCount = getRepliesCount(); lastTotalCommentWidth = totalCommentWidth; @@ -21023,6 +21211,14 @@ public boolean animateChange() { changed = true; } + animateRecommendationsExpanded = false; + final boolean channelsExpanded = currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); + if (channelsExpanded != lastDrawingRecommendationsExpanded) { + animateRecommendationsExpanded = true; + animateFromRecommendationsExpanded = lastDrawingRecommendationsExpanded; + changed = true; + } + animateLinkAbove = false; if (linkPreviewAbove != lastDrawingLinkAbove) { animateLinkAbove = true; @@ -21290,6 +21486,7 @@ public void resetAnimation() { animateSign = false; animateSmallImage = false; animateLinkAbove = false; + animateRecommendationsExpanded = false; animateDrawingTimeAlpha = false; animateLocationIsExpired = false; animatePlayingRound = false; @@ -21382,4 +21579,32 @@ public int getNameStatusX() { public int getNameStatusY() { return (int) (nameY + (nameLayout == null ? 0 : nameLayout.getHeight()) / 2); } + + @Override + public void computeScroll() { + super.computeScroll(); + if (channelRecommendationsCell != null) { + channelRecommendationsCell.computeScroll(); + } + } + + private ColorFilter[] adaptiveEmojiColorFilter; + private int[] adaptiveEmojiColor; + private ColorFilter getAdaptiveEmojiColorFilter(int n, int color) { + if (adaptiveEmojiColorFilter == null) { + adaptiveEmojiColor = new int[3]; + adaptiveEmojiColorFilter = new ColorFilter[3]; + } + if (color != adaptiveEmojiColor[n] || adaptiveEmojiColorFilter[n] == null) { + adaptiveEmojiColorFilter[n] = new PorterDuffColorFilter(adaptiveEmojiColor[n] = color, PorterDuff.Mode.SRC_IN); + } + return adaptiveEmojiColorFilter[n]; + } + + private boolean isDark() { + if (resourcesProvider != null) { + return resourcesProvider.isDark(); + } + return Theme.isCurrentThemeDark(); + } } 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 7f1ad0f1b0..410a72e2c6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -15,10 +15,12 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Shader; @@ -33,7 +35,6 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.ReplacementSpan; import android.text.style.StyleSpan; @@ -2187,7 +2188,7 @@ public void buildLayout() { 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)) { + if (span instanceof ClickableSpan || span instanceof CodeHighlighting.Span || span instanceof TypefaceSpan || span instanceof CodeHighlighting.ColorSpan || span instanceof QuoteSpan || span instanceof QuoteSpan.QuoteStyleSpan || (span instanceof StyleSpan && ((StyleSpan) span).getStyle() == android.graphics.Typeface.BOLD)) { messageStringSpannable.removeSpan(span); } } @@ -2910,10 +2911,10 @@ public boolean update(int mask, boolean animated) { avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else { if (useFromUserAsAvatar && message != null) { - avatarDrawable.setInfo(message.getFromPeerObject()); + avatarDrawable.setInfo(currentAccount, message.getFromPeerObject()); avatarImage.setForUserOrChat(message.getFromPeerObject(), avatarDrawable); } else if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); @@ -2924,7 +2925,7 @@ public boolean update(int mask, boolean animated) { avatarImage.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL, false); } } else if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setForUserOrChat(chat, avatarDrawable); } } @@ -3411,7 +3412,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); canvas.translate(nameLeft + nameLayoutTranslateX, AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 13)); SpoilerEffect.layoutDrawMaybe(nameLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, nameLayout, animatedEmojiStackName, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, nameLayout, animatedEmojiStackName, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(0, nameLayout.getPaint().getColor())); canvas.restore(); if (nameLayoutEllipsizeByGradient && !nameLayoutFits) { canvas.save(); @@ -3456,7 +3457,7 @@ protected void onDraw(Canvas canvas) { canvas.translate(messageNameLeft, messageNameTop); try { SpoilerEffect.layoutDrawMaybe(messageNameLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageNameLayout, animatedEmojiStack2, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageNameLayout, animatedEmojiStack2, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, messageNameLayout.getPaint().getColor())); } catch (Exception e) { FileLog.e(e); } @@ -3490,7 +3491,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); SpoilerEffect.clipOutCanvas(canvas, spoilers); SpoilerEffect.layoutDrawMaybe(messageLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, spoilers, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, spoilers, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(2, messageLayout.getPaint().getColor())); canvas.restore(); for (int i = 0; i < spoilers.size(); i++) { @@ -3503,7 +3504,7 @@ protected void onDraw(Canvas canvas) { } } else { SpoilerEffect.layoutDrawMaybe(messageLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(2, messageLayout.getPaint().getColor())); } messageLayout.getPaint().setAlpha(oldAlpha); canvas.restore(); @@ -3598,7 +3599,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); SpoilerEffect.clipOutCanvas(canvas, spoilers2); SpoilerEffect.layoutDrawMaybe(buttonLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, spoilers2, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, spoilers2, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(3, buttonLayout.getPaint().getColor())); canvas.restore(); for (int i = 0; i < spoilers2.size(); i++) { @@ -3611,7 +3612,7 @@ protected void onDraw(Canvas canvas) { } } else { SpoilerEffect.layoutDrawMaybe(buttonLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(3, buttonLayout.getPaint().getColor())); } canvas.restore(); } @@ -5260,4 +5261,17 @@ private void formatTopicsNames(int currentAccount, MessageObject message, TLRPC. } } } + + private ColorFilter[] adaptiveEmojiColorFilter; + private int[] adaptiveEmojiColor; + private ColorFilter getAdaptiveEmojiColorFilter(int n, int color) { + if (adaptiveEmojiColorFilter == null) { + adaptiveEmojiColor = new int[4]; + adaptiveEmojiColorFilter = new ColorFilter[4]; + } + if (color != adaptiveEmojiColor[n] || adaptiveEmojiColorFilter[n] == null) { + adaptiveEmojiColorFilter[n] = new PorterDuffColorFilter(adaptiveEmojiColor[n] = color, PorterDuff.Mode.SRC_IN); + } + return adaptiveEmojiColorFilter[n]; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java index aa6d810888..6f06588655 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java @@ -114,7 +114,7 @@ public void buildLayout() { nameLeft = AndroidUtilities.dp(14); } nameString = chat.title; - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setForUserOrChat(chat, avatarDrawable, recentMeUrl); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlUser) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(recentMeUrl.user_id); @@ -137,7 +137,7 @@ public void buildLayout() { drawVerified = user.verifiedExtended(); } nameString = UserObject.getUserName(user); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImage.setForUserOrChat(user, avatarDrawable, recentMeUrl); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlStickerSet) { if (!LocaleController.isRTL) { @@ -155,7 +155,7 @@ public void buildLayout() { nameLeft = AndroidUtilities.dp(14); } if (recentMeUrl.chat_invite.chat != null) { - avatarDrawable.setInfo(recentMeUrl.chat_invite.chat); + avatarDrawable.setInfo(currentAccount, recentMeUrl.chat_invite.chat); nameString = recentMeUrl.chat_invite.chat.title; drawVerified = recentMeUrl.chat_invite.chat.verifiedExtended(); avatarImage.setForUserOrChat(recentMeUrl.chat_invite.chat, avatarDrawable, recentMeUrl); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java index 608f98cd7a..d7c0f7df52 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -139,7 +139,7 @@ public void setAccount(int account) { if (user == null) { return; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); CharSequence text = ContactsController.formatName(user.first_name, user.last_name); try { text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java index c62b1365b0..74ef91919c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java @@ -10,7 +10,6 @@ import android.widget.ImageView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java index c2f0386765..fdee387713 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java @@ -34,7 +34,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.R; -import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.voip.VoIPService; @@ -469,7 +469,7 @@ public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant group if (id > 0) { currentUser = accountInstance.getMessagesController().getUser(id); currentChat = null; - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), currentUser); nameTextView.setText(UserObject.getUserName(currentUser)); if (currentUser != null && currentUser.verifiedExtended()) { @@ -509,7 +509,7 @@ public void draw(@NonNull Canvas canvas) { } else { currentChat = accountInstance.getMessagesController().getChat(-id); currentUser = null; - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), currentChat); if (currentChat != null) { nameTextView.setText(currentChat.title); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java index bf500bcc2c..53b5ccfb31 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -321,7 +321,7 @@ public void update(int mask) { return; } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); lastStatus = currentUser.status != null ? currentUser.status.expires : 0; if (currentName != null) { @@ -374,7 +374,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentName != null) { lastName = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java index 1a254677e8..280caf3af7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java @@ -40,6 +40,7 @@ public class HintDialogCell extends FrameLayout { private TextView nameTextView; private AvatarDrawable avatarDrawable = new AvatarDrawable(); private RectF rect = new RectF(); + private Theme.ResourcesProvider resourcesProvider; private int lastUnreadCount; private TLRPC.User currentUser; @@ -53,7 +54,7 @@ public class HintDialogCell extends FrameLayout { CheckBox2 checkBox; private final boolean drawCheckbox; - public HintDialogCell(Context context, boolean drawCheckbox) { + public HintDialogCell(Context context, boolean drawCheckbox, Theme.ResourcesProvider resourcesProvider) { super(context); this.drawCheckbox = drawCheckbox; @@ -69,7 +70,7 @@ public void setText(CharSequence text, BufferType type) { } }; NotificationCenter.listenEmojiLoading(nameTextView); - nameTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + nameTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); nameTextView.setMaxLines(1); nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); @@ -77,13 +78,13 @@ public void setText(CharSequence text, BufferType type) { nameTextView.setEllipsize(TextUtils.TruncateAt.END); addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 64, 6, 0)); - counterView = new CounterView(context, null); + counterView = new CounterView(context, resourcesProvider); addView(counterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, Gravity.TOP,0 ,4,0,0)); counterView.setColors(Theme.key_chats_unreadCounterText, Theme.key_chats_unreadCounter); counterView.setGravity(Gravity.RIGHT); if (drawCheckbox) { - checkBox = new CheckBox2(context, 21); + checkBox = new CheckBox2(context, 21, resourcesProvider); checkBox.setColor(Theme.key_dialogRoundCheckBox, Theme.key_dialogBackground, Theme.key_dialogRoundCheckBoxCheck); checkBox.setDrawUnchecked(false); checkBox.setDrawBackgroundAsArc(4); @@ -131,16 +132,16 @@ public void update(int mask) { public void update() { if (DialogObject.isUserDialog(dialogId)) { currentUser = MessagesController.getInstance(currentAccount).getUser(dialogId); - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); currentUser = null; } } public void setColors(int textColorKey, int backgroundColorKey) { - nameTextView.setTextColor(Theme.getColor(textColorKey)); + nameTextView.setTextColor(Theme.getColor(textColorKey, resourcesProvider)); this.backgroundColorKey = backgroundColorKey; checkBox.setColor(Theme.key_dialogRoundCheckBox, backgroundColorKey, Theme.key_dialogRoundCheckBoxCheck); } @@ -160,7 +161,7 @@ public void setDialog(long uid, boolean counter, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); imageView.setForUserOrChat(currentUser, avatarDrawable); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); @@ -171,7 +172,7 @@ public void setDialog(long uid, boolean counter, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); currentUser = null; imageView.setForUserOrChat(chat, avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java index 5ae3384b55..671ac9bbe1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java @@ -17,7 +17,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java index 5466fc7796..2c32084f79 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java @@ -26,44 +26,39 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Stories.StoriesUtilities; public class ManageChatUserCell extends FrameLayout { - private BackupImageView avatarImageView; - private SimpleTextView nameTextView; - private SimpleTextView statusTextView; + private final BackupImageView avatarImageView; + private final SimpleTextView nameTextView; + private final SimpleTextView statusTextView; + private final Theme.ResourcesProvider resourcesProvider; + private final AvatarDrawable avatarDrawable; private ImageView optionsButton; private ImageView customImageView; - private Theme.ResourcesProvider resourcesProvider; - - private AvatarDrawable avatarDrawable; private Object currentObject; - + private TL_stories.StoryItem storyItem; private CharSequence currentName; - private CharSequence currrntStatus; - + private CharSequence currentStatus; private String lastName; private int lastStatus; private TLRPC.FileLocation lastAvatar; private boolean isAdmin; - private boolean needDivider; - private int statusColor; private int statusOnlineColor; - - private int namePadding; - - private int currentAccount = UserConfig.selectedAccount; - + private final int namePadding; private int dividerColor = -1; - private ManageChatUserCellDelegate delegate; + private final int currentAccount = UserConfig.selectedAccount; + private final StoriesUtilities.AvatarStoryParams storyAvatarParams = new StoriesUtilities.AvatarStoryParams(false); public interface ManageChatUserCellDelegate { boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click); @@ -84,7 +79,24 @@ public ManageChatUserCell(Context context, int avatarPadding, int nPadding, bool avatarDrawable = new AvatarDrawable(); - avatarImageView = new BackupImageView(context); + avatarImageView = new BackupImageView(context) { + @Override + protected void onDraw(Canvas canvas) { + if (storyItem != null) { + int pad = AndroidUtilities.dp(1); + storyAvatarParams.originalAvatarRect.set(pad, pad, getMeasuredWidth() - pad, getMeasuredHeight() - pad); + storyAvatarParams.drawSegments = false; + storyAvatarParams.animate = false; + storyAvatarParams.drawInside = true; + storyAvatarParams.isArchive = false; + storyAvatarParams.resourcesProvider = resourcesProvider; + storyAvatarParams.storyItem = storyItem; + StoriesUtilities.drawAvatarWithStory(storyItem.dialogId, canvas, imageReceiver, storyAvatarParams); + } else { + super.onDraw(canvas); + } + } + }; avatarImageView.setRoundRadius(AndroidUtilities.dp(23)); addView(avatarImageView, LayoutHelper.createFrame(46, 46, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 7 + avatarPadding, 8, LocaleController.isRTL ? 7 + avatarPadding : 0, 0)); @@ -113,6 +125,23 @@ public ManageChatUserCell(Context context, int avatarPadding, int nPadding, bool } } + public void setStoryItem(TL_stories.StoryItem storyItem, OnClickListener listener) { + this.storyItem = storyItem; + avatarImageView.setOnClickListener(listener); + } + + public TL_stories.StoryItem getStoryItem() { + return storyItem; + } + + public BackupImageView getAvatarImageView() { + return avatarImageView; + } + + public StoriesUtilities.AvatarStoryParams getStoryAvatarParams() { + return storyAvatarParams; + } + public void setCustomRightImage(int resId) { customImageView = new ImageView(getContext()); customImageView.setImageResource(resId); @@ -130,7 +159,7 @@ public void setCustomImageVisible(boolean visible) { public void setData(Object object, CharSequence name, CharSequence status, boolean divider) { if (object == null) { - currrntStatus = null; + currentStatus = null; currentName = null; currentObject = null; nameTextView.setText(""); @@ -138,7 +167,7 @@ public void setData(Object object, CharSequence name, CharSequence status, boole avatarImageView.setImageDrawable(null); return; } - currrntStatus = status; + currentStatus = status; currentName = name; currentObject = object; if (optionsButton != null) { @@ -229,7 +258,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { @@ -243,9 +272,9 @@ public void update(int mask) { lastName = newName == null ? UserObject.getUserName(currentUser) : newName; nameTextView.setText(Emoji.replaceEmoji(lastName, nameTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(15), false)); } - if (currrntStatus != null) { + if (currentStatus != null) { statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); } else { if (currentUser.bot) { statusTextView.setTextColor(statusColor); @@ -293,7 +322,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentName != null) { lastName = null; @@ -302,9 +331,9 @@ public void update(int mask) { lastName = newName == null ? currentChat.title : newName; nameTextView.setText(lastName); } - if (currrntStatus != null) { + if (currentStatus != null) { statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); } else { statusTextView.setTextColor(statusColor); if (currentChat.participants_count != 0) { @@ -326,7 +355,7 @@ public void update(int mask) { } else if (currentObject instanceof Integer) { nameTextView.setText(currentName); statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SHARES); avatarImageView.setImage(null, "50_50", avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index f13b6490b1..531142d03c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -34,11 +34,11 @@ public class MentionCell extends LinearLayout { - private BackupImageView imageView; - private TextView nameTextView; - private TextView usernameTextView; - private AvatarDrawable avatarDrawable; - private Theme.ResourcesProvider resourcesProvider; + private final BackupImageView imageView; + private final TextView nameTextView; + private final TextView usernameTextView; + private final AvatarDrawable avatarDrawable; + private final Theme.ResourcesProvider resourcesProvider; private Drawable emojiDrawable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java index 4030f5c3a0..01797c4ddb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java @@ -22,6 +22,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; @@ -88,12 +89,25 @@ public NotificationsCheckCell(Context context, int padding, int height, boolean valueTextView.setEllipsize(TextUtils.TruncateAt.END); addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 80 : (withImage ? 64 : padding), 38 - (withImage ? 2 : 0) + (currentHeight - 70) / 2, LocaleController.isRTL ? (withImage ? 64 : padding) : 80, 0)); - checkBox = new Switch(context, resourcesProvider); + checkBox = new Switch(context, resourcesProvider) { + @Override + protected int processColor(int color) { + return NotificationsCheckCell.this.processColor(color); + } + }; checkBox.setColors(Theme.key_switchTrack, Theme.key_switchTrackChecked, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhite); addView(checkBox, LayoutHelper.createFrame(37, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0)); checkBox.setFocusable(false); } + public Switch getCheckBox() { + return checkBox; + } + + protected int processColor(int color) { + return color; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isMultiline) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java index 770df1bbbf..8bfd532751 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -10,6 +10,7 @@ import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.text.Layout; @@ -37,7 +38,6 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; @@ -46,9 +46,7 @@ import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.LaunchActivity; import org.telegram.ui.NotificationsSettingsActivity; -import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoriesUtilities; import java.util.Locale; @@ -136,6 +134,13 @@ public ProfileSearchCell(Context context, Theme.ResourcesProvider resourcesProvi statusDrawable.setCallback(this); } + private boolean customPaints; + private TextPaint namePaint, statusPaint; + public ProfileSearchCell useCustomPaints() { + customPaints = true; + return this; + } + @Override protected boolean verifyDrawable(@NonNull Drawable who) { return statusDrawable == who || super.verifyDrawable(who); @@ -369,7 +374,19 @@ public void buildLayout() { nameString = LocaleController.getString("HiddenName", R.string.HiddenName); } } - if (encryptedChat != null) { + if (customPaints) { + if (namePaint == null) { + namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + namePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + namePaint.setTextSize(AndroidUtilities.dp(16)); + if (encryptedChat != null) { + namePaint.setColor(Theme.getColor(Theme.key_chats_secretName, resourcesProvider)); + } else { + namePaint.setColor(Theme.getColor(Theme.key_chats_name, resourcesProvider)); + } + currentNamePaint = namePaint; + } else if (encryptedChat != null) { currentNamePaint = Theme.dialogs_searchNameEncryptedPaint; } else { currentNamePaint = Theme.dialogs_searchNamePaint; @@ -494,6 +511,18 @@ public void buildLayout() { } nameTop = AndroidUtilities.dp(19); } + if (customPaints) { + if (statusPaint == null) { + statusPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + } + statusPaint.setTextSize(AndroidUtilities.dp(15)); + if (currentStatusPaint == Theme.dialogs_offlinePaint) { + statusPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3, resourcesProvider)); + } else if (currentStatusPaint == Theme.dialogs_onlinePaint) { + statusPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText3, resourcesProvider)); + } + currentStatusPaint = statusPaint; + } if (!TextUtils.isEmpty(statusString)) { CharSequence statusStringFinal = TextUtils.ellipsize(statusString, currentStatusPaint, statusWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); @@ -583,7 +612,7 @@ public void updateStatus(boolean verified, TLRPC.User user, boolean animated) { public void update(int mask) { TLRPC.FileLocation photo = null; if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarImage.setImage(null, null, avatarDrawable, null, null, 0); @@ -608,7 +637,7 @@ public void update(int mask) { thumb = chat.photo.strippedBitmap; } } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", thumb, chat, 0); } else if (contact != null) { avatarDrawable.setInfo(0, contact.first_name, contact.last_name); @@ -691,10 +720,17 @@ protected void onDraw(Canvas canvas) { } if (useSeparator) { + Paint dividerPaint = null; + if (customPaints && resourcesProvider != null) { + dividerPaint = resourcesProvider.getPaint(Theme.key_paint_divider); + } + if (dividerPaint == null) { + dividerPaint = Theme.dividerPaint; + } if (LocaleController.isRTL) { - canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, Theme.dividerPaint); + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, dividerPaint); } else { - canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint); + canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, dividerPaint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java index ae37d0cc64..616957c36c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java @@ -41,7 +41,6 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MessageSeenCheckDrawable; -import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.messenger.LocaleController; import org.telegram.ui.Components.StatusBadgeComponent; @@ -168,7 +167,7 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea int colorFilter = Theme.getColor(style == STYLE_STORY ? Theme.key_windowBackgroundWhiteBlackText : Theme.key_chats_verifiedBackground, resourcesProvider); statusBadgeComponent.updateDrawable(user, chat, colorFilter, false); - avatarDrawable.setInfo(u); + avatarDrawable.setInfo(currentAccount, u); if (user != null) { dialogId = user.id; titleView.setText(UserObject.getUserName(user)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java index 5b7a24cf4c..497ce21c35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java @@ -247,7 +247,7 @@ public void setSession(TLObject object, boolean divider) { nameTextView.setText(session.domain); String name; if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); name = UserObject.getFirstName(user); imageView.setForUserOrChat(user, avatarDrawable); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java index 6c5d83b3dc..694593da11 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -8,8 +8,16 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.text.Layout; import android.text.TextUtils; @@ -20,6 +28,8 @@ import android.widget.FrameLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.dynamicanimation.animation.FloatValueHolder; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; @@ -43,16 +53,24 @@ import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; public class ShareDialogCell extends FrameLayout { - private BackupImageView imageView; - private TextView nameTextView; - private SimpleTextView topicTextView; - private CheckBox2 checkBox; - private AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final BackupImageView imageView; + private final TextView nameTextView; + private final SimpleTextView topicTextView; + private final CheckBox2 checkBox; + private final AvatarDrawable avatarDrawable = new AvatarDrawable() { + @Override + public void invalidateSelf() { + super.invalidateSelf(); + imageView.invalidate(); + } + }; + private RepostStoryDrawable repostStoryDrawable; private TLRPC.User user; - private int currentType; + private final int currentType; private float onlineProgress; private long lastUpdateTime; @@ -60,7 +78,7 @@ public class ShareDialogCell extends FrameLayout { private boolean topicWasVisible; - private int currentAccount = UserConfig.selectedAccount; + private final int currentAccount = UserConfig.selectedAccount; private final Theme.ResourcesProvider resourcesProvider; public static final int TYPE_SHARE = 0; @@ -75,7 +93,7 @@ public ShareDialogCell(Context context, int type, Theme.ResourcesProvider resour currentType = type; imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(28)); + imageView.setRoundRadius(dp(28)); if (type == TYPE_CREATE) { addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); } else { @@ -85,7 +103,7 @@ public ShareDialogCell(Context context, int type, Theme.ResourcesProvider resour nameTextView = new TextView(context) { @Override public void setText(CharSequence text, BufferType type) { - text = Emoji.replaceEmoji(text, getPaint().getFontMetricsInt(), AndroidUtilities.dp(10), false); + text = Emoji.replaceEmoji(text, getPaint().getFontMetricsInt(), dp(10), false); super.setText(text, type); } }; @@ -118,18 +136,24 @@ public void setText(CharSequence text, BufferType type) { }); addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 19, currentType == TYPE_CREATE ? -40 : 42, 0, 0)); - setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); + setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), dp(2), dp(2))); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); } public void setDialog(long uid, boolean checked, CharSequence name) { - if (DialogObject.isUserDialog(uid)) { + if (uid == Long.MAX_VALUE) { + nameTextView.setText(LocaleController.getString(R.string.FwdMyStory)); + if (repostStoryDrawable == null) { + repostStoryDrawable = new RepostStoryDrawable(imageView, resourcesProvider); + } + imageView.setImage(null, null, repostStoryDrawable, null); + } else if (DialogObject.isUserDialog(uid)) { user = MessagesController.getInstance(currentAccount).getUser(uid); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (currentType != TYPE_CREATE && UserObject.isReplyUser(user)) { nameTextView.setText(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); @@ -148,7 +172,7 @@ public void setDialog(long uid, boolean checked, CharSequence name) { } imageView.setForUserOrChat(user, avatarDrawable); } - imageView.setRoundRadius(AndroidUtilities.dp(28)); + imageView.setRoundRadius(dp(28)); } else { user = null; TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); @@ -159,9 +183,9 @@ public void setDialog(long uid, boolean checked, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageView.setForUserOrChat(chat, avatarDrawable); - imageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(28)); + imageView.setRoundRadius(chat != null && chat.forum ? dp(16) : dp(28)); } currentDialog = uid; checkBox.setChecked(checked, false); @@ -202,8 +226,8 @@ public void setTopic(TLRPC.TL_forumTopic topic, boolean animate) { topicTextView.setAlpha(value); nameTextView.setAlpha(1f - value); - topicTextView.setTranslationX((1f - value) * -AndroidUtilities.dp(10)); - nameTextView.setTranslationX(value * AndroidUtilities.dp(10)); + topicTextView.setTranslationX((1f - value) * -dp(10)); + nameTextView.setTranslationX(value * dp(10)); }) .addEndListener((animation, canceled, value, velocity) -> { topicTextView.setTag(R.id.spring_tag, null); @@ -215,11 +239,11 @@ public void setTopic(TLRPC.TL_forumTopic topic, boolean animate) { topicTextView.setAlpha(1f); nameTextView.setAlpha(0f); topicTextView.setTranslationX(0); - nameTextView.setTranslationX(AndroidUtilities.dp(10)); + nameTextView.setTranslationX(dp(10)); } else { topicTextView.setAlpha(0f); nameTextView.setAlpha(1f); - topicTextView.setTranslationX(-AndroidUtilities.dp(10)); + topicTextView.setTranslationX(-dp(10)); nameTextView.setTranslationX(0); } } @@ -242,12 +266,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean isOnline = !user.self && !user.bot && (user.status != null && user.status.expires > ConnectionsManager.getInstance(currentAccount).getCurrentTime() || MessagesController.getInstance(currentAccount).onlinePrivacy.containsKey(user.id)); if (isOnline || onlineProgress != 0) { - int top = imageView.getBottom() - AndroidUtilities.dp(6); - int left = imageView.getRight() - AndroidUtilities.dp(10); + int top = imageView.getBottom() - dp(6); + int left = imageView.getRight() - dp(10); Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(currentType == TYPE_CALL ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_windowBackgroundWhite)); - canvas.drawCircle(left, top, AndroidUtilities.dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(Theme.key_chats_onlineCircle)); - canvas.drawCircle(left, top, AndroidUtilities.dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); if (isOnline) { if (onlineProgress < 1.0f) { onlineProgress += dt / 150.0f; @@ -279,7 +303,7 @@ protected void onDraw(Canvas canvas) { int cy = imageView.getTop() + imageView.getMeasuredHeight() / 2; Theme.checkboxSquare_checkPaint.setColor(getThemedColor(Theme.key_dialogRoundCheckBox)); Theme.checkboxSquare_checkPaint.setAlpha((int) (checkBox.getProgress() * 255)); - int radius = AndroidUtilities.dp(currentType == TYPE_CREATE ? 24 : 28); + int radius = dp(currentType == TYPE_CREATE ? 24 : 28); AndroidUtilities.rectTmp.set(cx - radius, cy - radius, cx + radius, cy + radius); canvas.drawRoundRect(AndroidUtilities.rectTmp, imageView.getRoundRadius()[0], imageView.getRoundRadius()[0], Theme.checkboxSquare_checkPaint); super.onDraw(canvas); @@ -296,4 +320,62 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { info.setSelected(true); } } + + private static class RepostStoryDrawable extends Drawable { + + private final LinearGradient gradient; + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final RLottieDrawable lottieDrawable; + + public RepostStoryDrawable(View view, Theme.ResourcesProvider resourcesProvider) { + gradient = new LinearGradient(0, 0, dp(56), dp(56), new int[] { + Theme.getColor(Theme.key_stories_circle1, resourcesProvider), + Theme.getColor(Theme.key_stories_circle2, resourcesProvider) + }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + paint.setShader(gradient); + + lottieDrawable = new RLottieDrawable(R.raw.story_repost, "story_repost", dp(42), dp(42), true, null); + lottieDrawable.setMasterParent(view); + AndroidUtilities.runOnUIThread(lottieDrawable::start, 450); + } + + @Override + public void draw(@NonNull Canvas canvas) { + canvas.save(); + canvas.translate(getBounds().left, getBounds().top); + canvas.drawCircle(getBounds().width() / 2f, getBounds().height() / 2f, getBounds().width() / 2f, paint); + canvas.restore(); + + AndroidUtilities.rectTmp2.set(getBounds()); + AndroidUtilities.rectTmp2.inset(dp(8), dp(8)); + lottieDrawable.setBounds(AndroidUtilities.rectTmp2); + lottieDrawable.draw(canvas); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getIntrinsicWidth() { + return dp(56); + } + + @Override + public int getIntrinsicHeight() { + return dp(56); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index 4e9c2476de..cba6cc4a72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -47,10 +47,8 @@ import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LoadingSpan; -import org.telegram.ui.Components.Paint.Views.LocationView; import org.telegram.ui.LocationActivity; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -304,14 +302,14 @@ public void setDialog(LocationActivity.LiveLocation info, Location userLocation) if (DialogObject.isUserDialog(info.id)) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(info.id); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarImageView.setForUserOrChat(user, avatarDrawable); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-info.id); if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); nameTextView.setText(chat.title); avatarImageView.setForUserOrChat(chat, avatarDrawable); } @@ -336,14 +334,14 @@ public void setDialog(LocationController.SharingLocationInfo info) { if (DialogObject.isUserDialog(info.did)) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(info.did); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarImageView.setForUserOrChat(user, avatarDrawable); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-info.did); if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); nameTextView.setText(chat.title); avatarImageView.setForUserOrChat(chat, avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java index 6360a6e0d4..f625af0896 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java @@ -1,10 +1,16 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.URLSpan; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -12,81 +18,105 @@ import android.widget.LinearLayout; import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.StatisticActivity; +import org.telegram.ui.Stories.StoriesUtilities; -public class StatisticPostInfoCell extends FrameLayout { +import java.util.Date; - private TextView message; - private TextView views; - private TextView shares; - private TextView date; - private BackupImageView imageView; - private AvatarDrawable avatarDrawable = new AvatarDrawable(); +@SuppressLint("ViewConstructor") +public class StatisticPostInfoCell extends FrameLayout { + private final BackupImageView imageView; + private final SimpleTextView message; + private final TextView views; + private final TextView shares; + private final TextView date; + private final TextView likes; + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final StoriesUtilities.AvatarStoryParams storyAvatarParams = new StoriesUtilities.AvatarStoryParams(false); + private final Theme.ResourcesProvider resourcesProvider; + private StatisticActivity.RecentPostInfo postInfo; private final TLRPC.ChatFull chat; + private boolean needDivider; - public StatisticPostInfoCell(Context context, TLRPC.ChatFull chat) { + public StatisticPostInfoCell(Context context, TLRPC.ChatFull chat, Theme.ResourcesProvider resourcesProvider) { super(context); this.chat = chat; - imageView = new BackupImageView(context); - addView(imageView, LayoutHelper.createFrame(46, 46, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 16, 0)); + this.resourcesProvider = resourcesProvider; + imageView = new BackupImageView(context) { + @Override + protected void onDraw(Canvas canvas) { + if (postInfo != null && postInfo.isStory()) { + int pad = AndroidUtilities.dp(1); + storyAvatarParams.originalAvatarRect.set(pad, pad, getMeasuredWidth() - pad, getMeasuredHeight() - pad); + storyAvatarParams.drawSegments = false; + storyAvatarParams.animate = false; + storyAvatarParams.drawInside = true; + storyAvatarParams.isArchive = false; + storyAvatarParams.forceState = StoriesUtilities.STATE_HAS_UNREAD; + storyAvatarParams.resourcesProvider = resourcesProvider; + StoriesUtilities.drawAvatarWithStory(0, canvas, imageReceiver, storyAvatarParams); + } else { + super.onDraw(canvas); + } + } + }; + setClipChildren(false); + addView(imageView, LayoutHelper.createFrame(46, 46, (!LocaleController.isRTL ? Gravity.START : Gravity.END) | Gravity.CENTER_VERTICAL, !LocaleController.isRTL ? 12 : 16, 0, !LocaleController.isRTL ? 16 : 12, 0)); LinearLayout contentLayout = new LinearLayout(context); contentLayout.setOrientation(LinearLayout.VERTICAL); LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); - message = new TextView(context) { - AnimatedEmojiSpan.EmojiGroupedSpans stack; - @Override - public void setText(CharSequence text, BufferType type) { - super.setText(text, type); - stack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, stack, getLayout()); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - stack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, stack, getLayout()); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - AnimatedEmojiSpan.release(this, stack); - } - + message = new SimpleTextView(context) { @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, getLayout(), stack, 0, null, 0, 0, 0, 1f); + public boolean setText(CharSequence value) { + value = Emoji.replaceEmoji(value, getPaint().getFontMetricsInt(), false); + return super.setText(value); } }; - message.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - message.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + NotificationCenter.listenEmojiLoading(message); + message.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + message.setTextSize(16); + message.setMaxLines(1); message.setTextColor(Color.BLACK); - message.setLines(1); - message.setEllipsize(TextUtils.TruncateAt.END); - + message.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); views = new TextView(context); - views.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + views.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); views.setTextColor(Color.BLACK); + if (!LocaleController.isRTL) { + linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 16, 0)); + linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + } else { + linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 16, 0, 0, 0)); + } - linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 16, 0)); - linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); - contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 8, 0, 0)); + contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 7, 0, 0)); date = new TextView(context); date.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); @@ -97,47 +127,139 @@ protected void onDraw(Canvas canvas) { shares = new TextView(context); shares.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); shares.setTextColor(Color.BLACK); + shares.setGravity(Gravity.CENTER_VERTICAL); + + likes = new TextView(context); + likes.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + likes.setTextColor(Color.BLACK); + likes.setGravity(Gravity.CENTER_VERTICAL); linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); - linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 8, 0)); - linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); - contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 2, 0, 8)); + if (!LocaleController.isRTL) { + linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 8, 0)); + linearLayout.addView(likes, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 10, 0, 0, 0)); + } else { + linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); + linearLayout.addView(likes, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 8, 0, 0, 0)); + } + + contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 3, 0, 9)); - addView(contentLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.NO_GRAVITY, 72, 0, 12, 0)); + addView(contentLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.NO_GRAVITY, !LocaleController.isRTL ? 72 : 18, 0, !LocaleController.isRTL ? 18 : 72, 0)); message.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); views.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); date.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); shares.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + likes.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + Drawable likesDrawable = ContextCompat.getDrawable(context, R.drawable.mini_stats_likes).mutate(); + DrawableCompat.setTint(likesDrawable, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + Drawable sharesDrawable = ContextCompat.getDrawable(context, R.drawable.mini_stats_shares).mutate(); + DrawableCompat.setTint(sharesDrawable, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + + CombinedDrawable likesCombinedDrawable = new CombinedDrawable(null, likesDrawable, 0, dp(1)); + likesCombinedDrawable.setCustomSize(sharesDrawable.getIntrinsicWidth(), sharesDrawable.getIntrinsicHeight()); + likes.setCompoundDrawablesWithIntrinsicBounds(likesCombinedDrawable, null, null, null); + likes.setCompoundDrawablePadding(dp(2)); + + CombinedDrawable sharesCombinedDrawable = new CombinedDrawable(null, sharesDrawable, 0, dp(1)); + sharesCombinedDrawable.setCustomSize(sharesDrawable.getIntrinsicWidth(), sharesDrawable.getIntrinsicHeight()); + shares.setCompoundDrawablesWithIntrinsicBounds(sharesCombinedDrawable, null, null, null); + shares.setCompoundDrawablePadding(dp(2)); + setWillNotDraw(false); + } + + public BackupImageView getImageView() { + return imageView; + } + + public StoriesUtilities.AvatarStoryParams getStoryAvatarParams() { + return storyAvatarParams; + } + + public StatisticActivity.RecentPostInfo getPostInfo() { + return postInfo; } - public void setData(StatisticActivity.RecentPostInfo postInfo) { + public void setImageViewAction(View.OnClickListener action){ + imageView.setOnClickListener(action); + } + + public void setData(StatisticActivity.RecentPostInfo postInfo, boolean isLast) { + this.postInfo = postInfo; + this.needDivider = !isLast; MessageObject messageObject = postInfo.message; if (messageObject.photoThumbs != null) { TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs,50); + TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); imageView.setImage( ImageLocation.getForObject(size, messageObject.photoThumbsObject), "50_50", ImageLocation.getForObject(thumbSize, messageObject.photoThumbsObject), "b1", 0, messageObject); - imageView.setRoundRadius(AndroidUtilities.dp(4)); + imageView.setRoundRadius(AndroidUtilities.dp(9)); + imageView.setScaleX(0.96f); + imageView.setScaleY(0.96f); } else if (chat.chat_photo.sizes.size() > 0) { imageView.setImage(ImageLocation.getForPhoto(chat.chat_photo.sizes.get(0), chat.chat_photo), "50_50", null, null, chat); imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); + imageView.setScaleX(0.96f); + imageView.setScaleY(0.96f); + } else { + TLRPC.Chat currentChat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(chat.id); + avatarDrawable.setInfo(currentChat); + imageView.setForUserOrChat(currentChat, avatarDrawable); + imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); + imageView.setScaleX(1f); + imageView.setScaleY(1f); + } + if (messageObject.isStory()) { + imageView.setScaleX(1f); + imageView.setScaleY(1f); + imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); } - CharSequence text; if (messageObject.isMusic()) { text = String.format("%s, %s", messageObject.getMusicTitle().trim(), messageObject.getMusicAuthor().trim()); + } else if (messageObject.isStory()) { + text = LocaleController.getString("Story", R.string.Story); } else { text = messageObject.caption != null ? messageObject.caption : messageObject.messageText; } + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text == null ? "" : text); + URLSpan[] urlSpans = stringBuilder.getSpans(0, stringBuilder.length(), URLSpan.class); + for (URLSpan urlSpan : urlSpans) { + stringBuilder.removeSpan(urlSpan); + } + message.setText(AndroidUtilities.trim(AndroidUtilities.replaceNewLines(stringBuilder), null)); + views.setText(String.format(LocaleController.getPluralString("Views", postInfo.getViews()), AndroidUtilities.formatWholeNumber(postInfo.getViews(), 0))); + + Date time = new Date(postInfo.getDate() * 1000L); + String monthTxt = LocaleController.getInstance().formatterYear.format(time); + String timeTxt = LocaleController.getInstance().formatterDay.format(time); + date.setText(LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, monthTxt, timeTxt)); - message.setText(AndroidUtilities.trim(AndroidUtilities.replaceNewLines(new SpannableStringBuilder(text)), null)); - views.setText(String.format(LocaleController.getPluralString("Views", postInfo.counters.views), AndroidUtilities.formatCount(postInfo.counters.views))); - date.setText(LocaleController.formatDateAudio(postInfo.message.messageOwner.date, false)); - shares.setText(String.format(LocaleController.getPluralString("Shares", postInfo.counters.forwards), AndroidUtilities.formatCount(postInfo.counters.forwards))); + shares.setText(AndroidUtilities.formatWholeNumber(postInfo.getForwards(), 0)); + likes.setText(AndroidUtilities.formatWholeNumber(postInfo.getReactions(), 0)); + shares.setVisibility(postInfo.getForwards() != 0 ? VISIBLE : GONE); + likes.setVisibility(postInfo.getReactions() != 0 ? VISIBLE : GONE); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (needDivider) { + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + int paddingDp = 72; + if (LocaleController.isRTL) { + canvas.drawRect(0, getHeight() - 1, getWidth() - dp(paddingDp), getHeight(), dividerPaint); + } else { + canvas.drawRect(dp(paddingDp), getHeight() - 1, getWidth(), getHeight(), dividerPaint); + } + } } public void setData(StatisticActivity.MemberData memberData) { @@ -149,5 +271,12 @@ public void setData(StatisticActivity.MemberData memberData) { views.setVisibility(View.GONE); shares.setVisibility(View.GONE); + likes.setVisibility(View.GONE); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + storyAvatarParams.onDetachFromWindow(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index 28dca70384..c1427801d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -15,6 +15,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.view.Gravity; import android.view.View; @@ -31,6 +32,7 @@ import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.Switch; +import org.telegram.ui.FilterCreateActivity; public class TextCell extends FrameLayout { @@ -255,11 +257,26 @@ public void setTextColor(int color) { textView.setTextColor(color); } + protected int processColor(int color) { + return color; + } + + public void updateColors() { + int textKey = textView.getTag() instanceof Integer ? (int) textView.getTag() : Theme.key_windowBackgroundWhiteBlackText; + textView.setTextColor(processColor(Theme.getColor(textKey, resourcesProvider))); + if (imageView.getTag() instanceof Integer) { + imageView.setColorFilter(new PorterDuffColorFilter(processColor(Theme.getColor((int) imageView.getTag(), resourcesProvider)), PorterDuff.Mode.MULTIPLY)); + } + subtitleView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider))); + valueTextView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText, resourcesProvider))); + valueSpoilersTextView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText, resourcesProvider))); + } + public void setColors(int icon, int text) { - textView.setTextColor(Theme.getColor(text, resourcesProvider)); + textView.setTextColor(processColor(Theme.getColor(text, resourcesProvider))); textView.setTag(text); if (icon >= 0) { - imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(icon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + imageView.setColorFilter(new PorterDuffColorFilter(processColor(Theme.getColor(icon, resourcesProvider)), PorterDuff.Mode.MULTIPLY)); imageView.setTag(icon); } } @@ -432,6 +449,15 @@ public void setTextAndValueAndIcon(CharSequence text, String value, boolean anim } } + public static CharSequence applyNewSpan(String str) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + spannableStringBuilder.append(" d"); + FilterCreateActivity.NewSpan span = new FilterCreateActivity.NewSpan(10); + span.setColor(Theme.getColor(Theme.key_premiumGradient1)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + return spannableStringBuilder; + } + public void setColorfulIcon(int color, int resId) { offsetFromImage = getOffsetFromImage(true); imageView.setVisibility(VISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java index 21fed2c04c..1162db5136 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java @@ -36,7 +36,7 @@ public class TextDetailCell extends FrameLayout { private final TextView textView; - private final LinkSpanDrawable.LinksTextView valueTextView; + public final LinkSpanDrawable.LinksTextView valueTextView; private final TextView showMoreTextView = null; private final ImageView imageView; private boolean needDivider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java index 39fcda2577..8294b7c2ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java @@ -72,8 +72,12 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t this(context, layout, type, 0); } - @SuppressLint("ClickableViewAccessibility") public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int type, long dialogId) { + this(context, layout, type, dialogId, null); + } + + @SuppressLint("ClickableViewAccessibility") + public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int type, long dialogId, Theme.ResourcesProvider resourcesProvider) { super(context); this.type = type; int currentAccount = UserConfig.selectedAccount; @@ -83,7 +87,7 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t setOrientation(LinearLayout.VERTICAL); setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11)); - shadowDrawable = Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + shadowDrawable = Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow, resourcesProvider); int date = (int) (System.currentTimeMillis() / 1000) - 60 * 60; @@ -92,10 +96,6 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t if (type == TYPE_PEER_COLOR) { final boolean isChannel = dialogId < 0; - ChatActionCell actionCell = new ChatActionCell(context); - actionCell.setCustomText(LocaleController.getString(R.string.UserColorPreviewTitle)); - addView(actionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 2, 0, 5)); - TLRPC.Message message = new TLRPC.TL_message(); message.message = LocaleController.getString(isChannel ? R.string.ChannelColorPreview : R.string.UserColorPreview); message.reply_to = new TLRPC.TL_messageReplyHeader(); @@ -277,7 +277,7 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t } for (int a = 0; a < cells.length; a++) { - cells[a] = new ChatMessageCell(context) { + cells[a] = new ChatMessageCell(context, false, null, resourcesProvider) { private GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { @@ -340,12 +340,15 @@ protected void dispatchDraw(Canvas canvas) { if (getMessageObject() != null && getMessageObject().overrideLinkColor >= 0) { final int colorId = getMessageObject().overrideLinkColor; final int color1, color2; - if (colorId >= 14) { + if (getMessageObject().overrideProfilePeerColor != null) { + color1 = getMessageObject().overrideProfilePeerColor.getAvatarColor1(); + color2 = getMessageObject().overrideProfilePeerColor.getAvatarColor2(); + } else if (colorId >= 14) { MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); MessagesController.PeerColors peerColors = messagesController != null ? messagesController.peerColors : null; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - final int peerColorValue = messagesController.peerColors.getColor(colorId).getColor1(); + final int peerColorValue = peerColor.getColor1(); color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getPeerColorIndex(peerColorValue)]); color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getPeerColorIndex(peerColorValue)]); } else { @@ -437,9 +440,16 @@ public void invalidate() { } } + private Drawable overrideDrawable; + public void setOverrideBackground(Drawable drawable) { + overrideDrawable = drawable; + invalidate(); + } + + @Override protected void onDraw(Canvas canvas) { - Drawable newDrawable = Theme.getCachedWallpaperNonBlocking(); + Drawable newDrawable = overrideDrawable != null ? overrideDrawable : Theme.getCachedWallpaperNonBlocking(); if (Theme.wallpaperLoadTask != null) { invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 1a298c6b48..a22f16ffe6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -525,14 +525,14 @@ public void update(int mask) { ((LayoutParams) nameTextView.getLayoutParams()).topMargin = AndroidUtilities.dp(19); return; } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } else if (currentName != null) { avatarDrawable.setInfo(currentId, currentName.toString(), null); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java index 56a646e958..f20b89bf65 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java @@ -229,14 +229,14 @@ public void update(int mask) { lastAvatar = photo; if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } else if (currentName != null) { avatarDrawable.setInfo(currentId, currentName.toString(), null); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index 8874f08f2e..58634b49c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2087,6 +2087,9 @@ private void updateMessagesVisiblePart() { } else if (view instanceof ChatActionCell) { ChatActionCell cell = (ChatActionCell) view; cell.setVisiblePart(view.getY() + actionBar.getMeasuredHeight() - contentView.getBackgroundTranslationY(), contentView.getBackgroundSizeY()); + if (cell.hasGradientService()) { + cell.invalidate(); + } } if (view.getBottom() <= chatListView.getPaddingTop()) { continue; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java index b2bfc7ce67..cc0da46303 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java @@ -65,6 +65,7 @@ public abstract class BaseChartView private final static int BOTTOM_SIGNATURE_OFFSET = AndroidUtilities.dp(10); private final static int DP_12 = AndroidUtilities.dp(12); + private final static int DP_8 = AndroidUtilities.dp(8); private final static int DP_6 = AndroidUtilities.dp(6); private final static int DP_5 = AndroidUtilities.dp(5); private final static int DP_2 = AndroidUtilities.dp(2); @@ -226,9 +227,15 @@ public void onAnimationEnd(Animator animation) { private float startFromMaxH; private float startFromMinH; private float minMaxUpdateStep; + protected Theme.ResourcesProvider resourcesProvider; public BaseChartView(Context context) { + this(context, null); + } + + public BaseChartView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + this.resourcesProvider = resourcesProvider; init(); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @@ -262,23 +269,23 @@ protected void init() { } protected LegendSignatureView createLegendView() { - return new LegendSignatureView(getContext()); + return new LegendSignatureView(getContext(), resourcesProvider); } public void updateColors() { if (useAlphaSignature) { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignatureAlpha)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignatureAlpha, resourcesProvider)); } else { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); } - bottomSignaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); - linePaint.setColor(Theme.getColor(Theme.key_statisticChartHintLine)); - selectedLinePaint.setColor(Theme.getColor(Theme.key_statisticChartActiveLine)); - pickerSelectorPaint.setColor(Theme.getColor(Theme.key_statisticChartActivePickerChart)); - unactiveBottomChartPaint.setColor(Theme.getColor(Theme.key_statisticChartInactivePickerChart)); - selectionBackgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ripplePaint.setColor(Theme.getColor(Theme.key_statisticChartRipple)); + bottomSignaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); + linePaint.setColor(Theme.getColor(Theme.key_statisticChartHintLine, resourcesProvider)); + selectedLinePaint.setColor(Theme.getColor(Theme.key_statisticChartActiveLine, resourcesProvider)); + pickerSelectorPaint.setColor(Theme.getColor(Theme.key_statisticChartActivePickerChart, resourcesProvider)); + unactiveBottomChartPaint.setColor(Theme.getColor(Theme.key_statisticChartInactivePickerChart, resourcesProvider)); + selectionBackgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + ripplePaint.setColor(Theme.getColor(Theme.key_statisticChartRipple, resourcesProvider)); legendSignatureView.recolor(); hintLinePaintAlpha = linePaint.getAlpha(); @@ -729,13 +736,13 @@ HORIZONTAL_PADDING, getMeasuredHeight() - PICKER_PADDING - pikerHeight, canvas.drawPath(RoundedRect(pathTmp, pickerRect.left, pickerRect.top - DP_1, pickerRect.left + DP_12, - pickerRect.bottom + DP_1, DP_6, DP_6, + pickerRect.bottom + DP_1, DP_8, DP_8, true, false, false, true), pickerSelectorPaint); canvas.drawPath(RoundedRect(pathTmp, pickerRect.right - DP_12, pickerRect.top - DP_1, pickerRect.right, - pickerRect.bottom + DP_1, DP_6, DP_6, + pickerRect.bottom + DP_1, DP_8, DP_8, false, true, true, false), pickerSelectorPaint); canvas.drawRect(pickerRect.left + DP_12, @@ -1592,10 +1599,16 @@ public static class SharedUiComponents { private RectF rectF = new RectF(); private Paint xRefP = new Paint(Paint.ANTI_ALIAS_FLAG); + private Theme.ResourcesProvider resourcesProvider; public SharedUiComponents() { + this(null); + } + + public SharedUiComponents(Theme.ResourcesProvider resourcesProvider) { xRefP.setColor(0); xRefP.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + this.resourcesProvider = resourcesProvider; } int k = 0; @@ -1609,8 +1622,8 @@ Bitmap getPickerMaskBitmap(int h, int w) { canvas = new Canvas(pickerRoundBitmap); rectF.set(0, 0, w, h); - canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), xRefP); + canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(6), AndroidUtilities.dp(6), xRefP); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java index 1a360db042..a604d66c0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java @@ -14,7 +14,11 @@ public class DoubleLinearChartView extends BaseChartView { public DoubleLinearChartView(Context context) { - super(context); + this(context, null); + } + + public DoubleLinearChartView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); } @Override @@ -240,7 +244,7 @@ protected void drawSignaturesToHorizontalLines(Canvas canvas, ChartHorizontalLin int y = (int) ((getMeasuredHeight() - chartBottom) - chartHeight * ((a.values[i] - currentMinHeight) / (currentMaxHeight - currentMinHeight))); if (a.valuesStr != null && lines.size() > 0) { if (a.valuesStr2 == null || lines.size() < 2) { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); signaturePaint.setAlpha((int) (a.alpha * signaturePaintAlpha * transitionAlpha * additionalOutAlpha)); } else { signaturePaint.setColor(lines.get(leftIndex).lineColor); @@ -259,7 +263,7 @@ protected void drawSignaturesToHorizontalLines(Canvas canvas, ChartHorizontalLin @Override public LineViewData createLineViewData(ChartData.Line line) { - return new LineViewData(line); + return new LineViewData(line, resourcesProvider); } public int findMaxValue(int startXIndex, int endXIndex) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java index d772343b09..a131107e60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java @@ -8,6 +8,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.SegmentTree; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Charts.data.ChartData; import org.telegram.ui.Charts.data.StackBarChartData; import org.telegram.ui.Charts.view_data.LineViewData; @@ -18,14 +19,18 @@ public class StackBarChartView extends BaseChartView { datesTmp.setPivotX(datesTmp.getMeasuredWidth() * 0.7f); @@ -87,11 +93,11 @@ public ChartHeaderView(Context context) { public void recolor() { - title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - dates.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - datesTmp.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - back.setTextColor(Theme.getColor(Theme.key_statisticChartBackZoomColor)); - zoomIcon.setColorFilter(Theme.getColor(Theme.key_statisticChartBackZoomColor), PorterDuff.Mode.SRC_IN); + title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + dates.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + datesTmp.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + back.setTextColor(Theme.getColor(Theme.key_statisticChartBackZoomColor, resourcesProvider)); + zoomIcon.setColorFilter(Theme.getColor(Theme.key_statisticChartBackZoomColor, resourcesProvider), PorterDuff.Mode.SRC_IN); } public void setDates(long start, long end) { @@ -105,9 +111,9 @@ public void setDates(long start, long end) { } final String newText; if (end - start >= 86400000L) { - newText = formatter.format(new Date(start)) + " — " + formatter.format(new Date(end)); + newText = LocaleController.getInstance().formatterYear.format(new Date(start)) + " — " + LocaleController.getInstance().formatterYear.format(new Date(end)); } else { - newText = formatter.format(new Date(start)); + newText = LocaleController.getInstance().formatterYear.format(new Date(start)); } dates.setText(newText); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java index c1091e04c6..056965b8cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java @@ -56,6 +56,7 @@ public class LegendSignatureView extends FrameLayout { Drawable shadowDrawable; Drawable backgroundDrawable; + private Theme.ResourcesProvider resourcesProvider; Runnable showProgressRunnable = new Runnable() { @Override @@ -72,7 +73,12 @@ public void run() { }; public LegendSignatureView(Context context) { + this(context, null); + } + + public LegendSignatureView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + this.resourcesProvider = resourcesProvider; setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); content = new LinearLayout(getContext()); content.setOrientation(LinearLayout.VERTICAL); @@ -102,13 +108,13 @@ public LegendSignatureView(Context context) { } public void recolor() { - time.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - hourTime.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - chevron.setColorFilter(Theme.getColor(Theme.key_statisticChartChevronColor)); - progressView.setProgressColor(Theme.getColor(Theme.key_statisticChartChevronColor)); + time.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + hourTime.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + chevron.setColorFilter(Theme.getColor(Theme.key_statisticChartChevronColor, resourcesProvider)); + progressView.setProgressColor(Theme.getColor(Theme.key_statisticChartChevronColor, resourcesProvider)); shadowDrawable = getContext().getResources().getDrawable(R.drawable.stats_tooltip).mutate(); - backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_dialogBackground), Theme.getColor(Theme.key_listSelector), 0xff000000); + backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_dialogBackground, resourcesProvider), Theme.getColor(Theme.key_listSelector, resourcesProvider), 0xff000000); CombinedDrawable drawable = new CombinedDrawable(shadowDrawable, backgroundDrawable, AndroidUtilities.dp(3), AndroidUtilities.dp(3)); drawable.setFullsize(true); setBackground(drawable); @@ -169,15 +175,15 @@ public void setData(int index, long date, ArrayList lines, boolean h.value.setText(formatWholeNumber(l.y[index])); h.signature.setText(l.name); if (l.colorKey >= 0 && Theme.hasThemeKey(l.colorKey)) { - h.value.setTextColor(Theme.getColor(l.colorKey)); + h.value.setTextColor(Theme.getColor(l.colorKey, resourcesProvider)); } else { h.value.setTextColor(Theme.getCurrentTheme().isDark() ? l.colorDark : l.color); } - h.signature.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + h.signature.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); if (showPercentage && h.percentage != null) { h.percentage.setVisibility(VISIBLE); - h.percentage.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + h.percentage.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); float v = lines.get(i).line.y[index] / (float) sum; if (v < 0.1f && v != 0f) { h.percentage.setText(String.format(Locale.ENGLISH, "%.1f%s", (100f * v), "%")); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java index 7c81692e8b..0d1f7256a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java @@ -35,7 +35,14 @@ public class LineViewData { public float alpha = 1f; + private Theme.ResourcesProvider resourcesProvider; + public LineViewData(ChartData.Line line) { + this(line, null); + } + + public LineViewData(ChartData.Line line, Theme.ResourcesProvider resourcesProvider) { + this.resourcesProvider = resourcesProvider; this.line = line; paint.setStrokeWidth(AndroidUtilities.dpf2(2)); @@ -61,9 +68,9 @@ public LineViewData(ChartData.Line line) { public void updateColors() { if (line.colorKey >= 0 && Theme.hasThemeKey(line.colorKey)) { - lineColor = Theme.getColor(line.colorKey); + lineColor = Theme.getColor(line.colorKey, resourcesProvider); } else { - int color = Theme.getColor(Theme.key_windowBackgroundWhite); + int color = Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider); boolean darkBackground = ColorUtils.calculateLuminance(color) < 0.5f; lineColor = darkBackground ? line.colorDark : line.color; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java index 62b09d71ec..9ca28a2c4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java @@ -13,13 +13,20 @@ public class StackBarViewData extends LineViewData { public final Paint unselectedPaint = new Paint(); public int blendColor = 0; + private Theme.ResourcesProvider resourcesProvider; + public void updateColors() { super.updateColors(); - blendColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhite),lineColor,0.3f); + blendColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider),lineColor,0.3f); } public StackBarViewData(ChartData.Line line) { + this(line, null); + } + + public StackBarViewData(ChartData.Line line, Theme.ResourcesProvider resourcesProvider) { super(line); + this.resourcesProvider = resourcesProvider; paint.setStrokeWidth(AndroidUtilities.dpf2(1)); paint.setStyle(Paint.Style.STROKE); unselectedPaint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 331277fe5c..d0044d2d58 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -8,6 +8,8 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -48,6 +50,7 @@ import android.graphics.Region; import android.graphics.Shader; import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -266,6 +269,7 @@ import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.MentionsContainerView; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MessageContainsEmojiButton; @@ -821,7 +825,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean[] cacheEndReached = new boolean[2]; private boolean[] forwardEndReached = new boolean[]{true, true}; private boolean hideForwardEndReached; - private boolean loading; + private boolean loading = true; private boolean firstLoading = true; private boolean chatWasReset; private boolean firstUnreadSent; @@ -897,6 +901,7 @@ public int getColor(int key) { public int highlightMessageId = Integer.MAX_VALUE; public boolean showNoQuoteAlert; public String highlightMessageQuote; + public int highlightMessageQuoteOffset = -1; private int scrollToMessagePosition = -10000; private Runnable unselectRunnable; @@ -1012,6 +1017,7 @@ public void run() { private int contentPaddingTop; private float contentPanTranslation; + private float contentPanTranslationT; private float floatingDateViewOffset; private float topChatPanelViewOffset; private float pinnedMessageEnterOffset; @@ -1242,6 +1248,10 @@ public int getTopicId() { return isTopic ? threadMessageId : 0; } + public boolean isForumInViewAsMessagesMode() { + return ChatObject.isForum(currentChat) && !isTopic; + } + @Override public List onGetDebugItems() { List items = new ArrayList<>(); @@ -1492,7 +1502,7 @@ public boolean onItemClick(View view, int position, float x, float y) { } processRowSelect(view, outside, x, y); } - if (view instanceof ChatMessageCell) { + if (view instanceof ChatMessageCell && (((ChatMessageCell) view).getMessageObject() != null && ((ChatMessageCell) view).getMessageObject().type != MessageObject.TYPE_JOINED_CHANNEL)) { startMultiselect(position); result = true; } @@ -1639,6 +1649,19 @@ public void onItemClick(View view, int position, float x, float y) { processRowSelect(view, outside, x, y); return; } + if (view instanceof ChatMessageCell) { + MessageObject msg = ((ChatMessageCell) view).getMessageObject(); + if (msg != null && msg.type == MessageObject.TYPE_JOINED_CHANNEL) { + msg.toggleChannelRecommendations(); + msg.forceUpdate = true; + ((ChatMessageCell) view).forceResetMessageObject(); + view.requestLayout(); + if (position >= 0) { + chatAdapter.notifyItemChanged(position); + } + return; + } + } createMenu(view, true, false, x, y); } @@ -1720,10 +1743,23 @@ public void onDoubleTap(View view, int position, float x, float y) { return; } if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SHOW_REACTIONS) { - if (isSecretChat() || isInScheduleMode()) { + ChatMessageCell cell = (ChatMessageCell) view; + MessageObject primaryMessage = cell.getPrimaryMessageObject(); + if (primaryMessage.isSecretMedia() || primaryMessage.isExpiredStory() || primaryMessage.type == MessageObject.TYPE_JOINED_CHANNEL) { return; } - createMenu(view, true, false, x, y, true, true); + ReactionsEffectOverlay.removeCurrent(false); + String reactionString = getMediaDataController().getDoubleTapReaction(); + if (reactionString.startsWith("animated_")) { + boolean available = dialog_id >= 0; + if (!available && chatInfo != null) { + available = ChatObject.reactionIsAvailable(chatInfo, reactionString); + } + if (!available) { + return; + } + createMenu(view, true, false, x, y, true, true); + } } else if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SEND_REACTIONS) { if (isSecretChat() || isInScheduleMode()) { return; @@ -1868,7 +1904,7 @@ public void onMessageSend(CharSequence message, boolean notify, int scheduleDate chatActivityEnterView.getEmojiView().onMessageSend(); } - if (!getMessagesController().premiumLocked && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && !TextUtils.isEmpty(message) && messages != null) { + if (!getMessagesController().premiumLocked && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && !TextUtils.isEmpty(message) && messages != null) { for (int i = 1; i < Math.min(5, messages.size()); ++i) { MessageObject msg = messages.get(i); if (msg != null && !msg.isOutOwner() && (msg.isVoice() || msg.isRoundVideo()) && msg.isContentUnread()) { @@ -2625,6 +2661,8 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messageTranslating); getNotificationCenter().addObserver(this, NotificationCenter.onReceivedChannelDifference); getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); + getNotificationCenter().addObserver(this, NotificationCenter.updateTranscriptionLock); super.onFragmentCreate(); @@ -2992,6 +3030,8 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslating); getNotificationCenter().removeObserver(this, NotificationCenter.onReceivedChannelDifference); getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); + getNotificationCenter().removeObserver(this, NotificationCenter.updateTranscriptionLock); if (currentEncryptedChat != null) { getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } @@ -3267,6 +3307,7 @@ public void onItemClick(final int id) { } } } else if (id == view_as_topics) { + getMessagesController().getTopicsController().toggleViewForumAsMessages(-dialog_id, false); TopicsFragment.prepareToSwitchAnimation(ChatActivity.this); } else if (id == copy) { SpannableStringBuilder str = new SpannableStringBuilder(); @@ -4376,18 +4417,12 @@ private void processTouchEvent(MotionEvent e) { } slidingView = (ChatMessageCell) view; MessageObject message = slidingView.getMessageObject(); - boolean allowReplyOnOpenTopic = false; - if (message != null && ChatObject.isForum(currentChat)) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, MessageObject.getTopicId(message.messageOwner, true)); - if (topic != null) { - allowReplyOnOpenTopic = !topic.closed || ChatObject.canManageTopic(currentAccount, currentChat, topic); - } - } + boolean allowReplyOnOpenTopic = canSendMessageToTopic(message); if (chatMode != 0 || threadMessageObjects != null && threadMessageObjects.contains(message) || getMessageType(message) == 1 && (message.getDialogId() == mergeDialogId || message.needDrawBluredPreview()) || currentEncryptedChat == null && message.getId() < 0 || bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE && !(bottomOverlayChatWaitsReply && allowReplyOnOpenTopic || message.wasJustSent) || - currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat)) || + currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat) || (ChatObject.isForum(currentChat) && !allowReplyOnOpenTopic)) || textSelectionHelper.isInSelectionMode()) { if (!canSendInCommentGroup()) { slidingView.setSlidingOffset(0); @@ -4746,8 +4781,12 @@ public void draw(Canvas canvas) { int alpha = skeletonPaint.getAlpha(); int wasServiceAlpha = skeletonServicePaint.getAlpha(); int wasOutlineAlpha = skeletonOutlinePaint.getAlpha(); - skeletonServicePaint.setAlpha((int) (0xFF * topSkeletonAlpha)); - skeletonPaint.setAlpha((int) (topSkeletonAlpha * alpha)); + float adaptDark = 1f; + if (themeDelegate != null && themeDelegate.isDark && skeletonServicePaint.getShader() != null) { + adaptDark *= .3f; + } + skeletonServicePaint.setAlpha((int) (0xFF * topSkeletonAlpha * adaptDark)); + skeletonPaint.setAlpha((int) (topSkeletonAlpha * adaptDark * alpha)); skeletonOutlinePaint.setAlpha((int) (topSkeletonAlpha * alpha)); while (lastTop > blurredViewTopOffset) { lastTop -= AndroidUtilities.dp(3f); @@ -6104,8 +6143,29 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { progressView.setVisibility(View.INVISIBLE); contentView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); - progressView2 = new View(context); - progressView2.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(18), progressView2, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); + progressView2 = new View(context) { + private final RectF rect = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + applyServiceShaderMatrix(); + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackground)); + if (themeDelegate != null ? themeDelegate.hasGradientService() : Theme.hasGradientService()) { + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + super.dispatchDraw(canvas); + } + public void applyServiceShaderMatrix() { + applyServiceShaderMatrix(getMeasuredWidth(), getServiceHeight(this), getX(), getServiceTop(this)); + } + private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, float x, float viewTop) { + if (themeDelegate != null) { + themeDelegate.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } else { + Theme.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } + } + }; progressView.addView(progressView2, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); progressBar = new RadialProgressView(context, themeDelegate); @@ -6114,6 +6174,10 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { progressView.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); floatingDateView = new ChatActionCell(context, false, themeDelegate) { + @Override + public boolean isFloating() { + return true; + } @Override public void setTranslationY(float translationY) { @@ -10222,7 +10286,7 @@ public void processInlineBotWebView(TLRPC.TL_inlineBotWebView object) { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), getResourceProvider()); webViewSheet.setParentActivity(getParentActivity()); webViewSheet.requestWebView(currentAccount, currentUser != null ? currentUser.id : currentChat.id, mentionContainer.getAdapter().getFoundContextBot().id, object.text, object.url, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, BotWebViewSheet.FLAG_FROM_INLINE_SWITCH); - webViewSheet.show(); + showDialog(webViewSheet); }; if (approved) { open.run(); @@ -12010,11 +12074,11 @@ private ReplyQuote(long peerId, @NonNull MessageObject message, int start, int e update(); } - public static ReplyQuote from(MessageObject messageObject, String text) { + public static ReplyQuote from(MessageObject messageObject, String text, int offset) { if (messageObject == null || messageObject.messageOwner == null || messageObject.messageOwner.message == null || text == null) { return null; } - int start = messageObject.messageOwner.message.indexOf(text); + int start = MessageObject.findQuoteStart(messageObject.messageOwner.message, text, offset); if (start < 0) { return null; } @@ -12322,12 +12386,27 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes } } else if (messageObjectToReply != null) { editingMessageObject = null; + + // set it for a case when replying in in View as messages mode + MessageObject topicTopMessageObject = null; + if (isForumInViewAsMessagesMode()) { + int topicId = MessageObject.getTopicId(messageObjectToReply.messageOwner, true); + if (topicId != 0) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null && topic.topicStartMessage != null) { + topicTopMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, false, false); + topicTopMessageObject.isTopicMainMessage = true; + topicTopMessageObject.replyToForumTopic = topic; + } + } + } + replyingMessageObject = messageObjectToReply; replyingQuote = quote; if (replyingQuote != null && replyingQuote.getText() == null) { replyingQuote = null; } - chatActivityEnterView.setReplyingMessageObject(messageObjectToReply, quote); + chatActivityEnterView.setReplyingMessageObject(messageObjectToReply, quote, topicTopMessageObject); chatActivityEnterView.setEditingMessageObject(null, false); forbidForwardingWithDismiss = false; if (messagePreviewParams == null) { @@ -13161,8 +13240,8 @@ public void updateMessagesVisiblePart(boolean inLayout) { minAdapterPosition = adapterPosition; } } - int top = (int) view.getY(); - int bottom = top + view.getMeasuredHeight(); + final int top = (int) view.getY(); + final int bottom = top + view.getMeasuredHeight(); ChatMessageCell messageCell = null; if (view instanceof ChatMessageCell) { messageCell = (ChatMessageCell) view; @@ -13195,6 +13274,12 @@ public void updateMessagesVisiblePart(boolean inLayout) { keyboardOffset = chatActivityEnterView.getEmojiPadding(); } + // in channels mark as read messages that are visible 80% on the screen + final boolean visibleToBeRead = currentChat == null || !ChatObject.isChannelAndNotMegaGroup(currentChat) || view.getMeasuredHeight() > 0 && top + view.getMeasuredHeight() * .80f < clipBottomFinal; + + final float visibleTop = getServiceTop(view); + final int visibleBackgroundHeight = getServiceHeight(view); + if (messageCell != null) { messageObject = messageCell.getMessageObject(); if (messageObject.getDialogId() == dialog_id && messageObject.getId() > maxVisibleId) { @@ -13203,7 +13288,7 @@ public void updateMessagesVisiblePart(boolean inLayout) { } messageCell.setParentBounds(chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4), chatListView.getMeasuredHeight() - blurredViewBottomOffset); - messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, keyboardOffset, view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY(), contentView.getMeasuredWidth(), contentView.getBackgroundSizeY(), blurredViewTopOffset, blurredViewBottomOffset); + messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, keyboardOffset, view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY() - (1f - contentPanTranslationT) * chatListViewPaddingTop, contentView.getMeasuredWidth(), contentView.getBackgroundSizeY(), blurredViewTopOffset, blurredViewBottomOffset); markSponsoredAsRead(messageObject); if (!threadMessageVisible && messageStarter != null && (messageObject == messageStarter || isTopic && messageObject != null && messageObject.getId() == messageStarter.getId()) && messageCell.getBottom() > chatListViewPaddingTop) { threadMessageVisible = true; @@ -13267,13 +13352,18 @@ public void updateMessagesVisiblePart(boolean inLayout) { if (messageObject != null && messageObject.getDialogId() == dialog_id && messageObject.getId() > maxVisibleId) { maxVisibleId = Math.max(maxVisibleId, messageObject.getId()); } - cell.setVisiblePart(view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY(), contentView.getBackgroundSizeY()); + cell.setVisiblePart(visibleTop, visibleBackgroundHeight); } else if (view instanceof BotHelpCell) { view.invalidate(); + } else if (view instanceof ChatLoadingCell) { + ((ChatLoadingCell) view).setVisiblePart(visibleTop, visibleBackgroundHeight); } if (chatMode != MODE_SCHEDULED && messageObject != null) { int id = messageObject.getId(); - if (!isThreadChat() && (!messageObject.isOut() && messageObject.isUnread() || messageObject.messageOwner.from_scheduled && id > currentReadMaxId) || id > 0 && isThreadChat() && id > currentReadMaxId && id > replyMaxReadId) { + if ( + !isThreadChat() && visibleToBeRead && (!messageObject.isOut() && messageObject.isUnread() || messageObject.messageOwner.from_scheduled && id > currentReadMaxId) || + isThreadChat() && id > 0 && id > currentReadMaxId && id > replyMaxReadId + ) { if (id > 0) { maxPositiveUnreadId = Math.max(maxPositiveUnreadId, messageObject.getId()); } @@ -13548,6 +13638,17 @@ public void updateMessagesVisiblePart(boolean inLayout) { } } } + if (progressView2 != null) { + progressView2.invalidate(); + } + } + + private float getServiceTop(View view) { + return view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY() - (1f - contentPanTranslationT) * chatListViewPaddingTop; + } + + public int getServiceHeight(View view) { + return contentView.getBackgroundSizeY(); } private boolean pinnedOnlyStarterMessage() { @@ -13637,7 +13738,7 @@ private int scrollOffsetForQuote(MessageObject object) { return 0; } - int index = text.toString().indexOf(highlightMessageQuote); + int index = MessageObject.findQuoteStart(text.toString(), highlightMessageQuote, highlightMessageQuoteOffset); if (index < 0) { return 0; } @@ -13682,6 +13783,7 @@ private void startMessageUnselect() { unselectRunnable = () -> { highlightMessageId = Integer.MAX_VALUE; highlightMessageQuote = null; + highlightMessageQuoteOffset = -1; showNoQuoteAlert = false; updateVisibleRows(); unselectRunnable = null; @@ -14128,6 +14230,7 @@ protected void onPanTranslationUpdate(float y, float progress, boolean keyboardV return; } contentPanTranslation = y; + contentPanTranslationT = progress; if (chatAttachAlert != null && chatAttachAlert.isShowing()) { setNonNoveTranslation(y); } else { @@ -15307,6 +15410,7 @@ private void setNonNoveTranslation(float y) { emptyViewContainer.setTranslationY(0); progressView.setTranslationY(0); contentPanTranslation = 0; + contentPanTranslationT = 0; contentView.setBackgroundTranslation(0); if (instantCameraView != null) { instantCameraView.onPanTranslationUpdate(0); @@ -15969,6 +16073,13 @@ public void onAnimationEnd(Animator animation) { newVisibility = View.GONE; } else if (selectedCount == 1) { newVisibility = View.VISIBLE; + for (int b = 0, N = selectedMessagesIds[0].size(); b < N; b++) { + MessageObject message = selectedMessagesIds[0].valueAt(b); + if (ChatObject.isForum(currentChat) && !canSendMessageToTopic(message)) { + newVisibility = View.GONE; + break; + } + } } else { newVisibility = View.VISIBLE; long lastGroupId = 0; @@ -15976,7 +16087,7 @@ public void onAnimationEnd(Animator animation) { for (int b = 0, N = selectedMessagesIds[a].size(); b < N; b++) { MessageObject message = selectedMessagesIds[a].valueAt(b); long groupId = message.getGroupId(); - if (groupId == 0 || lastGroupId != 0 && lastGroupId != groupId) { + if (groupId == 0 || lastGroupId != 0 && lastGroupId != groupId || (ChatObject.isForum(currentChat) && !canSendMessageToTopic(message))) { newVisibility = View.GONE; break; } @@ -16142,7 +16253,7 @@ private void processRowSelect(View view, boolean outside, float touchX, float to if (message != null && message.isAnyGift()) { return; } - if (type < 2 || type == 20 || type == MessageObject.TYPE_SUGGEST_PHOTO || (message != null && message.isWallpaperAction())) { + if (type < 2 || type == 20 || type == MessageObject.TYPE_SUGGEST_PHOTO || message != null && message.type == MessageObject.TYPE_JOINED_CHANNEL || (message != null && message.isWallpaperAction())) { return; } addToSelectedMessages(message, outside); @@ -17532,7 +17643,6 @@ public void didReceivedNotification(int id, int account, final Object... args) { messages.get(messages.size() - 1).stableId = lastStableId++; messages.add(messages.size() - 1, obj); } - MessageObject prevObj; if (currentEncryptedChat == null) { if (createUnreadMessageAfterId != 0 && load_type != 1 && a + 1 < messArr.size()) { @@ -18662,6 +18772,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (pendingRequestsDelegate != null) { pendingRequestsDelegate.setChatInfo(chatInfo, true); } + checkLeaveChannelButton(); } } else if (id == NotificationCenter.chatInfoCantLoad) { long chatId = (Long) args[0]; @@ -19818,6 +19929,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); loadingPinnedMessagesList = true; } + updateVisibleWallpaperActions(); } } else if (id == NotificationCenter.didSetNewWallpapper) { if (fragmentView != null) { @@ -20148,6 +20260,41 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (avatarContainer != null) { avatarContainer.avatarImageView.invalidate(); } + } else if (id == NotificationCenter.channelRecommendationsLoaded) { + final long chatId = (long) args[0]; + if (chatListView != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell){ + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.channelRecommendationsCell != null && cell.channelRecommendationsCell.chatId == chatId) { + boolean wasExpanded = cell.channelRecommendationsCell.isExpanded(); + cell.channelRecommendationsCell.update(); + if (cell.channelRecommendationsCell.isExpanded() != wasExpanded) { + cell.getMessageObject().forceUpdate = true; + cell.forceResetMessageObject(); + cell.requestLayout(); + final int position = chatListView.getChildAdapterPosition(child); + if (position >= 0) { + chatAdapter.notifyItemChanged(position); + } + } + } + } + } + } + } else if (id == NotificationCenter.updateTranscriptionLock) { + if (chatListView != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell){ + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.transcribeButton != null) { + cell.transcribeButton.setLock(TranscribeButton.showTranscribeLock(cell.getMessageObject()), true); + } + } + } + } } } @@ -20723,7 +20870,7 @@ private void rotateMotionBackgroundDrawable() { wallpaper = ((SizeNotifierFrameLayout) fragmentView).getBackgroundImage(); } if (wallpaper instanceof ChatBackgroundDrawable) { - wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(); + wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(true); } if (wallpaper instanceof MotionBackgroundDrawable) { ((MotionBackgroundDrawable) wallpaper).switchToNextPosition(); @@ -20763,12 +20910,19 @@ private void processNewMessages(ArrayList arr) { messagesDict[0].put(messageObject.getId(), messageObject); messageObject.copyStableParams(messages.get(i)); if (type == MessageObject.TYPE_ACTION_WALLPAPER) { - messageObject.messageOwner.action.wallpaper = messages.get(i).messageOwner.action.wallpaper; + final TLRPC.WallPaper oldWallpaper = messages.get(i).messageOwner.action.wallpaper; + final long newId = messageObject.messageOwner.action.wallpaper != null ? messageObject.messageOwner.action.wallpaper.id : (oldWallpaper != null ? oldWallpaper.id : 0); + messageObject.messageOwner.action.wallpaper = oldWallpaper; + if (messageObject.messageOwner.action.wallpaper != null) { + messageObject.messageOwner.action.wallpaper.id = newId; + } } else if (type == MessageObject.TYPE_SUGGEST_PHOTO) { PhotoUtilities.replacePhotoImagesInCache(currentAccount, messages.get(i).messageOwner.action.photo, messageObject.messageOwner.action.photo); } messages.set(i, messageObject); - chatAdapter.notifyItemChanged(chatAdapter.messagesStartRow + i); + if (type != MessageObject.TYPE_ACTION_WALLPAPER) { + chatAdapter.notifyItemChanged(chatAdapter.messagesStartRow + i); + } break; } } @@ -21448,7 +21602,7 @@ private void saveScrollPosition() { if (scrollToMessageObject != null) { int scrollToIndex = messages.indexOf(scrollToMessageObject); if (scrollToIndex > 0) { - chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); +// chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); } } } @@ -22047,7 +22201,7 @@ public void onBecomeFullyVisible() { @Override public void onBecomeFullyHidden() { - if (!getMessagesController().premiumLocked && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && messages != null) { + if (!getMessagesController().premiumLocked && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && messages != null) { for (int i = 0; i < messages.size(); ++i) { MessageObject msg = messages.get(i); if (msg != null && !msg.isOutOwner() && (msg.isVoice() || msg.isRoundVideo()) && !msg.isUnread() && (msg.isContentUnread() || ChatObject.isChannelAndNotMegaGroup(currentChat))) { @@ -22479,7 +22633,6 @@ private void updateBottomOverlay() { if (bottomOverlayChatText == null || chatMode == MODE_SCHEDULED || getContext() == null) { return; } - boolean haveBeenWaiting = bottomOverlayChatWaitsReply; bottomOverlayChatWaitsReply = false; if (reportType >= 0) { updateActionModeTitle(); @@ -22525,7 +22678,7 @@ private void updateBottomOverlay() { } showBottomOverlayProgress(false, false); } - } else if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting)) { + } else if (shouldDisplaySwipeToLeftToReplyInForum()) { bottomOverlayChatWaitsReply = true; showBottomOverlayProgress(false, false); bottomOverlayChatText.setTextInfo(LocaleController.getString("ForumReplyToMessagesInTopic", R.string.ForumReplyToMessagesInTopic)); @@ -22548,7 +22701,7 @@ private void updateBottomOverlay() { } showBottomOverlayProgress(false, false); } - } else if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting)) { + } else if (shouldDisplaySwipeToLeftToReplyInForum()) { bottomOverlayChatWaitsReply = true; showBottomOverlayProgress(false, false); bottomOverlayChatText.setTextInfo(LocaleController.getString("ForumReplyToMessagesInTopic", R.string.ForumReplyToMessagesInTopic)); @@ -22730,7 +22883,7 @@ public void onAnimationEnd(Animator animation) { bottomOverlayChat.setVisibility(View.VISIBLE); chatActivityEnterView.setVisibility(View.INVISIBLE); } else if (chatMode == MODE_PINNED || - currentChat != null && ((ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) && (currentChat.join_to_send || !isThreadChat() || ChatObject.isForum(currentChat)) || forumTopic != null && forumTopic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic) || currentChat.forum && !isTopic && replyingMessageObject == null) || + currentChat != null && ((ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) && (currentChat.join_to_send || !isThreadChat() || ChatObject.isForum(currentChat)) || forumTopic != null && forumTopic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic) || shouldDisplaySwipeToLeftToReplyInForum()) || currentUser != null && (UserObject.isDeleted(currentUser) || userBlocked || UserObject.isReplyUser(currentUser))) { if (chatActivityEnterView.isEditingMessage()) { chatActivityEnterView.setVisibility(View.VISIBLE); @@ -22771,20 +22924,6 @@ public void onAnimationEnd(Animator animation) { topViewWasVisible = 0; } } - if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting) && bottomOverlayChatWaitsReply) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, 1); - if (topic != null) { - if (topic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic)) { - Drawable lock = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); - lock.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.MULTIPLY)); - bottomOverlayChatText.setTextInfo(lock, LocaleController.getString("TopicClosedByAdmin", R.string.TopicClosedByAdmin)); - bottomOverlayChatText.setEnabled(false); - } else { - bottomOverlayChat.setVisibility(View.INVISIBLE); - chatActivityEnterView.setVisibility(View.VISIBLE); - } - } - } if (sentBotStart) { getMessagesController().sendBotStart(currentUser, botUser); @@ -22795,6 +22934,30 @@ public void onAnimationEnd(Animator animation) { checkRaiseSensors(); } + private boolean shouldDisplaySwipeToLeftToReplyInForum() { + return isForumInViewAsMessagesMode() && replyingMessageObject == null && !canSendMessageToGeneralTopic(); + } + + private boolean canSendMessageToTopic(MessageObject message) { + if (message != null && ChatObject.isForum(currentChat)) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, MessageObject.getTopicId(message.messageOwner, true)); + return canSendMessageToTopic(topic); + } + return false; + } + + private boolean canSendMessageToGeneralTopic() { + if (isForumInViewAsMessagesMode() && currentChat != null) { + TLRPC.TL_forumTopic generalTopic = getMessagesController().getTopicsController().findTopic(currentChat.id, 1); + return canSendMessageToTopic(generalTopic); + } + return false; + } + + private boolean canSendMessageToTopic(TLRPC.TL_forumTopic topic) { + return topic != null && (!topic.closed || ChatObject.canManageTopic(currentAccount, currentChat, topic)); + } + public void updateReplyMessageHeader(boolean notify) { if (avatarContainer != null && threadMessageId != 0) { if (isTopic) { @@ -24701,8 +24864,8 @@ public void applyDraftMaybe(boolean canClear) { } TLRPC.DraftMessage draftMessage = null; Integer topicId = null; - if (ChatObject.isForum(currentChat) && !isTopic) { - Pair pair = getMediaDataController().getOneThreadDraft(dialog_id);; + if (isForumInViewAsMessagesMode()) { + Pair pair = getMediaDataController().getOneThreadDraft(dialog_id); if (pair != null) { topicId = pair.first; draftMessage = pair.second; @@ -24790,29 +24953,29 @@ public void applyDraftMaybe(boolean canClear) { }, 700); } } - } /*else if (canClear && draftMessage == null) { - chatActivityEnterView.setFieldText(""); - hideFieldPanel(true); - }*/ - if ((replyingMessageObject == null || threadMessageObject == replyingMessageObject) && draftReplyMessage != null && !(threadMessageObject != null && threadMessageObject.getId() == draftReplyMessage.id)) { - replyingMessageObject = new MessageObject(currentAccount, draftReplyMessage, getMessagesController().getUsers(), false, false); - if (draftMessage.reply_to != null && (draftMessage.reply_to.flags & 4) != 0) { - replyingQuote = ReplyQuote.from(replyingMessageObject, draftMessage.reply_to.quote_text); - } - checkNewMessagesOnQuoteEdit(false); - if (replyingQuote != null) { - showFieldPanelForReplyQuote(replyingMessageObject, replyingQuote); - } else { - showFieldPanelForReply(replyingMessageObject); - } - updateBottomOverlay(); - } else if (topicId != null && topicId != 0 && currentChat != null) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); - if (topic != null && topic.topicStartMessage != null) { - replyingMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, getMessagesController().getUsers(), false, false); - replyingMessageObject.replyToForumTopic = topic; - showFieldPanelForReply(replyingMessageObject); + } + if (replyingMessageObject == null || threadMessageObject == replyingMessageObject) { + if (draftReplyMessage != null && !(threadMessageObject != null && threadMessageObject.getId() == draftReplyMessage.id)) { + replyingMessageObject = new MessageObject(currentAccount, draftReplyMessage, getMessagesController().getUsers(), false, false); + if (draftMessage.reply_to != null && (draftMessage.reply_to.flags & 4) != 0) { + replyingQuote = ReplyQuote.from(replyingMessageObject, draftMessage.reply_to.quote_text, (draftMessage.reply_to.flags & 16) != 0 ? draftMessage.reply_to.quote_offset : -1); + } + checkNewMessagesOnQuoteEdit(false); + if (replyingQuote != null) { + showFieldPanelForReplyQuote(replyingMessageObject, replyingQuote); + } else { + showFieldPanelForReply(replyingMessageObject); + } updateBottomOverlay(); + } else if (topicId != null && topicId != 0 && currentChat != null) { + // user created a draft in topic + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null && topic.topicStartMessage != null) { + replyingMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, getMessagesController().getUsers(), false, false); + replyingMessageObject.replyToForumTopic = topic; + showFieldPanelForReply(replyingMessageObject); + updateBottomOverlay(); + } } } } @@ -25183,11 +25346,21 @@ private boolean createMenu(View v, boolean single, boolean listView, float x, fl } final int type = getMessageType(message); if (single) { - if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + boolean isGiveawayResultsMessage = false; + if (message.messageOwner.action instanceof TLRPC.TL_messageActionCustomAction) { + TLRPC.TL_messageActionCustomAction customAction = (TLRPC.TL_messageActionCustomAction) message.messageOwner.action; + if (customAction.message != null && customAction.message.contains("giveaway")) { + //fallback for old versions + isGiveawayResultsMessage = true; + } + } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + isGiveawayResultsMessage = true; + } + if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || isGiveawayResultsMessage) { if (message.getReplyMsgId() != 0) { - scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, message.getDialogId() == mergeDialogId ? 1 : 0, false, 0); + AndroidUtilities.runOnUIThread(() -> scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, message.getDialogId() == mergeDialogId ? 1 : 0, false, 0)); } else { - Toast.makeText(getParentActivity(), LocaleController.getString("MessageNotFound", R.string.MessageNotFound), Toast.LENGTH_SHORT).show(); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString("MessageNotFound", R.string.MessageNotFound), themeDelegate).show(); } return true; } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { @@ -26147,7 +26320,7 @@ public void setAutoDeleteHistory(int time, int action) { isReactionsAvailable = nekoXShowReactionsView && !message.isSecretMedia() && !isSecretChat() && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone) || (chatInfo == null && !ChatObject.isChannel(currentChat)) || currentUser != null) && !availableReacts.isEmpty(); } boolean showMessageSeen = !isReactionsViewAvailable && !isInScheduleMode() && currentChat != null && message.isOutOwner() && message.isSent() && !message.isEditing() && !message.isSending() && !message.isSendError() && !message.isContentUnread() && !message.isUnread() && (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - message.messageOwner.date < getMessagesController().chatReadMarkExpirePeriod) && (ChatObject.isMegagroup(currentChat) || !ChatObject.isChannel(currentChat)) && chatInfo != null && chatInfo.participants_count <= getMessagesController().chatReadMarkSizeThreshold && !(message.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByRequest) && (v instanceof ChatMessageCell); - boolean showSponsorInfo = selectedObject != null && selectedObject.isSponsored() && (selectedObject.sponsoredInfo != null || selectedObject.sponsoredAdditionalInfo != null || selectedObject.sponsoredWebPage != null || selectedObject.sponsoredWebPage != null); + boolean showSponsorInfo = selectedObject != null && selectedObject.isSponsored() && (selectedObject.sponsoredInfo != null || selectedObject.sponsoredAdditionalInfo != null || selectedObject.sponsoredWebPage != null || selectedObject.sponsoredBotApp != null); int flags = 0; if (isReactionsViewAvailable || showMessageSeen || showSponsorInfo) { @@ -27115,6 +27288,9 @@ public void dismiss(boolean animated) { if (chatActivityEnterView != null && (chatActivityEnterView.isRecordingAudioVideo() || chatActivityEnterView.isRecordLocked())) { return false; } + if (message != null && message.type == MessageObject.TYPE_JOINED_CHANNEL) { + return false; + } createActionMode(); final ActionBarMenu actionMode = actionBar.createActionMode(); @@ -27303,12 +27479,39 @@ private void closeMenu(boolean hideDim) { Runnable updateReactionRunnable; + private void showMultipleReactionsPromo(ChatMessageCell cell, ReactionsLayoutInBubble.VisibleReaction visibleReaction, int currentChosenReactions) { + if (SharedConfig.multipleReactionsPromoShowed || cell == null || cell.getMessageObject() == null || visibleReaction == null || getUserConfig().isPremium()) { + return; + } + if (currentChosenReactions == 1) { + SharedConfig.setMultipleReactionsPromoShowed(true); + TLRPC.Document document; + if (visibleReaction.documentId == 0) { + TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); + if (availableReaction == null) { + return; + } + document = availableReaction.center_icon; + } else { + document = AnimatedEmojiDrawable.findDocument(currentAccount, visibleReaction.documentId); + } + if (document == null) { + return; + } + BulletinFactory.of(ChatActivity.this).createEmojiBulletin( + document, + LocaleController.getString(R.string.ChatMultipleReactionsPromo) + ).setDuration(Bulletin.DURATION_PROLONG).show(); + } + } + public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { if (isInScheduleMode() || primaryMessage == null) { return; } ReactionsEffectOverlay.removeCurrent(false); + int currentChosenReactions = primaryMessage.getChoosenReactions().size(); boolean added = primaryMessage.selectReaction(visibleReaction, bigEmoji, fromDoubleTap); int messageIdForCell = primaryMessage.getId(); if (groupedMessagesMap.get(primaryMessage.getGroupId()) != null) { @@ -27321,9 +27524,12 @@ public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayou int finalMessageIdForCell = messageIdForCell; - if (added && !fromDoubleTap) { + if (added) { ChatMessageCell cell = findMessageCell(finalMessageIdForCell, true); - ReactionsEffectOverlay.show(ChatActivity.this, reactionsLayout, cell, fromView, x, y, visibleReaction, currentAccount, reactionsLayout != null ? (bigEmoji ? ReactionsEffectOverlay.LONG_ANIMATION : ReactionsEffectOverlay.ONLY_MOVE_ANIMATION) : ReactionsEffectOverlay.SHORT_ANIMATION); + showMultipleReactionsPromo(cell, visibleReaction, currentChosenReactions); + if (!fromDoubleTap) { + ReactionsEffectOverlay.show(ChatActivity.this, reactionsLayout, cell, fromView, x, y, visibleReaction, currentAccount, reactionsLayout != null ? (bigEmoji ? ReactionsEffectOverlay.LONG_ANIMATION : ReactionsEffectOverlay.ONLY_MOVE_ANIMATION) : ReactionsEffectOverlay.SHORT_ANIMATION); + } } if (added) { if (visibleReaction.emojicon != null) { @@ -28761,9 +28967,10 @@ public void setHighlightMessageId(int id) { highlightMessageId = id; } - public void setHighlightQuote(int id, String quote) { + public void setHighlightQuote(int id, String quote, int quote_offset) { highlightMessageId = id; highlightMessageQuote = quote; + highlightMessageQuoteOffset = quote_offset; showNoQuoteAlert = true; } @@ -28846,7 +29053,7 @@ private void updateVisibleRows(boolean suppressUpdateMessageObject) { startMessageUnselect(); } if (cell.isHighlighted() && highlightMessageQuote != null) { - if (!cell.setHighlightedText(highlightMessageQuote, true) && showNoQuoteAlert) { + if (!cell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset) && showNoQuoteAlert) { showNoQuoteFound(); } showNoQuoteAlert = false; @@ -30356,6 +30563,28 @@ public void needShowEffectOverlay(ChatActionCell cell, TLRPC.Document document, emojiAnimationsOverlay.showAnimationForActionCell(cell, document, videoSize); } + @Override + public void didClickButton(ChatActionCell cell) { + if (cell == null) return; + MessageObject message = cell.getMessageObject(); + if (message == null) return; + if (message.type == MessageObject.TYPE_ACTION_WALLPAPER && !cell.getMessageObject().isOutOwner() && cell.getMessageObject().isWallpaperForBoth() && cell.getMessageObject().isCurrentWallpaper()) { + AlertDialog d = new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.RemoveWallpaperTitle)) + .setMessage(LocaleController.getString(R.string.RemoveWallpaperMessage)) + .setPositiveButton(LocaleController.getString(R.string.Remove), (w, di) -> { + ChatThemeController.getInstance(currentAccount).clearWallpaper(dialog_id, true, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .create(); + showDialog(d); + TextView button = (TextView) d.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(getThemedColor(Theme.key_text_RedBold)); + } + } + } + @Override public void didClickImage(ChatActionCell cell) { MessageObject message = cell.getMessageObject(); @@ -30368,9 +30597,8 @@ public void didClickImage(ChatActionCell cell) { return; } if (cell.getMessageObject().type == MessageObject.TYPE_ACTION_WALLPAPER) { - MessagesController messagesController = MessagesController.getInstance(currentAccount); - if (message.getId() < 0 && messagesController.uploadingWallpaper != null && TextUtils.equals(message.messageOwner.action.wallpaper.uploadingImage, messagesController.uploadingWallpaper)) { + if (cell.showingCancelButton() && message.getId() < 0 && messagesController.uploadingWallpaper != null && TextUtils.equals(message.messageOwner.action.wallpaper.uploadingImage, messagesController.uploadingWallpaper)) { messagesController.cancelUploadWallpaper(); removeMessageObject(message); return; @@ -30688,9 +30916,16 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (currentChat != null) { long fromId = prevMessage.getFromChatId(); pinnedTop = fromId == message.getFromChatId() && !message.isImportedForward() && !prevMessage.isImportedForward(); -// if (!pinnedTopByGroup && pinnedTop && fromId < 0 && currentChat.megagroup) { -// pinnedTop = false; -// } + if (!pinnedTopByGroup && pinnedTop && fromId < 0 && currentChat.megagroup) { + pinnedTop = false; + } + if (pinnedTop && isForumInViewAsMessagesMode()) { + int topicId = message.replyToForumTopic == null ? MessageObject.getTopicId(message.messageOwner, true) : message.replyToForumTopic.id; + int prevTopicId = prevMessage.replyToForumTopic == null ? MessageObject.getTopicId(prevMessage.messageOwner, true) : prevMessage.replyToForumTopic.id; + if (topicId != prevTopicId) { + pinnedTop = false; + } + } } else if (UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser)) { if (message.isPrivateForward() || prevMessage.isPrivateForward()) { pinnedTop = false; @@ -30719,7 +30954,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { messageCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); if (messageCell.isHighlighted() && highlightMessageQuote != null) { - messageCell.setHighlightedText(highlightMessageQuote, true); + messageCell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset); } if (highlightMessageId != Integer.MAX_VALUE) { startMessageUnselect(); @@ -31045,7 +31280,7 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { if (!inPreviewMode || !messageCell.isHighlighted()) { messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && (messageCell.getMessageObject().getId() == highlightMessageId || messageCell.getCurrentMessagesGroup() != null && messageCell.getCurrentMessagesGroup().contains(highlightMessageId))); if (messageCell.isHighlighted() && highlightMessageQuote != null) { - if (!messageCell.setHighlightedText(highlightMessageQuote, true) && showNoQuoteAlert) { + if (!messageCell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset) && showNoQuoteAlert) { showNoQuoteFound(); } showNoQuoteAlert = false; @@ -31626,7 +31861,7 @@ public void didPressSideButton(ChatMessageCell cell) { arrayList = new ArrayList<>(); arrayList.add(messageObject); } - showDialog(new ShareAlert(getContext(), ChatActivity.this, arrayList, null, null, ChatObject.isChannel(currentChat), null, null, false, false, themeDelegate) { + showDialog(new ShareAlert(getContext(), ChatActivity.this, arrayList, null, null, ChatObject.isChannel(currentChat), null, null, false, false, false, themeDelegate) { @Override public void dismissInternal() { super.dismissInternal(); @@ -31732,10 +31967,7 @@ public void didPressUserStatus(ChatMessageCell cell, TLRPC.User user, TLRPC.Docu 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; - } + int colorId = UserObject.getColorId(user); if (colorId < 7) { premiumPreviewBottomSheet.accentColor = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]); } else { @@ -31990,6 +32222,37 @@ public void needShowPremiumBulletin(int type) { if (!NekoConfig.disableVibration.Bool()) topUndoView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} + } else if (type == 1) { + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + CharSequence text = getMessagesController().transcribeAudioTrialCooldownUntil > 0 ? + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeftUntil", TranscribeButton.getTranscribeTrialCount(currentAccount), until)) : + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeft", TranscribeButton.getTranscribeTrialCount(currentAccount))); + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.transcribe, text, 6).show(true); + try { + fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) {} + } else if (type == 2 || type == 3) { + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + BulletinFactory.of(ChatActivity.this).createSimpleBulletin( + R.raw.transcribe, + new SpannableStringBuilder().append( + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialEnd", getMessagesController().transcribeAudioTrialWeeklyNumber)) + ).append(" ").append( + type == 2 ? + AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.TranscriptionTrialEndBuy), () -> { + new PremiumFeatureBottomSheet(ChatActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT, true).show(); + getMessagesController().pressTranscribeButton(); + }) : + getMessagesController().transcribeAudioTrialCooldownUntil <= 0 ? "" : + AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TranscriptionTrialEndWaitOrBuy, until), () -> { + new PremiumFeatureBottomSheet(ChatActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT, true).show(); + getMessagesController().pressTranscribeButton(); + }) + ), + 6, + 7000 + ).show(true); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); } } @@ -32281,6 +32544,80 @@ public void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBlock BulletinFactory.of(ChatActivity.this).createCopyBulletin(LocaleController.getString(R.string.CodeCopied)).show(); } + @Override + public void didPressMoreChannelRecommendations(ChatMessageCell cell) { + if (getUserConfig().isPremium()) { + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + args.putInt("start_from", SharedMediaLayout.TAB_RECOMMENDED_CHANNELS); + presentFragment(new MediaActivity(args, avatarContainer.getSharedMediaPreloader())); + } else { + BulletinFactory.of(ChatActivity.this).createSimpleBulletin( + R.raw.star_premium_2, + AndroidUtilities.replaceSingleTag(LocaleController.formatPluralStringComma("UnlockSimilarChannelsPremium", getMessagesController().recommendedChannelsLimitPremium), () -> { + presentFragment(new PremiumPreviewFragment("similar_channels")); + }) + ).show(); + } + } + + @Override + public void didPressChannelRecommendation(ChatMessageCell cell, TLRPC.Chat chat, boolean longPress) { + if (chat == null || parentLayout != null && parentLayout.isInPreviewMode()) { + return; + } + Bundle args = new Bundle(); + args.putLong("chat_id", chat.id); + if (longPress) { + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getParentActivity(), R.drawable.popup_fixed_alert, getResourceProvider(), ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_SHOWN_FROM_BOTTOM); + previewMenu.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + + ActionBarMenuSubItem openChannel = new ActionBarMenuSubItem(getParentActivity(), false, false); + openChannel.setTextAndIcon(LocaleController.getString(R.string.OpenChannel2), R.drawable.msg_channel); + openChannel.setMinimumWidth(160); + openChannel.setOnClickListener(view -> { + if (parentLayout != null) { + parentLayout.expandPreviewFragment(); + } + }); + previewMenu.addView(openChannel); + + ActionBarMenuSubItem joinChannel = new ActionBarMenuSubItem(getParentActivity(), false, false); + joinChannel.setTextAndIcon(LocaleController.getString(R.string.ProfileJoinChannel), R.drawable.msg_addbot); + joinChannel.setMinimumWidth(160); + joinChannel.setOnClickListener(view -> { + finishPreviewFragment(); + chat.left = false; + if (cell != null && cell.channelRecommendationsCell != null) { + getNotificationCenter().postNotificationName(NotificationCenter.channelRecommendationsLoaded, cell.channelRecommendationsCell.chatId); + } + getMessagesController().addUserToChat(chat.id, getUserConfig().getCurrentUser(), 0, null, ChatActivity.this, () -> { + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.contact_check, LocaleController.formatString(R.string.YouJoinedChannel, chat == null ? "" : chat.title)).show(true); + }); + }); + previewMenu.addView(joinChannel); + + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.allowExpandPreviewByClick = true; + presentFragmentAsPreviewWithMenu(chatActivity, previewMenu); + checkShowBlur(true); + } else { + presentFragment(new ChatActivity(args)); + } + } + + @Override + public void didPressChannelRecommendationsClose(ChatMessageCell cell) { + MessageObject msg = cell.getMessageObject(); + if (msg != null && msg.type == MessageObject.TYPE_JOINED_CHANNEL) { + msg.toggleChannelRecommendations(); + msg.forceUpdate = true; + cell.forceResetMessageObject(); + cell.requestLayout(); + chatAdapter.updateRowWithMessageObject(msg, false, false); + } + } + @Override public boolean didPressAnimatedEmoji(ChatMessageCell cell, AnimatedEmojiSpan span) { if (getMessagesController().premiumLocked || span == null || span.standard) { @@ -32396,8 +32733,12 @@ public void didPressReplyMessage(ChatMessageCell cell, int id) { finishFragment(); } else { String quote = null; + int quoteOffset = -1; if (messageObject.messageOwner != null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.quote) { quote = messageObject.messageOwner.reply_to.quote_text; + if ((messageObject.messageOwner.reply_to.flags & 1024) != 0) { + quoteOffset = messageObject.messageOwner.reply_to.quote_offset; + } } long did = dialog_id; boolean couldBeDifferentTopic = false; @@ -32472,11 +32813,12 @@ public void end(boolean replaced) { AndroidUtilities.runOnUIThread(ChatActivity.this::resetProgressDialogLoading, 250); } } - }, messageObject.getId()); + }, messageObject.getId(), quoteOffset); } } else { if (messageObject.messageOwner != null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.quote) { highlightMessageQuote = messageObject.messageOwner.reply_to.quote_text; + highlightMessageQuoteOffset = quoteOffset; showNoQuoteAlert = true; } scrollToMessageId(id, messageObject.getId(), true, messageObject.getDialogId() == mergeDialogId ? 1 : 0, true, 0, () -> { @@ -32785,7 +33127,49 @@ public void end(boolean replaced) { if (messageObject.isSponsored()) { logSponsoredClicked(messageObject); Bundle args = new Bundle(); - if (messageObject.sponsoredWebPage != null) { + if (messageObject.sponsoredBotApp != null) { + TLRPC.TL_messages_getBotApp getBotApp = new TLRPC.TL_messages_getBotApp(); + TLRPC.TL_inputBotAppShortName app = new TLRPC.TL_inputBotAppShortName(); + if (messageObject.messageOwner == null || messageObject.messageOwner.from_id == null) { + return; + } + TLRPC.User bot = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.from_id.user_id); + if (bot == null) { + return; + } + app.bot_id = MessagesController.getInstance(currentAccount).getInputUser(bot); + app.short_name = messageObject.sponsoredBotApp.short_name; + getBotApp.app = app; + ConnectionsManager.getInstance(currentAccount).sendRequest(getBotApp, (response1, error1) -> { +// if (progress != null) { +// progress.end(); +// } + if (error1 != null) { + BulletinFactory.of(ChatActivity.this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(true); + } else { + TLRPC.TL_messages_botApp botApp = (TLRPC.TL_messages_botApp) response1; + AndroidUtilities.runOnUIThread(() -> { +// dismissLoading.run(); + AtomicBoolean allowWrite = new AtomicBoolean(); + Runnable loadBotSheet = () -> { + BotWebViewSheet sheet = new BotWebViewSheet(getContext(), getResourceProvider()); + sheet.setParentActivity(getParentActivity()); + sheet.requestWebView(currentAccount, bot.id, bot.id, null, null, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP, 0, false, ChatActivity.this, botApp.app, allowWrite.get(), messageObject.botStartParam, bot); + showDialog(sheet); + if (botApp.inactive) { + sheet.showJustAddedBulletin(); + } + }; + + if (botApp.request_write_access) { + AlertsCreator.createBotLaunchAlert(ChatActivity.this, allowWrite, bot, loadBotSheet); + } else { + loadBotSheet.run(); + } + }); + } + }); + } else if (messageObject.sponsoredWebPage != null) { Browser.openUrl(getContext(), messageObject.sponsoredWebPage.url, true, false); } else if (messageObject.sponsoredChatInvite != null) { showDialog(new JoinGroupAlert(getContext(), messageObject.sponsoredChatInvite, messageObject.sponsoredChatInviteHash, ChatActivity.this, themeDelegate)); @@ -34458,7 +34842,7 @@ public void setCurrentTheme(final EmojiThemes chatTheme, TLRPC.WallPaper newWall startServiceIconColor = drawServiceGradient ? 0xffffffff : Theme.getColor(Theme.key_chat_serviceIcon); } else if (drawServiceGradient && backgroundDrawable instanceof MotionBackgroundDrawable) { startServiceBitmap = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); - } else if (backgroundDrawable != null){ + } else if (backgroundDrawable != null) { initServiceMessageColors(backgroundDrawable); } startServiceColor = currentServiceColor; @@ -34713,7 +35097,7 @@ private void initPaints() { } int colorKey = Theme.getThemePaintColorKey(entry.getKey()); - if (colorKey >= 0) { + if (colorKey >= 0 && !Theme.key_paint_chatActionBackgroundDarken.equals(entry.getKey())) { newPaint.setColor(getColor(colorKey)); } currentPaints.put(entry.getKey(), newPaint); @@ -34732,6 +35116,8 @@ private void initPaints() { boolean drawServiceGradient; boolean drawSelectedGradient; + final Rect src = new Rect(), dst = new Rect(); + private void initServiceMessageColors(Drawable backgroundDrawable) { int[] result = AndroidUtilities.calcDrawableColor(backgroundDrawable); int currentServiceMessageColor = result[0]; @@ -34744,20 +35130,56 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { } currentServiceColor = serviceColor; + float dimAmount = 0; if (backgroundDrawable instanceof ChatBackgroundDrawable) { - backgroundDrawable = ((ChatBackgroundDrawable) backgroundDrawable).getDrawable(); + dimAmount = ((ChatBackgroundDrawable) backgroundDrawable).getDimAmount(); + backgroundDrawable = ((ChatBackgroundDrawable) backgroundDrawable).getDrawable(false); } - drawServiceGradient = backgroundDrawable instanceof MotionBackgroundDrawable && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW; + drawServiceGradient = (backgroundDrawable instanceof MotionBackgroundDrawable || backgroundDrawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW; drawSelectedGradient = drawServiceGradient; if (drawServiceGradient) { - serviceBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); - serviceBitmapSource = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); - serviceCanvas = new Canvas(serviceBitmap); - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, null); - serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - useSourceShader = true; + if (backgroundDrawable instanceof BitmapDrawable) { + Bitmap source = ((BitmapDrawable) backgroundDrawable).getBitmap(); + int w, h; + if (source.getWidth() > source.getHeight()) { + w = 40; + h = (int) ((float) w / source.getWidth() * source.getHeight()); + } else { + h = 40; + w = (int) ((float) h / source.getHeight() * source.getWidth()); + } + serviceBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + serviceCanvas = new Canvas(serviceBitmap); + src.set(0, 0, source.getWidth(), source.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(source, src, dst, null); + Utilities.blurBitmap(serviceBitmap, 3, 1, serviceBitmap.getWidth(), serviceBitmap.getHeight(), serviceBitmap.getRowBytes()); + serviceCanvas.drawColor(ColorUtils.setAlphaComponent(0xff000000, (int) (0xFF * dimAmount))); + serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + serviceBitmapSource = Bitmap.createBitmap(serviceBitmap); + serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + serviceShaderSource.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } + useSourceShader = true; + } else { + serviceBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); + serviceBitmapSource = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); + serviceCanvas = new Canvas(serviceBitmap); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, null); + serviceCanvas.drawColor(ColorUtils.setAlphaComponent(0xff000000, (int) (0xFF * dimAmount))); + serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + serviceShaderSource.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } + useSourceShader = true; + } } else { serviceBitmap = null; serviceShader = null; @@ -34771,22 +35193,49 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { Paint msgBackgroundSelectedPaint = getPaint(Theme.key_paint_chatMessageBackgroundSelected); if (actionBackgroundPaint != null) { + Paint darkenPaint = currentPaints.get(Theme.key_paint_chatActionBackgroundDarken); + if (darkenPaint == null) { + currentPaints.put(Theme.key_paint_chatActionBackgroundDarken, darkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG)); + darkenPaint.setColor(0); + } if (drawServiceGradient) { ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(((MotionBackgroundDrawable) backgroundDrawable).getIntensity() >= 0 ? 1.8f : 0.5f); + if (backgroundDrawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) backgroundDrawable).getIntensity(); + if (intensity >= 0) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.12f : -.06f); + } else { + colorMatrix.setSaturation(1.1f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .4f : .8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.08f : -.06f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .9f : .84f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.04f : +.06f); + } - actionBackgroundPaint.setAlpha(127); + actionBackgroundPaint.setAlpha(0xff); actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); actionBackgroundPaint.setShader(serviceShaderSource); + actionBackgroundPaint.setFilterBitmap(true); - actionBackgroundSelectedPaint.setAlpha(127); + actionBackgroundSelectedPaint.setAlpha(0xFF); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.26f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .92f); actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); actionBackgroundSelectedPaint.setShader(serviceShaderSource); + actionBackgroundSelectedPaint.setFilterBitmap(true); + darkenPaint.setAlpha(0); } else { actionBackgroundPaint.setColorFilter(null); actionBackgroundPaint.setShader(null); actionBackgroundSelectedPaint.setColorFilter(null); actionBackgroundSelectedPaint.setShader(null); + darkenPaint.setAlpha(0x15); } } @@ -34801,6 +35250,7 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { msgBackgroundSelectedPaint.setAlpha(64); msgBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix2)); msgBackgroundSelectedPaint.setShader(serviceShaderSource); + msgBackgroundSelectedPaint.setFilterBitmap(true); } else { if (selectedBackgroundColor == 0) { selectedBackgroundColor = getColor(Theme.key_chat_selectedBackground); @@ -34863,9 +35313,13 @@ private void updateServiceMessageColor(float progress) { if (serviceCanvas != null && serviceBitmapSource != null) { if (progress != 1f && startServiceBitmap != null) { useSourceShader = false; - serviceCanvas.drawBitmap(startServiceBitmap, 0, 0, null); + src.set(0, 0, startServiceBitmap.getWidth(), startServiceBitmap.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(startServiceBitmap, src, dst, null); paint.setAlpha((int) (255 * progress)); - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, paint); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, paint); if (actionBackgroundPaint != null) { actionBackgroundPaint.setShader(serviceShader); actionBackgroundSelectedPaint.setShader(serviceShader); @@ -34875,7 +35329,9 @@ private void updateServiceMessageColor(float progress) { } } else { useSourceShader = true; - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, null); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, null); if (actionBackgroundPaint != null) { actionBackgroundPaint.setShader(serviceShaderSource); actionBackgroundSelectedPaint.setShader(serviceShaderSource); @@ -34893,7 +35349,7 @@ private Drawable getBackgroundDrawableFromTheme(EmojiThemes chatTheme, int prevP Theme.ThemeInfo themeInfo = EmojiThemes.getDefaultThemeInfo(isDark); SparseIntArray currentColors = chatTheme.getPreviewColors(currentAccount, isDark ? 1 : 0); String wallpaperLink = chatTheme.getWallpaperLink(isDark ? 1 : 0); - Theme.BackgroundDrawableSettings settings = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink, prevPhase); + Theme.BackgroundDrawableSettings settings = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink, prevPhase, false); drawable = settings.wallpaper; drawable = new ColorDrawable(Color.BLACK); } else { @@ -35768,4 +36224,44 @@ public void updateClip(int[] clip) { clip[1] = chatListView.getMeasuredHeight() - (chatListView.getPaddingBottom() - AndroidUtilities.dp(3)); } } + + private void updateVisibleWallpaperActions() { + if (chatListView != null && chatAdapter != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + int position = chatListView.getChildAdapterPosition(child) - chatAdapter.messagesStartRow; + if (child instanceof ChatActionCell && position >= 0 && position < messages.size()) { + MessageObject msg = messages.get(position); + if (msg != null && msg.isWallpaperForBoth()) { + ((ChatActionCell) child).setMessageObject(msg, true); + } + } + } + } + } + + private void checkLeaveChannelButton() { + if (headerItem == null) return; + if (!headerItem.hasSubItem(delete_chat)) { + if (!isTopic) { + if (ChatObject.isChannel(currentChat) && !currentChat.creator) { + if (!ChatObject.isNotInChat(currentChat)) { + if (currentChat.megagroup) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("LeaveMegaMenu", R.string.LeaveMegaMenu)); + } else { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("LeaveChannelMenu", R.string.LeaveChannelMenu)); + } + } + } else if (!ChatObject.isChannel(currentChat)) { + if (currentChat != null) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("DeleteAndExit", R.string.DeleteAndExit)); + } else if (currentUser != null && currentUser.bot) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_block2, LocaleController.getString(R.string.DeleteAndBlock)).setColors(getThemedColor(Theme.key_text_RedRegular), getThemedColor(Theme.key_text_RedRegular)); + } else { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_delete, LocaleController.getString("DeleteChatUser", R.string.DeleteChatUser)); + } + } + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java index b5371b5aa6..fff49d0454 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java @@ -138,6 +138,9 @@ public ChatBackgroundDrawable(TLRPC.WallPaper wallPaper, boolean themeIsDark, bo public static Drawable createThumb(TLRPC.WallPaper wallPaper) { Drawable thumb = null; + if (wallPaper.thumbDrawable != null) { + return wallPaper.thumbDrawable; + } if (wallPaper.stripedThumb != null) { return new BitmapDrawable(wallPaper.stripedThumb); } @@ -171,7 +174,7 @@ public static Drawable createThumb(TLRPC.WallPaper wallPaper) { } } } - return thumb; + return wallPaper.thumbDrawable = thumb; } private static Drawable bitmapDrawableOf(Drawable drawable) { @@ -205,6 +208,13 @@ public void draw(@NonNull Canvas canvas) { } } + public float getDimAmount() { + if (motionBackgroundDrawable == null) { + return dimAmount; + } + return 0; + } + @Override public void setAlpha(int alpha) { if (this.alpha != alpha) { @@ -255,16 +265,18 @@ public void onDetachedFromWindow(View view) { } } - public Drawable getDrawable() { + public Drawable getDrawable(boolean prioritizeThumb) { if (motionBackgroundDrawable != null) { return motionBackgroundDrawable; } - if (imageReceiver.getStaticThumb() != null) { + if (prioritizeThumb && imageReceiver.getStaticThumb() != null) { return imageReceiver.getStaticThumb(); } else if (imageReceiver.getThumb() != null) { return imageReceiver.getThumb(); - } else { + } else if (imageReceiver.getDrawable() != null) { return imageReceiver.getDrawable(); + } else { + return imageReceiver.getStaticThumb(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 1d2bd23ed5..cbf3d99dd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -74,6 +74,7 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BulletinFactory; @@ -85,6 +86,8 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; +import org.telegram.ui.Components.Reactions.ChatCustomReactionsEditActivity; +import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.UndoView; @@ -181,6 +184,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image private int realAdminCount = 0; private boolean hasUploadedPhoto; + private final List preloadedReactions = new ArrayList<>(); private PhotoViewer.PhotoViewerProvider provider = new PhotoViewer.EmptyPhotoViewerProvider() { @@ -401,6 +405,7 @@ public void onResume() { @Override public void onPause() { super.onPause(); + ReactionsUtils.stopPreloadReactions(preloadedReactions); if (nameTextView != null) { nameTextView.onPause(); } @@ -887,7 +892,7 @@ public void afterTextChanged(Editable editable) { } if (ChatObject.isChannelAndNotMegaGroup(currentChat) && ChatObject.canChangeChatInfo(currentChat)) { - colorCell = new PeerColorActivity.ChangeNameColorCell(true, context, getResourceProvider()); + colorCell = new PeerColorActivity.ChangeNameColorCell(currentAccount, true, context, getResourceProvider()); colorCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); typeEditContainer.addView(colorCell, LayoutHelper.createLinear(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); colorCell.setOnClickListener(v -> { @@ -1033,11 +1038,15 @@ public void afterTextChanged(Editable editable) { reactionsCell = new TextCell(context); reactionsCell.setBackground(Theme.getSelectorDrawable(false)); reactionsCell.setOnClickListener(v -> { - Bundle args = new Bundle(); - args.putLong(ChatReactionsEditActivity.KEY_CHAT_ID, chatId); - ChatReactionsEditActivity reactionsEditActivity = new ChatReactionsEditActivity(args); - reactionsEditActivity.setInfo(info); - presentFragment(reactionsEditActivity); + if (ChatObject.isChannelAndNotMegaGroup(currentChat)) { + presentFragment(new ChatCustomReactionsEditActivity(chatId, info)); + } else { + Bundle args = new Bundle(); + args.putLong(ChatReactionsEditActivity.KEY_CHAT_ID, chatId); + ChatReactionsEditActivity reactionsEditActivity = new ChatReactionsEditActivity(args); + reactionsEditActivity.setInfo(info); + presentFragment(reactionsEditActivity); + } }); adminCell = new TextCell(context); @@ -1668,8 +1677,7 @@ private void processDone() { getParentLayout().removeFragmentFromStack(i); Bundle bundle = new Bundle(); bundle.putLong("chat_id",chatId); - TopicsFragment topicsFragment = new TopicsFragment(bundle); - getParentLayout().addFragmentToStack(topicsFragment, i); + getParentLayout().addFragmentToStack(TopicsFragment.getTopicsOrChat(this, bundle), i); } } } @@ -1773,6 +1781,8 @@ public void setInfo(TLRPC.ChatFull chatFull) { } historyHidden = !ChatObject.isChannel(currentChat) || info.hidden_prehistory; availableReactions = info.available_reactions; + preloadedReactions.clear(); + preloadedReactions.addAll(ReactionsUtils.startPreloadReactions(currentChat, info)); } } @@ -2051,6 +2061,7 @@ public void onAnimationEnd(Animator animation) { } private void updateReactionsCell(boolean animated) { + boolean isChannelAndNotMegaGroup = ChatObject.isChannelAndNotMegaGroup(currentChat); String finalString; if (availableReactions == null || availableReactions instanceof TLRPC.TL_chatReactionsNone) { finalString = LocaleController.getString("ReactionsOff", R.string.ReactionsOff); @@ -2065,15 +2076,25 @@ private void updateReactionsCell(boolean animated) { if (reaction != null && !reaction.inactive) { count++; } + } else if (someReaction instanceof TLRPC.TL_reactionCustomEmoji) { + count++; } } - int reacts = Math.min(getMediaDataController().getEnabledReactionsList().size(), count); - finalString = reacts == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : - LocaleController.formatString("ReactionsCount", R.string.ReactionsCount, reacts, getMediaDataController().getEnabledReactionsList().size()); + if (isChannelAndNotMegaGroup) { + finalString = count == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : String.valueOf(count); + } else { + int reacts = Math.min(getMediaDataController().getEnabledReactionsList().size(), count); + finalString = reacts == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : + LocaleController.formatString("ReactionsCount", R.string.ReactionsCount, reacts, getMediaDataController().getEnabledReactionsList().size()); + } } else { finalString = LocaleController.getString("ReactionsAll", R.string.ReactionsAll); } - reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, R.drawable.msg_reactions2, true); + if (isChannelAndNotMegaGroup) { + reactionsCell.setTextAndValueAndIcon(TextCell.applyNewSpan(LocaleController.getString("Reactions", R.string.Reactions)), finalString, animated, R.drawable.msg_reactions2, true); + } else { + reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, animated, R.drawable.msg_reactions2, true); + } } @Override @@ -2180,6 +2201,12 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(reactionsCell, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(reactionsCell, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); + if (statsAndBoosts != null) { + themeDescriptions.add(new ThemeDescription(statsAndBoosts, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); + themeDescriptions.add(new ThemeDescription(statsAndBoosts, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); + themeDescriptions.add(new ThemeDescription(statsAndBoosts, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); + } + return themeDescriptions; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index c20d987493..ef70073263 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -541,7 +541,7 @@ private void showLinkAlert(TLRPC.Chat chat, boolean query) { frameLayout2.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 21 : 76), 11, (LocaleController.isRTL ? 76 : 21), 0)); frameLayout2.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 57, 24, 9)); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageView.setForUserOrChat(chat, avatarDrawable); builder.setPositiveButton(LocaleController.getString("DiscussionLinkGroup", R.string.DiscussionLinkGroup), (dialogInterface, i) -> { if (chatFull.hidden_prehistory) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java index 44c1e1a180..1e51b4788f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java @@ -5,7 +5,6 @@ import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; @@ -14,13 +13,10 @@ import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; -import android.util.Log; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; -import androidx.core.graphics.ColorUtils; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; @@ -132,7 +128,7 @@ public void updateDialog() { MessagesController.getInstance(currentAccount).getChat(dialog.id); } AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setInfo(nextChat); + avatarDrawable.setInfo(currentAccount, nextChat); imageReceiver.setImage(ImageLocation.getForChat(nextChat, ImageLocation.TYPE_SMALL), "50_50", avatarDrawable, null, UserConfig.getInstance(0).getCurrentUser(), 0); MessagesController.getInstance(currentAccount).ensureMessagesLoaded(dialog.id, 0, null); counterDrawable.setCount(dialog.unread_count, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 1e7a95bbe1..d81f294e24 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -8,6 +8,8 @@ package org.telegram.ui; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.DatePickerDialog; import android.app.TimePickerDialog; @@ -1340,6 +1342,14 @@ private void onDonePressed() { } }, err -> { setLoading(false); + if (err != null && "USER_PRIVACY_RESTRICTED".equals(err.text)) { + LimitReachedBottomSheet restrictedUsersBottomSheet = new LimitReachedBottomSheet(ChatRightsEditActivity.this, getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, getResourceProvider()); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(currentUser); + restrictedUsersBottomSheet.setRestrictedUsers(currentChat, arrayList); + restrictedUsersBottomSheet.show(); + return false; + } return true; }); } else if (currentType == TYPE_BANNED) { @@ -1418,19 +1428,26 @@ private void onDonePressed() { private ValueAnimator doneDrawableAnimator; - public void setLoading(boolean enable) { + public void setLoading(boolean newLoading) { if (doneDrawableAnimator != null) { doneDrawableAnimator.cancel(); } - loading = !enable; - actionBar.getBackButton().setEnabled(!enable); + loading = newLoading; + actionBar.getBackButton().setEnabled(!loading); if (doneDrawable != null) { - doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), enable ? 1f : 0f); + doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), loading ? 1f : 0f); doneDrawableAnimator.addUpdateListener(a -> { doneDrawable.setProgress((float) a.getAnimatedValue()); doneDrawable.invalidateSelf(); }); - doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (enable ? 1 : 0)))); + doneDrawableAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + doneDrawable.setProgress(loading ? 1 : 0); + doneDrawable.invalidateSelf(); + } + }); + doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (loading ? 1 : 0)))); doneDrawableAnimator.start(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 414dca81e3..e41e1fd7ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -1401,11 +1401,11 @@ public static void createImportDialogAlert(BaseFragment fragment, String title, imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); imageView.setForUserOrChat(user, avatarDrawable); } } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(account, chat); imageView.setForUserOrChat(chat, avatarDrawable); } @@ -1482,7 +1482,7 @@ public void setText(CharSequence text, BufferType type) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1603,7 +1603,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1780,11 +1780,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(fragment.getCurrentAccount(), chat); imageView.setForUserOrChat(chat, avatarDrawable); } @@ -2069,7 +2069,7 @@ public void setText(CharSequence text, BufferType type) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); BackupImageView imageView = new BackupImageView(context); imageView.setRoundRadius(AndroidUtilities.dp(20)); @@ -2409,7 +2409,7 @@ public static void showChatWithAdmin(BaseFragment fragment, TLRPC.User user, Str buttonTextView.setText(LocaleController.getString("IUnderstand", R.string.IUnderstand)); buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); - buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); + buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); linearLayout.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 16, 12, 16, 8)); @@ -2512,9 +2512,9 @@ public static void checkRestrictedInviteUsers(int currentAccount, TLRPC.Chat cur AndroidUtilities.runOnUIThread(() -> { BaseFragment lastFragment = LaunchActivity.getLastFragment(); if (lastFragment != null && lastFragment.getParentActivity() != null) { - LimitReachedBottomSheet restricterdUsersBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, null); - restricterdUsersBottomSheet.setRestrictedUsers(currentChat, finalArrayList); - restricterdUsersBottomSheet.show(); + LimitReachedBottomSheet restrictedUsersBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, null); + restrictedUsersBottomSheet.setRestrictedUsers(currentChat, finalArrayList); + restrictedUsersBottomSheet.show(); } }, 200); } @@ -3238,7 +3238,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("SetTimeLimit", R.string.SetTimeLimit)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3427,7 +3427,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("SetEmojiStatusUntilButton", R.string.SetEmojiStatusUntilButton)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3572,7 +3572,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(AndroidUtilities.dp(14)); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setText(LocaleController.getString("DisableAutoDeleteTimer", R.string.DisableAutoDeleteTimer)); @@ -3717,7 +3717,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); @@ -3889,7 +3889,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java index 1d8d97a1d8..145ea37628 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -70,6 +70,7 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC = 13; public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW = 14; public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; + public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB = 16; public int rawDrawIndex; @@ -520,7 +521,7 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b } imageReceiver.setVideoThumbIsSame(true); boolean onlyStaticPreview = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW && cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_KEYBOARD && !liteModeKeyboard || cacheType == CACHE_TYPE_ALERT_PREVIEW && !liteModeReactions; - if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB) { onlyStaticPreview = true; } String filter = sizedp + "_" + sizedp; @@ -572,12 +573,16 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b imageReceiver.setImage(null, null, mediaLocation, mediaFilter, null, null, thumbDrawable, document.size, null, document, 1); } else { if (onlyStaticPreview || (!liteModeKeyboard && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW)) { + ImageLocation thumbLocation = null; + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB) { + thumbLocation = ImageLocation.getForDocument(thumb, document); + } if ("video/webm".equals(document.mime_type)) { - imageReceiver.setImage(null, null, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(null, null, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } else if (MessageObject.isAnimatedStickerDocument(document, true)) { - imageReceiver.setImage(mediaLocation, mediaFilter + "_firstframe", null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(mediaLocation, mediaFilter + "_firstframe", thumbLocation, null, thumbDrawable, document.size, null, document, 1); } else { - imageReceiver.setImage(ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } } else { imageReceiver.setImage(mediaLocation, mediaFilter, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); @@ -586,7 +591,7 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b updateAutoRepeat(imageReceiver); - if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { imageReceiver.setLayerNum(7); } if (cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS) { @@ -1059,7 +1064,7 @@ public void resetAnimation() { changeProgress.set(1, true); } - public boolean set(long documentId, int cacheType, boolean animated) { + public boolean set(long documentId, int cacheType, boolean animated) { if (drawables[0] instanceof AnimatedEmojiDrawable && ((AnimatedEmojiDrawable) drawables[0]).getDocumentId() == documentId) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java index e7c20ab131..af509b0f27 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java @@ -1,5 +1,8 @@ package org.telegram.ui.Components; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -32,10 +35,12 @@ import java.util.List; public class AnimatedEmojiSpan extends ReplacementSpan { + private static boolean lockPositionChanging; public long documentId; public TLRPC.Document document; private float scale; + private float extraScale = 1f; public boolean standard; public boolean full = false; public boolean top = false; @@ -52,6 +57,80 @@ public class AnimatedEmojiSpan extends ReplacementSpan { float lastDrawnCy; private boolean recordPositions = true; public boolean fromEmojiKeyboard; + private boolean isAdded; + private boolean isRemoved; + private Runnable removedAction; + private boolean animateChanges; + private ValueAnimator moveAnimator; + private ValueAnimator scaleAnimator; + + /** + * To correctly move emoji to a new line, we need to return the final size in {@link #getSize}. + * However, this approach causes flickering. So fix this using {@link #lockPositionChanging} flag. + */ + public void setAdded() { + isAdded = true; + extraScale = 0f; + lockPositionChanging = true; + } + + public void setAnimateChanges() { + this.animateChanges = true; + } + + public void setRemoved(Runnable action) { + removedAction = action; + isRemoved = true; + extraScale = 1f; + } + + public float getExtraScale() { + if (isAdded) { + isAdded = false; + extraScale = 0f; + scaleAnimator = ValueAnimator.ofFloat(extraScale, 1f); + scaleAnimator.addUpdateListener(animator -> { + extraScale = (float) animator.getAnimatedValue(); + scale = AndroidUtilities.lerp(.2f, 1f, extraScale); + lockPositionChanging = false; + }); + scaleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scaleAnimator = null; + } + }); + scaleAnimator.setDuration(130); + scaleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + scaleAnimator.start(); + } else if (isRemoved) { + isRemoved = false; + extraScale = 1f; + if (scaleAnimator != null) { + scaleAnimator.removeAllListeners(); + scaleAnimator.cancel(); + } + scaleAnimator = ValueAnimator.ofFloat(extraScale, 0f); + scaleAnimator.addUpdateListener(animator -> { + extraScale = (float) animator.getAnimatedValue(); + scale = AndroidUtilities.lerp(0f, 1f, extraScale); + }); + scaleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scaleAnimator = null; + if (removedAction != null) { + removedAction.run(); + removedAction = null; + } + } + }); + scaleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + scaleAnimator.setDuration(130); + scaleAnimator.start(); + } + return extraScale; + } public AnimatedEmojiSpan(@NonNull TLRPC.Document document, Paint.FontMetricsInt fontMetrics) { this(document.id, 1.2f, fontMetrics); @@ -146,19 +225,19 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon if (fm != null) { if (!full) { - fm.ascent = (int) (fontMetrics.ascent); + fm.ascent = (int) (fontMetrics.ascent); fm.descent = (int) (fontMetrics.descent); - fm.top = (int) (fontMetrics.top); - fm.bottom = (int) (fontMetrics.bottom); + fm.top = (int) (fontMetrics.top); + fm.bottom = (int) (fontMetrics.bottom); } else { float height = Math.abs(fontMetrics.bottom) + Math.abs(fontMetrics.top); - fm.ascent = (int) Math.ceil(fontMetrics.top / height * measuredSize); + fm.ascent = (int) Math.ceil(fontMetrics.top / height * measuredSize); fm.descent = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); - fm.top = (int) Math.ceil(fontMetrics.top / height * measuredSize); - fm.bottom = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); + fm.top = (int) Math.ceil(fontMetrics.top / height * measuredSize); + fm.bottom = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); } } } @@ -167,12 +246,41 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon fm.ascent += diff; fm.descent -= diff; } - return measuredSize - 1; + return Math.max(0, measuredSize - 1); } - private int asizeDp; - public void addSize(int asizeDp) { -// this.asizeDp = asizeDp; + private boolean isAnimating() { + return moveAnimator != null || scaleAnimator != null; + } + + private boolean animateChanges(float cx, float cy) { + if (moveAnimator != null) { + return true; + } + if (!animateChanges) { + return false; + } + animateChanges = false; + final float fromCx = lastDrawnCx; + final float fromCy = lastDrawnCy; + final float toCx = cx; + final float toCy = cy; + moveAnimator = ValueAnimator.ofFloat(0f, 1f); + moveAnimator.addUpdateListener(animator -> { + float percent = (float) animator.getAnimatedValue(); + lastDrawnCy = AndroidUtilities.lerp(fromCy, toCy, percent); + lastDrawnCx = AndroidUtilities.lerp(fromCx, toCx, percent); + }); + moveAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + moveAnimator = null; + } + }); + moveAnimator.setDuration(140); + moveAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + moveAnimator.start(); + return true; } @Override @@ -181,6 +289,12 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i spanDrawn = true; float cx = x + measuredSize / 2f; float cy = top + (bottom - top) / 2f; + if ((cy != lastDrawnCy && lastDrawnCy != 0 || cx != lastDrawnCx && lastDrawnCx != 0) && animateChanges(cx, cy)) { + return; + } + if (lockPositionChanging) { + return; + } if (cx != lastDrawnCx || cy != lastDrawnCy) { lastDrawnCx = cx; lastDrawnCy = cy; @@ -300,7 +414,18 @@ public void draw(Canvas canvas, long time, float boundTop, float boundBottom, fl if (drawable.getImageReceiver() != null) { drawable.setColorFilter(colorFilter == null ? Theme.chat_animatedEmojiTextColorFilter : colorFilter); drawable.setTime(time); - drawable.draw(canvas, drawableBounds, alpha * this.alpha); + float scale = span.getExtraScale(); + if (scale != 1f) { + canvas.save(); + canvas.scale(scale, scale, drawableBounds.centerX(), drawableBounds.centerY()); + drawable.draw(canvas, drawableBounds, alpha * this.alpha); + canvas.restore(); + } else { + drawable.draw(canvas, drawableBounds, alpha * this.alpha); + } + if (span.isAnimating()) { + invalidate(); + } } } @@ -337,15 +462,15 @@ public static EmojiGroupedSpans update(int cacheType, View view, boolean invalid return update(cacheType, view, invalidateParent, prev, clone, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, EmojiGroupedSpans prev, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, EmojiGroupedSpans prev, Layout... layouts) { return update(cacheType, view, false, prev, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, Layout... layouts) { return update(cacheType, view, invalidateParent, prev, false, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, boolean clone, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, boolean clone, Layout... layouts) { if (layouts == null || layouts.length <= 0) { if (prev != null) { prev.holders.clear(); @@ -645,14 +770,6 @@ public void clearPositions() { } } - public void incrementFrames(int inc) { - for (int i = 0; i < holders.size(); i++) { - if (holders.get(i).drawable != null && holders.get(i).drawable.getImageReceiver() != null) { - holders.get(i).drawable.getImageReceiver().incrementFrames(inc); - } - } - } - public void recordPositions(boolean record) { for (int i = 0; i < holders.size(); i++) { holders.get(i).span.recordPositions = record; @@ -706,7 +823,7 @@ private void checkBackgroundRendering() { private final ArrayList backgroundHolders = new ArrayList<>(); @Override - public void drawInBackground(Canvas canvas) { + public void drawInBackground(Canvas canvas) { for (int i = 0; i < backgroundHolders.size(); i++) { AnimatedEmojiHolder holder = backgroundHolders.get(i); if (holder != null && holder.backgroundDrawHolder[threadIndex] != null) { @@ -826,6 +943,8 @@ public static AnimatedEmojiSpan cloneSpan(AnimatedEmojiSpan span) { animatedEmojiSpan = new AnimatedEmojiSpan(span.documentId, span.scale, span.fontMetrics); } animatedEmojiSpan.fromEmojiKeyboard = span.fromEmojiKeyboard; + animatedEmojiSpan.isAdded = span.isAdded; + animatedEmojiSpan.isRemoved = span.isRemoved; return animatedEmojiSpan; } @@ -854,7 +973,7 @@ public static CharSequence cloneSpans(CharSequence text, int newCacheType) { if (spans[i] instanceof AnimatedEmojiSpan) { int start = spanned.getSpanStart(spans[i]); - int end = spanned.getSpanEnd(spans[i]); + int end = spanned.getSpanEnd(spans[i]); AnimatedEmojiSpan oldSpan = (AnimatedEmojiSpan) spans[i]; newText.removeSpan(oldSpan); @@ -876,6 +995,7 @@ public TextViewEmojis(Context context) { } AnimatedEmojiSpan.EmojiGroupedSpans stack; + @Override public void setText(CharSequence text, TextView.BufferType type) { super.setText(text, type); 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 489e53d303..d8acbd1ca5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -62,7 +62,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, private static native void stopDecoder(long ptr); - private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride, boolean preview, float startTimeSeconds, float endTimeSeconds); + private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride, boolean preview, float startTimeSeconds, float endTimeSeconds, boolean loop); private static native void seekToMs(long ptr, long ms, boolean precise); @@ -431,7 +431,7 @@ public void run() { if (backgroundBitmap != null) { lastFrameDecodeTime = System.currentTimeMillis(); - if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime) == 0) { + if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime, true) == 0) { AndroidUtilities.runOnUIThread(uiRunnableNoFrame); return; } @@ -547,7 +547,7 @@ public Bitmap getFrameAtTime(long ms, boolean precise) { if (precise) { result = getFrameAtTime(nativePtr, ms, backgroundBitmap, metaData, backgroundBitmap.getRowBytes()); } else { - result = getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), true, 0, 0); + result = getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), true, 0, 0, true); } return result != 0 ? backgroundBitmap : null; } @@ -765,6 +765,10 @@ public int getCurrentProgressMs() { return nextRenderingBitmapTime != 0 ? nextRenderingBitmapTime : renderingBitmapTime; } + public int getProgressMs() { + return metaData[3]; + } + public int getDurationMs() { return metaData[4]; } @@ -1083,7 +1087,7 @@ public boolean isRecycled() { return isRecycled || decoderTryCount >= 15; } - public Bitmap getNextFrame() { + public Bitmap getNextFrame(boolean loop) { if (nativePtr == 0) { return backgroundBitmap; } @@ -1094,7 +1098,7 @@ public Bitmap getNextFrame() { backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); } } - getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime, loop); return backgroundBitmap; } @@ -1140,7 +1144,7 @@ public int getNextFrame(Bitmap bitmap) { if (generatingCacheBitmap == null) { generatingCacheBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); } - getVideoFrame(cacheGenerateNativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(cacheGenerateNativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime, true); if (cacheGenerateTimestamp != 0 && (metaData[3] == 0 || cacheGenerateTimestamp > metaData[3])) { return 0; } @@ -1175,7 +1179,7 @@ public Bitmap getFirstFrame(Bitmap bitmap) { if (nativePtr == 0) { return bitmap; } - getVideoFrame(nativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(nativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime, true); destroyDecoder(nativePtr); bitmap.eraseColor(Color.TRANSPARENT); canvas.save(); @@ -1192,11 +1196,11 @@ public void drawFrame(Canvas canvas, int incFrame) { return; } for (int i = 0; i < incFrame; ++i) { - getNextFrame(); + getNextFrame(true); } Bitmap bitmap = getBackgroundBitmap(); if (bitmap == null) { - bitmap = getNextFrame(); + bitmap = getNextFrame(true); } AndroidUtilities.rectTmp2.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); canvas.drawBitmap(getBackgroundBitmap(), AndroidUtilities.rectTmp2, getBounds(), getPaint()); 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 d0b595a9dd..c32374e047 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java @@ -115,6 +115,8 @@ public AnimatedFloat(float initialValue, Runnable invalidate, long transitionDel this.firstSet = false; } + // get() is not recommended to use (unless minimize System.currentTimeMillis() calls) + @Deprecated public float get() { return value; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java index a5d2028c00..386ec15810 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java @@ -26,7 +26,7 @@ public class AutoDeletePopupWrapper { private final ActionBarMenuSubItem disableItem; Callback callback; long lastDismissTime; - TextView textView; + public TextView textView; public AutoDeletePopupWrapper(Context context, PopupSwipeBackLayout swipeBackLayout, Callback callback, boolean createBackground, int type, Theme.ResourcesProvider resourcesProvider) { windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); @@ -115,14 +115,14 @@ public void updateItems(int ttl) { } } - public void allowExtenededHint() { + public void allowExtendedHint(int linkColor) { if (textView == null) { return; } SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(LocaleController.getString("AutoDeletePopupDescription", R.string.AutoDeletePopupDescription)); spannableStringBuilder.append("\n\n"); - spannableStringBuilder.append(AndroidUtilities.replaceSingleTag(LocaleController.getString("AutoDeletePopupDescription2", R.string.AutoDeletePopupDescription2), () -> { + spannableStringBuilder.append(AndroidUtilities.replaceSingleLink(LocaleController.getString(R.string.AutoDeletePopupDescription2), linkColor, () -> { callback.showGlobalAutoDeleteScreen(); })); textView.setText(spannableStringBuilder); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java index 246662a427..17ad01a59a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -24,9 +26,9 @@ import android.text.TextUtils; import androidx.core.graphics.ColorUtils; -import androidx.core.math.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -40,8 +42,6 @@ import java.util.ArrayList; -import xyz.nextalone.nagram.helper.PeerColorHelper; - public class AvatarDrawable extends Drawable { private TextPaint namePaint; @@ -69,12 +69,14 @@ public class AvatarDrawable extends Drawable { private int gradientColor21, gradientColor22; private LinearGradient gradient2; private boolean drawAvatarBackground = true; + private boolean rotate45Background = false; public static final int AVATAR_TYPE_NORMAL = 0; public static final int AVATAR_TYPE_SAVED = 1; public static final int AVATAR_TYPE_ARCHIVED = 2; public static final int AVATAR_TYPE_SHARES = 3; public static final int AVATAR_TYPE_REPLIES = 12; + public static final int AVATAR_TYPE_STORY = 20; public static final int AVATAR_TYPE_FILTER_CONTACTS = 4; public static final int AVATAR_TYPE_FILTER_NON_CONTACTS = 5; @@ -105,7 +107,7 @@ public AvatarDrawable(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); namePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - namePaint.setTextSize(AndroidUtilities.dp(18)); + namePaint.setTextSize(dp(18)); } public AvatarDrawable(TLRPC.User user) { @@ -193,12 +195,12 @@ public static int getNameColorNameForId(long id) { } public void setInfo(TLRPC.User user) { + setInfo(UserConfig.selectedAccount, user); + } + + public void setInfo(int currentAccount, TLRPC.User user) { if (user != null) { - Integer colorId = (user.flags2 & 128) != 0 ? user.color : null; - if (user.self) { - colorId = PeerColorHelper.replaceColor(colorId); - } - setInfo(user.id, user.first_name, user.last_name, null, colorId); + setInfo(user.id, user.first_name, user.last_name, null, user != null && user.color != null ? UserObject.getColorId(user) : null, UserObject.getPeerColorForAvatar(currentAccount, user)); drawDeleted = UserObject.isDeleted(user); } } @@ -213,12 +215,23 @@ public void setInfo(TLObject object) { } } + public void setInfo(int currentAccount, TLObject object) { + if (object instanceof TLRPC.User) { + setInfo(currentAccount, (TLRPC.User) object); + } else if (object instanceof TLRPC.Chat) { + setInfo(currentAccount, (TLRPC.Chat) object); + } else if (object instanceof TLRPC.ChatInvite) { + setInfo(currentAccount, (TLRPC.ChatInvite) object); + } + } + public void setScaleSize(float value) { scaleSize = value; } public void setAvatarType(int value) { avatarType = value; + rotate45Background = false; if (avatarType == AVATAR_TYPE_REGISTER) { hasGradient = false; color = color2 = Theme.getColor(Theme.key_chats_actionBackground); @@ -229,6 +242,11 @@ public void setAvatarType(int value) { hasGradient = true; color = getThemedColor(Theme.key_avatar_backgroundSaved); color2 = getThemedColor(Theme.key_avatar_background2Saved); + } else if (avatarType == AVATAR_TYPE_STORY) { + rotate45Background = true; + hasGradient = true; + color = getThemedColor(Theme.key_stories_circle1); + color2 = getThemedColor(Theme.key_stories_circle2); } else if (avatarType == AVATAR_TYPE_SHARES) { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); @@ -270,7 +288,7 @@ public void setAvatarType(int value) { color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(4)]); } - needApplyColorAccent = avatarType != AVATAR_TYPE_ARCHIVED && avatarType != AVATAR_TYPE_SAVED && avatarType != AVATAR_TYPE_REPLIES && avatarType != AVATAR_TYPE_OTHER_CHATS; + needApplyColorAccent = avatarType != AVATAR_TYPE_ARCHIVED && avatarType != AVATAR_TYPE_SAVED && avatarType != AVATAR_TYPE_STORY && avatarType != AVATAR_TYPE_REPLIES && avatarType != AVATAR_TYPE_OTHER_CHATS; } public void setArchivedAvatarHiddenProgress(float progress) { @@ -282,13 +300,20 @@ public int getAvatarType() { } public void setInfo(TLRPC.Chat chat) { + setInfo(UserConfig.selectedAccount, chat); + } + public void setInfo(int currentAccount, TLRPC.Chat chat) { if (chat != null) { - setInfo(chat.id, chat.title, null, null, (chat.flags2 & 64) != 0 ? chat.color : null); + setInfo(chat.id, chat.title, null, null, chat != null && chat.color != null ? ChatObject.getColorId(chat) : null, ChatObject.getPeerColorForAvatar(currentAccount, chat)); } } + public void setInfo(TLRPC.ChatInvite chat) { + setInfo(UserConfig.selectedAccount, chat); + } + public void setInfo(int currentAccount, TLRPC.ChatInvite chat) { if (chat != null) { - setInfo(0, chat.title, null, null, chat.chat != null && (chat.chat.flags2 & 64) != 0 ? chat.chat.color : null); + setInfo(0, chat.title, null, null, chat.chat != null && chat.chat.color != null ? ChatObject.getColorId(chat.chat) : null, ChatObject.getPeerColorForAvatar(currentAccount, chat.chat)); } } @@ -314,7 +339,7 @@ public void setTextSize(int size) { } public void setInfo(long id, String firstName, String lastName) { - setInfo(id, firstName, lastName, null, null); + setInfo(id, firstName, lastName, null, null, null); } public int getColor() { @@ -334,13 +359,16 @@ private static String takeFirstCharacter(String text) { } public void setInfo(long id, String firstName, String lastName, String custom) { - setInfo(id, firstName, lastName, custom, null); + setInfo(id, firstName, lastName, custom, null, null); } - public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor) { + public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor, MessagesController.PeerColor profileColor) { hasGradient = true; invalidateTextLayout = true; - if (customColor != null) { + if (profileColor != null) { + color = profileColor.getAvatarColor1(); + color2 = profileColor.getAvatarColor2(); + } else if (customColor != null) { if (customColor >= 14) { MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); if (messagesController != null && messagesController.peerColors != null && messagesController.peerColors.getColor(customColor) != null) { @@ -430,12 +458,19 @@ public void draw(Canvas canvas) { canvas.translate(bounds.left, bounds.top); if (drawAvatarBackground) { + if (rotate45Background) { + canvas.save(); + canvas.rotate(-45, size / 2.0f, size / 2.0f); + } if (roundRadius > 0) { AndroidUtilities.rectTmp.set(0, 0, size, size); canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, Theme.avatar_backgroundPaint); } else { canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f, Theme.avatar_backgroundPaint); } + if (rotate45Background) { + canvas.restore(); + } } if (avatarType == AVATAR_TYPE_ARCHIVED) { @@ -499,6 +534,8 @@ public void draw(Canvas canvas) { drawable = Theme.avatarDrawables[15]; } else if (avatarType == AVATAR_TYPE_UNCLAIMED) { drawable = Theme.avatarDrawables[16]; + } else if (avatarType == AVATAR_TYPE_STORY) { + drawable = Theme.avatarDrawables[17]; } else { drawable = Theme.avatarDrawables[9]; } @@ -523,8 +560,8 @@ public void draw(Canvas canvas) { } else if (drawDeleted && Theme.avatarDrawables[1] != null) { int w = Theme.avatarDrawables[1].getIntrinsicWidth(); int h = Theme.avatarDrawables[1].getIntrinsicHeight(); - if (w > size - AndroidUtilities.dp(6) || h > size - AndroidUtilities.dp(6)) { - float scale = size / (float) AndroidUtilities.dp(50); + if (w > size - dp(6) || h > size - dp(6)) { + float scale = size / (float) dp(50); w *= scale; h *= scale; } @@ -537,10 +574,10 @@ public void draw(Canvas canvas) { invalidateTextLayout = false; if (stringBuilder.length() > 0) { CharSequence text = stringBuilder.toString().toUpperCase(); - text = Emoji.replaceEmoji(text, namePaint.getFontMetricsInt(), AndroidUtilities.dp(16), true); + text = Emoji.replaceEmoji(text, namePaint.getFontMetricsInt(), dp(16), true); if (textLayout == null || !TextUtils.equals(text, textLayout.getText())) { try { - textLayout = new StaticLayout(text, namePaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + textLayout = new StaticLayout(text, namePaint, dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (textLayout.getLineCount() > 0) { textLeft = textLayout.getLineLeft(0); textWidth = textLayout.getLineWidth(0); @@ -555,7 +592,7 @@ public void draw(Canvas canvas) { } } if (textLayout != null) { - float scale = size / (float) AndroidUtilities.dp(50); + float scale = size / (float) dp(50); canvas.scale(scale, scale, size / 2f, size / 2f) ; canvas.translate((size - textWidth) / 2 - textLeft, (size - textHeight) / 2); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java index 8c21a30ddb..fcef07bf4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java @@ -305,10 +305,10 @@ public void setObject(int index, int account, TLObject object) { long id = MessageObject.getPeerId(participant.peer); if (DialogObject.isUserDialog(id)) { currentUser = MessagesController.getInstance(account).getUser(id); - animatingStates[index].avatarDrawable.setInfo(currentUser); + animatingStates[index].avatarDrawable.setInfo(account, currentUser); } else { currentChat = MessagesController.getInstance(account).getChat(-id); - animatingStates[index].avatarDrawable.setInfo(currentChat); + animatingStates[index].avatarDrawable.setInfo(account, currentChat); } if (currentStyle == 4) { if (id == AccountInstance.getInstance(account).getUserConfig().getClientUserId()) { @@ -332,14 +332,14 @@ public void setObject(int index, int account, TLObject object) { } else { animatingStates[index].avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NORMAL); animatingStates[index].avatarDrawable.setScaleSize(1f); - animatingStates[index].avatarDrawable.setInfo(currentUser); + animatingStates[index].avatarDrawable.setInfo(account, currentUser); } animatingStates[index].id = currentUser.id; } else { currentChat = (TLRPC.Chat) object; animatingStates[index].avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NORMAL); animatingStates[index].avatarDrawable.setScaleSize(1f); - animatingStates[index].avatarDrawable.setInfo(currentChat); + animatingStates[index].avatarDrawable.setInfo(account, currentChat); animatingStates[index].id = -currentChat.id; } if (currentUser != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java index 9c3441cf70..e3974d569c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java @@ -109,7 +109,7 @@ public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButt Drawable thumb = avatarDrawable; boolean addDivider = false; if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), chat); if (chat.photo != null && chat.photo.strippedBitmap != null) { thumb = chat.photo.strippedBitmap; } @@ -130,11 +130,11 @@ public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButt imageView.setImageDrawable(avatarDrawable); } else if (UserObject.isDeleted(user)) { name = LocaleController.getString("HiddenName", R.string.HiddenName); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), user); imageView.setImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), "50_50", avatarDrawable, user); } else { name = UserObject.getUserName(user); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), user); imageView.setImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), "50_50", thumb, user); } titleView.setText(name); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java index 17f5965114..3bdd4a8e81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -43,6 +43,7 @@ public class BackupImageView extends View { public BackupImageView(Context context) { super(context); imageReceiver = createImageReciever(); + imageReceiver.setCrossfadeByScale(0); imageReceiver.setAllowLoadingOnAttachedOnly(true); imageReceiver.setDelegate((imageReceiver1, set, thumb, memCache) -> { if (set && !thumb) { @@ -184,6 +185,11 @@ public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocat onNewImageSet(); } + public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, Drawable thumb, String ext, long size, int cacheType, Object parentObject) { + imageReceiver.setImage(imageLocation, imageFilter, thumbLocation, thumbFilter, thumb, size, ext, parentObject, cacheType); + onNewImageSet(); + } + public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, long size, int cacheType, Object parentObject) { imageReceiver.setImage(imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); onNewImageSet(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java index 743d114c12..c05dcaf773 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java @@ -178,6 +178,10 @@ public void generateBlob() { private final static float animationSpeed = 1f - ANIMATION_SPEED_WAVE_HUGE; private final static float animationSpeedTiny = 1f - ANIMATION_SPEED_WAVE_SMALL; + public void setValue(float value) { + amplitude = value; + } + public void setValue(float value, boolean isBig) { animateToAmplitude = value; if (!LiteMode.isEnabled(liteFlag)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java index 26b57060f7..4dd5fa3b16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java @@ -696,6 +696,8 @@ public static class StoryBlurDrawer { public static final int BLUR_TYPE_MENU_BACKGROUND = 5; public static final int BLUR_TYPE_SHADOW = 6; public static final int BLUR_TYPE_EMOJI_VIEW = 7; + public static final int BLUR_TYPE_REPLY_BACKGROUND = 8; + public static final int BLUR_TYPE_REPLY_TEXT_XFER = 9; private final BlurManager manager; private final View view; @@ -728,10 +730,9 @@ public StoryBlurDrawer(@Nullable BlurManager manager, @NonNull View view, int ty } else if (type == BLUR_TYPE_CAPTION_XFER) { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); oldPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.8f); - AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.45f); - AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 2.5f); - AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.4f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.3f); +// AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 1.4f); } else if (type == BLUR_TYPE_CAPTION) { AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.35f); AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.7f); @@ -747,7 +748,16 @@ public StoryBlurDrawer(@Nullable BlurManager manager, @NonNull View view, int ty AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.35f); } else if (type == BLUR_TYPE_EMOJI_VIEW) { AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.5f); - AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .85f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .95f); + } else if (type == BLUR_TYPE_REPLY_BACKGROUND) { + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, -.15f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.47f); + } else if (type == BLUR_TYPE_REPLY_TEXT_XFER) { + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + oldPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.4f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.45f); +// AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 1.4f); } paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); oldPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java index 4b55e6164e..bc8b718e03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java @@ -46,6 +46,7 @@ protected class Tab { final AnimatedFloat nonscrollingT = new AnimatedFloat(BottomPagerTabs.this, 0, 200, CubicBezierInterpolator.EASE_OUT_QUINT); public int customEndFrameMid; public int customEndFrameEnd; + public boolean customFrameInvert; public Tab(int i, int resId, CharSequence text) { this.i = i; @@ -68,6 +69,9 @@ public Tab(int i, int resId, CharSequence text) { private boolean active; public void setActive(boolean active, boolean animated) { + if (customFrameInvert) { + active = !active; + } if (this.active == active) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index 64fdc41f73..002e831813 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -202,6 +202,11 @@ public Bulletin hideAfterBottomSheet(boolean hide) { return this; } + public Bulletin setTag(int tag) { + this.tag = tag; + return this; + } + public Bulletin show() { return show(false); } @@ -1915,9 +1920,4 @@ public void updateLayout() { } } } - - public Bulletin setTag(int tag) { - this.tag = tag; - return this; - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java index d2c1928b31..b3144644bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -223,6 +223,26 @@ public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLi return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLines, int duration) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + if (text != null) { + String string = text.toString(); + SpannableStringBuilder ssb = text instanceof SpannableStringBuilder ? (SpannableStringBuilder) text : new SpannableStringBuilder(text); + for (int index = string.indexOf('\n'), l = 0; index >= 0 && index < text.length(); l++, index = string.indexOf('\n', index + 1)) { + if (l >= maxLines) { + ssb.replace(index, index + 1, " "); + } + } + text = ssb; + } + layout.textView.setText(text); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(maxLines); + return create(layout, duration); + } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); @@ -501,6 +521,20 @@ public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text) return create(layout, Bulletin.DURATION_LONG); } + public Bulletin createStaticEmojiBulletin(TLRPC.Document document, CharSequence text) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + if (MessageObject.isTextColorEmoji(document)) { + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); + } + layout.setAnimation(document, 36, 36); + layout.imageView.stopAnimation(); + layout.textView.setText(text); + layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(3); + return create(layout, Bulletin.DURATION_LONG); + } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text, CharSequence button, Runnable onButtonClick) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); if (MessageObject.isTextColorEmoji(document)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java index 7852b1cb23..b0115a5a87 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java @@ -94,7 +94,7 @@ public boolean isPressed() { return isPressed; } - private void invalidate() { + public void invalidate() { if (view != null) { view.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 4cd0c458e8..86aa28e20c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -656,6 +656,7 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo i private boolean ignoreTextChange; private int innerTextChange; private MessageObject replyingMessageObject; + private MessageObject replyingTopMessage; private ChatActivity.ReplyQuote replyingQuote; private MessageObject botMessageObject; private TLRPC.WebPage messageWebPage; @@ -894,7 +895,7 @@ protected void onDetachedFromWindow() { public RecordDot(Context context) { super(context); - int resId = R.raw.chat_audio_record_delete; + int resId = R.raw.chat_audio_record_delete_2; drawable = new RLottieDrawable(resId, "" + resId, AndroidUtilities.dp(28), AndroidUtilities.dp(28), false, null); drawable.setCurrentParentView(this); drawable.setInvalidateOnProgressSet(true); @@ -908,9 +909,6 @@ public void updateColors() { drawable.beginApplyLayerColors(); drawable.setLayerColor("Cup Red.**", dotColor); drawable.setLayerColor("Box.**", dotColor); - drawable.setLayerColor("Line 1.**", background); - drawable.setLayerColor("Line 2.**", background); - drawable.setLayerColor("Line 3.**", background); drawable.commitApplyLayerColors(); if (playPauseDrawable != null) { playPauseDrawable.setColor(getThemedColor(Theme.key_chat_recordedVoicePlayPause)); @@ -3595,7 +3593,7 @@ private void openWebViewMenu() { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), parentFragment.getResourceProvider()); webViewSheet.setParentActivity(parentActivity); webViewSheet.requestWebView(currentAccount, dialog_id, dialog_id, botMenuWebViewTitle, botMenuWebViewUrl, BotWebViewSheet.TYPE_BOT_MENU_BUTTON, 0, false); - webViewSheet.show(); + parentFragment.showDialog(webViewSheet); if (botCommandsMenuButton != null) { botCommandsMenuButton.setOpened(false); @@ -4705,6 +4703,7 @@ public boolean onTouchEvent(MotionEvent event) { } else { if (clickMaybe) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } if (messageEditText != null && !AndroidUtilities.showKeyboard(messageEditText)) { @@ -4717,6 +4716,7 @@ public boolean onTouchEvent(MotionEvent event) { } else { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } } @@ -4724,6 +4724,13 @@ public boolean onTouchEvent(MotionEvent event) { } } + /* + * The color of the handles changes when opened PhotoView and write a comment. + */ + private void fixHandlesColor() { + setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); + } + @Override public void setOffsetY(float offset) { super.setOffsetY(offset); @@ -6063,6 +6070,17 @@ public void updateFieldHint(boolean animated) { messageEditText.setHintText(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage)); } else if (botKeyboardViewVisible && botButtonsMessageObject != null && botButtonsMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(botButtonsMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(botButtonsMessageObject.messageOwner.reply_markup.placeholder, animated); + } else if (parentFragment != null && parentFragment.isForumInViewAsMessagesMode()) { + if (replyingTopMessage != null && replyingTopMessage.replyToForumTopic != null && replyingTopMessage.replyToForumTopic.title != null) { + messageEditText.setHintText(LocaleController.formatString("TypeMessageIn", R.string.TypeMessageIn, replyingTopMessage.replyToForumTopic.title), animated); + } else { + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(parentFragment.getCurrentChat().id, 1); + if (topic != null && topic.title != null) { + messageEditText.setHintText(LocaleController.formatString("TypeMessageIn", R.string.TypeMessageIn, topic.title), animated); + } else { + messageEditText.setHintText(LocaleController.getString("TypeMessage", R.string.TypeMessage), animated); + } + } } else { boolean isChannel = false; boolean anonymously = false; @@ -6131,27 +6149,35 @@ public void updateFieldHint(boolean animated) { } public void setReplyingMessageObject(MessageObject messageObject, ChatActivity.ReplyQuote quote) { + setReplyingMessageObject(messageObject, quote, null); + } + + public void setReplyingMessageObject(MessageObject messageObject, ChatActivity.ReplyQuote quote, MessageObject replyingTopMessage) { + boolean animated = parentFragment != null && parentFragment.isForumInViewAsMessagesMode() && this.replyingTopMessage != replyingTopMessage; if (messageObject != null) { if (botMessageObject == null && botButtonsMessageObject != replyingMessageObject) { botMessageObject = botButtonsMessageObject; } replyingMessageObject = messageObject; replyingQuote = quote; + this.replyingTopMessage = replyingTopMessage; if (!(parentFragment != null && parentFragment.isTopic && parentFragment.getThreadMessage() == replyingMessageObject)) { setButtons(replyingMessageObject, true); } } else if (replyingMessageObject == botButtonsMessageObject) { replyingMessageObject = null; + this.replyingTopMessage = null; replyingQuote = null; setButtons(botMessageObject, false); botMessageObject = null; } else { replyingMessageObject = null; replyingQuote = null; + this.replyingTopMessage = null; } TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; MediaController.getInstance().setReplyingMessage(messageObject, getThreadMessage(), storyItem); - updateFieldHint(false); + updateFieldHint(animated); } public void setWebPage(TLRPC.WebPage webPage, boolean searchWebPages) { @@ -6884,9 +6910,9 @@ public boolean processSendingText(CharSequence text, boolean notify, int schedul updateStickersOrder = SendMessagesHelper.checkUpdateStickersOrder(text); MessageObject replyToTopMsg = getThreadMessage(); -// if (parentFragment != null && parentFragment.replyingTopMessage != null) { -// replyToTopMsg = parentFragment.replyingTopMessage; -// } + if (replyToTopMsg == null && replyingTopMessage != null) { + replyToTopMsg = replyingTopMessage; + } SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(message[0].toString(), dialog_id, replyingMessageObject, replyToTopMsg, messageWebPage, messageWebPageSearch, entities, null, null, notify, scheduleDate, sendAnimationData, updateStickersOrder); params.canSendGames = withGame; applyStoryToSendMessageParams(params); @@ -8889,10 +8915,6 @@ private void updateRecordedDeleteIconColors() { recordDeleteImageView.setLayerColor("Box Red.**", dotColor); recordDeleteImageView.setLayerColor("Cup Grey.**", greyColor); recordDeleteImageView.setLayerColor("Box Grey.**", greyColor); - - recordDeleteImageView.setLayerColor("Line 1.**", background); - recordDeleteImageView.setLayerColor("Line 2.**", background); - recordDeleteImageView.setLayerColor("Line 3.**", background); } } @@ -9551,7 +9573,11 @@ public void run() { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), resourcesProvider); webViewSheet.setParentActivity(parentActivity); webViewSheet.requestWebView(currentAccount, messageObject.messageOwner.dialog_id, botId, button.text, button.url, button instanceof TLRPC.TL_keyboardButtonSimpleWebView ? BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON : BotWebViewSheet.TYPE_WEB_VIEW_BUTTON, replyMessageObject != null ? replyMessageObject.messageOwner.id : 0, false); - webViewSheet.show(); + if (parentFragment != null) { + parentFragment.showDialog(webViewSheet); + } else { + webViewSheet.show(); + } } }; if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, botId)) { @@ -11512,8 +11538,7 @@ public SlideTextView(@NonNull Context context) { arrowPaint.setStrokeCap(Paint.Cap.ROUND); arrowPaint.setStrokeJoin(Paint.Join.ROUND); - slideToCancelString = LocaleController.getString("SlideToCancel", R.string.SlideToCancel); - slideToCancelString = slideToCancelString.charAt(0) + slideToCancelString.substring(1).toLowerCase(); + slideToCancelString = LocaleController.getString(R.string.SlideToCancel2); cancelString = LocaleController.getString("Cancel", R.string.Cancel).toUpperCase(); 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 95ff58109a..c61eaeecf6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -113,8 +113,6 @@ import org.telegram.ui.PhotoPickerActivity; import org.telegram.ui.PhotoPickerSearchActivity; import org.telegram.ui.PremiumPreviewFragment; -import org.telegram.ui.Stories.DarkThemeResourceProvider; -import org.telegram.ui.Stories.recorder.CaptionContainerView; import org.telegram.ui.WebAppDisclaimerAlert; import java.io.File; @@ -465,6 +463,10 @@ public void setDialogId(long dialogId) { } public interface ChatAttachViewDelegate { + default boolean selectItemOnClicking() { + return false; + } + void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); default void onCameraOpened() { @@ -1141,7 +1143,7 @@ public void setUser(TLRPC.User user) { nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); currentUser = user; nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageView.setForUserOrChat(user, avatarDrawable); imageView.setSize(-1, -1); imageView.setColorFilter(null); @@ -1159,7 +1161,7 @@ public void setAttachBot(TLRPC.User user, TLRPC.TL_attachMenuBot bot) { nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); currentUser = user; nameTextView.setText(bot.short_name); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); boolean animated = true; TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getAnimatedAttachMenuBotIcon(bot); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java index ae36a6060c..1a738067ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -225,7 +225,7 @@ public void update(int mask) { } if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { 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 9dd6216147..7457cf8214 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -805,6 +805,20 @@ public int getSpanSize(int position) { if (position < 0 || position >= arrayList.size()) { return; } + if (parentAlert.delegate != null && parentAlert.delegate.selectItemOnClicking() && arrayList.get(position) instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) arrayList.get(position); + selectedPhotos.clear(); + if (photoEntry != null) { + addToSelectedPhotos(photoEntry, -1); + } + parentAlert.applyCaption(); + parentAlert.delegate.didPressedButton(7, true, true, 0, false); + selectedPhotos.clear(); + cameraPhotos.clear(); + selectedPhotosOrder.clear(); + selectedPhotos.clear(); + return; + } PhotoViewer.getInstance().setParentActivity(fragment, resourcesProvider); PhotoViewer.getInstance().setParentAlert(parentAlert); PhotoViewer.getInstance().setMaxSelectedPhotos(parentAlert.maxSelectedPhotos, parentAlert.allowOrder); @@ -859,7 +873,7 @@ public int getSpanSize(int position) { } int finalPosition = position; BaseFragment finalFragment = fragment; - AndroidUtilities.runOnUIThread(()-> { + AndroidUtilities.runOnUIThread(() -> { int avatarType = type; if (parentAlert.isPhotoPicker) { PhotoViewer.getInstance().setParentActivity(finalFragment); @@ -1485,6 +1499,12 @@ public void showAvatarConstructorFragment(AvatarConstructorPreviewCell view, TLR selectedPhotos.put(-1, photoEntry); selectedPhotosOrder.add(-1); parentAlert.delegate.didPressedButton(7, true, false, 0, false); + if (!avatarConstructorFragment.finishOnDone) { + if (parentAlert.baseFragment != null) { + parentAlert.baseFragment.removeSelfFromStack(); + } + avatarConstructorFragment.finishFragment(); + } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index df8300d619..8e1d04368d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -53,9 +53,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; import org.telegram.ui.ProfileActivity; -import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoriesUtilities; -import org.telegram.ui.Stories.StoryViewer; import org.telegram.ui.TopicsFragment; import java.util.concurrent.atomic.AtomicReference; @@ -65,6 +63,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { public boolean allowDrawStories; + private Integer storiesForceState; public BackupImageView avatarImageView; private SimpleTextView titleTextView; private AtomicReference titleTextLargerCopyView = new AtomicReference<>(); @@ -78,6 +77,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private int currentAccount = UserConfig.selectedAccount; private boolean occupyStatusBar = true; private int leftPadding = AndroidUtilities.dp(8); + private int rightAvatarPadding = 0; StatusDrawable currentTypingDrawable; private int lastWidth = -1; @@ -109,6 +109,10 @@ public void hideSubtitle() { subtitleTextView.setVisibility(View.GONE); } + public void setStoriesForceState(Integer storiesForceState) { + this.storiesForceState = storiesForceState; + } + private class SimpleTextConnectedView extends SimpleTextView { private AtomicReference reference; @@ -143,7 +147,7 @@ public boolean setText(CharSequence value) { public ChatAvatarContainer(Context context, BaseFragment baseFragment, boolean needTime) { this(context, baseFragment, needTime, null); } - + public ChatAvatarContainer(Context context, BaseFragment baseFragment, boolean needTime, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -190,7 +194,10 @@ protected void onDraw(Canvas canvas) { params.drawSegments = true; params.drawInside = true; params.resourcesProvider = resourcesProvider; - StoriesUtilities.drawAvatarWithStory(parentFragment.getDialogId(), canvas, imageReceiver, params); + if (storiesForceState != null) { + params.forceState = storiesForceState; + } + StoriesUtilities.drawAvatarWithStory(parentFragment != null ? parentFragment.getDialogId() : 0, canvas, imageReceiver, params); } else { super.onDraw(canvas); } @@ -529,7 +536,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto int actionBarHeight = ActionBar.getCurrentActionBarHeight(); int viewTop = (actionBarHeight - AndroidUtilities.dp(42)) / 2 + (Build.VERSION.SDK_INT >= 21 && occupyStatusBar ? AndroidUtilities.statusBarHeight : 0); avatarImageView.layout(leftPadding, viewTop + 1, leftPadding + AndroidUtilities.dp(42), viewTop + 1 + AndroidUtilities.dp(42)); - int l = leftPadding + (avatarImageView.getVisibility() == VISIBLE ? AndroidUtilities.dp(54) : 0); + int l = leftPadding + (avatarImageView.getVisibility() == VISIBLE ? AndroidUtilities.dp( 54) : 0) + rightAvatarPadding; SimpleTextView titleTextLargerCopyView = this.titleTextLargerCopyView.get(); if (subtitleTextView.getVisibility() != GONE) { titleTextView.layout(l, viewTop + AndroidUtilities.dp(1.3f) - titleTextView.getPaddingTop(), l + titleTextView.getMeasuredWidth(), viewTop + titleTextView.getTextHeight() + AndroidUtilities.dp(1.3f) - titleTextView.getPaddingTop() + titleTextView.getPaddingBottom()); @@ -556,6 +563,10 @@ public void setLeftPadding(int value) { leftPadding = value; } + public void setRightAvatarPadding(int value) { + rightAvatarPadding = value; + } + public void showTimeItem(boolean animated) { if (timeItem == null || timeItem.getTag() != null || avatarImageView.getVisibility() != View.VISIBLE) { return; @@ -961,7 +972,7 @@ public int getLastSubtitleColorKey() { } public void setChatAvatar(TLRPC.Chat chat) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); avatarImageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(21)); @@ -973,7 +984,7 @@ public void setUserAvatar(TLRPC.User user) { } public void setUserAvatar(TLRPC.User user, boolean showSelf) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarDrawable.setScaleSize(.8f); @@ -1001,7 +1012,7 @@ public void checkAndUpdateAvatar() { TLRPC.User user = parentFragment.getCurrentUser(); TLRPC.Chat chat = parentFragment.getCurrentChat(); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setScaleSize(.8f); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); @@ -1021,7 +1032,7 @@ public void checkAndUpdateAvatar() { } } } else if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java index 6dad3210c8..1923c90b84 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java @@ -21,6 +21,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; @@ -1128,6 +1129,13 @@ private void openGalleryForBackground() { chatAttachAlert.drawNavigationBar = true; chatAttachAlert.setupPhotoPicker(LocaleController.getString("ChooseBackground", R.string.ChooseBackground)); chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + long start; + @Override + public boolean selectItemOnClicking() { + start = System.currentTimeMillis(); + return true; + } + @Override public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { try { @@ -1147,7 +1155,13 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu FileOutputStream stream = new FileOutputStream(currentWallpaperPath); bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.FileWallpaper("", currentWallpaperPath, currentWallpaperPath), bitmap); + ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.FileWallpaper("", currentWallpaperPath, currentWallpaperPath), bitmap) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + themePreviewActivity.setInitialModes(false, false, .20f); themePreviewActivity.setDialogId(chatActivity.getDialogId()); themePreviewActivity.setDelegate(() -> { chatAttachAlert.dismissInternal(); @@ -1163,7 +1177,12 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu @Override public void onWallpaperSelected(Object object) { - ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false); + ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; wallpaperActivity.setDialogId(chatActivity.getDialogId()); wallpaperActivity.setDelegate(() -> { chatAttachAlert.dismissInternal(); @@ -1256,16 +1275,16 @@ public boolean isDark() { } @Override - public void switchDayNight() { + public void switchDayNight(boolean animated) { forceDark = !forceDark; if (selectedItem != null) { isLightDarkChangeAnimation = true; chatActivity.forceDisallowRedrawThemeDescriptions = true; TLRPC.WallPaper wallpaper = hasChanges() ? null : themeDelegate.getCurrentWallpaper(); if (selectedItem.chatTheme.showAsDefaultStub) { - themeDelegate.setCurrentTheme(null, wallpaper, true, forceDark); + themeDelegate.setCurrentTheme(null, wallpaper, animated, forceDark); } else { - themeDelegate.setCurrentTheme(selectedItem.chatTheme, wallpaper, true, forceDark); + themeDelegate.setCurrentTheme(selectedItem.chatTheme, wallpaper, animated, forceDark); } chatActivity.forceDisallowRedrawThemeDescriptions = false; } @@ -1280,6 +1299,7 @@ public void switchDayNight() { params.onDismiss = () -> { overlayFragment = null; }; + params.occupyNavigationBar = true; overlayFragment = themePreviewActivity; chatActivity.showAsSheet(themePreviewActivity, params); } 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 a30c32580a..6ca6dbd110 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java @@ -151,7 +151,7 @@ public void recycleEmojis() { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - updateAnimatedEmoji(false); + updateAnimatedEmoji(true); invalidateQuotes(false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java index 4381bb967a..08c9f8839e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -766,6 +766,7 @@ public void onCustomEmojiSelected(long documentId, TLRPC.Document document, Str if (i < 0) { i = 0; } + try { innerTextChange = 2; SpannableString spannable = new SpannableString(emoticon); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java index 5fd6d0fb4a..a8b574dcda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -96,7 +96,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { public boolean animateAppear = true; - private int accentColor; + private final int accentColor; private Runnable onSettingsOpenRunnable; private boolean wasDrawn; private int animatedEmojiCacheType = AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP; @@ -300,6 +300,9 @@ private void getChildBounds(int i, RectF out) { if (type == SelectAnimatedEmojiDialog.TYPE_TOPIC_ICON) { recentDrawableId = R.drawable.msg_emoji_smiles; } + if(type == SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS) { + recentDrawableId = R.drawable.emoji_love; + } if (includeRecent) { contentView.addView(recentTab = new EmojiTabButton(context, recentDrawableId, false, false)); recentTab.id = (long) "recent".hashCode(); @@ -503,7 +506,7 @@ public void updateEmojiPacks(ArrayList emojiPacks) { currentPackButton.setAnimatedEmojiDocument(thumbDocument); } currentPackButton.updateSelect(selected == i, false); - if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR || currentType == SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { currentPackButton.setLock(null, false); } else if (!isPremium && !free) { currentPackButton.setLock(true, false); @@ -659,7 +662,7 @@ protected ColorFilter getEmojiColorFilter() { } private int selectorColor() { - if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { return Theme.multAlpha(accentColor, .09f); } return Theme.multAlpha(Theme.getColor(Theme.key_chat_emojiPanelIcon, resourcesProvider), .18f); @@ -1000,10 +1003,15 @@ public void onAnimationEnd(Animator animation) { public void updateLockImageReceiver() { if (lockView != null && !lockView.ready() && getDrawable() instanceof AnimatedEmojiDrawable) { - ImageReceiver imageReceiver = ((AnimatedEmojiDrawable) getDrawable()).getImageReceiver(); - if (imageReceiver != null) { - lockView.setImageReceiver(imageReceiver); - lockView.invalidate(); + if (((AnimatedEmojiDrawable) getDrawable()).canOverrideColor()) { + lockView.setImageReceiver(null); + lockView.setColor(accentColor); + } else { + ImageReceiver imageReceiver = ((AnimatedEmojiDrawable) getDrawable()).getImageReceiver(); + if (imageReceiver != null) { + lockView.setImageReceiver(imageReceiver); + lockView.invalidate(); + } } } } @@ -1140,7 +1148,7 @@ public void updateColor() { } private void setColor(int color) { - if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { color = accentColor; } PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index a7a20edf30..cd98b20c70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -7561,7 +7561,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { public int getItemViewType(int position) { if (position == 0) { return VIEW_TYPE_SEARCHFIELD; - } else if (position == 1 && searchWas && result.isEmpty()) { + } else if (position == 1 && searchWas && result.isEmpty() && packs.isEmpty()) { return VIEW_TYPE_HELP; } if (!packs.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java new file mode 100644 index 0000000000..b30784b3fc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java @@ -0,0 +1,138 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.view.MotionEvent; +import android.view.View; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; + +public class FilledTabsView extends View { + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private Text[] tabs; + private RectF[] bounds; + + public FilledTabsView(Context context) { + super(context); + + selectedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); + selectedPaint.setColor(0xFFFFFFFF); + } + + public void setTabs(CharSequence ...texts) { + tabs = new Text[texts.length]; + bounds = new RectF[texts.length]; + + for (int i = 0; i < texts.length; ++i) { + tabs[i] = new Text(texts[i], 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + bounds[i] = new RectF(); + } + + invalidate(); + } + + private float selectedTabIndex; + + public void setSelected(float tabIndex) { + if (Math.abs(tabIndex - selectedTabIndex) > 0.001f) { + invalidate(); + } + selectedTabIndex = tabIndex; + } + + private Utilities.Callback onTabClick; + public FilledTabsView onTabSelected(Utilities.Callback onTabClick) { + this.onTabClick = onTabClick; + return this; + } + + @Override + public void setBackgroundColor(int color) { + backgroundPaint.setColor(color); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (tabs == null) { + return; + } + + final int W = getWidth(); + final int H = getHeight(); + + int w = dp(2) + tabs.length * dp(24) + dp(2); + for (int i = 0; i < tabs.length; ++i) + w += tabs[i].getWidth(); + + float top = (H - dp(30)) / 2f, bottom = (H + dp(30)) / 2f; + float x = (W - w) / 2f; + + AndroidUtilities.rectTmp.set(x, top, x + w, bottom); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(15), dp(15), backgroundPaint); + + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + x += dp(2 + 12); + for (int i = 0; i < tabs.length; ++i) { + tabs[i].draw(canvas, x, H / 2f, 0xFFFFFFFF, 1f); + bounds[i].set(x - dp(2 + 12), top, x + tabs[i].getWidth() + dp(12 + 2), bottom); + x += tabs[i].getWidth() + dp(12 + 12); + } + + x = (W - w) / 2f + dp(2); + top = (H - dp(30 - 4)) / 2f; + bottom = (H + dp(30 - 4)) / 2f; + + final int l = Utilities.clamp((int) Math.floor(selectedTabIndex), tabs.length - 1, 0); + final int r = Utilities.clamp((int) Math.ceil(selectedTabIndex), tabs.length - 1, 0); + float left = AndroidUtilities.lerp(bounds[l].left + dp(2), bounds[r].left + dp(2), (float) (selectedTabIndex - Math.floor(selectedTabIndex))); + float right = AndroidUtilities.lerp(bounds[l].right - dp(2), bounds[r].right - dp(2), (float) (selectedTabIndex - Math.floor(selectedTabIndex))); + + AndroidUtilities.rectTmp.set(left, top, right, bottom); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(15), dp(15), selectedPaint); + canvas.restore(); + } + + private int lastPressedIndex = -1; + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (tabs == null || bounds == null) return false; + int index = -1; + for (int i = 0; i < bounds.length; ++i) { + if (bounds[i].contains(event.getX(), event.getY())) { + index = i; + break; + } + } + + if (index >= 0 && index != lastPressedIndex) { + lastPressedIndex = index; + if (onTabClick != null) { + onTabClick.run(index); + } + } + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + lastPressedIndex = -1; + } + if (event.getAction() == MotionEvent.ACTION_DOWN && index >= 0) { + return true; + } + return super.onTouchEvent(event); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java index 7e96afaf58..32063ad628 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java @@ -30,11 +30,11 @@ public class FlatCheckBox extends View { int colorTextActive; - int HEIGHT = AndroidUtilities.dp(36); + int HEIGHT = AndroidUtilities.dp(37); int INNER_PADDING = AndroidUtilities.dp(22); int TRANSLETE_TEXT = AndroidUtilities.dp(8); - int P = AndroidUtilities.dp(2); + int P = AndroidUtilities.dp(2.5f); RectF rectF = new RectF(); @@ -113,7 +113,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (getMeasuredWidth() != lastW) { rectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - rectF.inset(P + outLinePaint.getStrokeWidth() / 2, P + outLinePaint.getStrokeWidth() / 2 + AndroidUtilities.dp(2)); + rectF.inset(P + outLinePaint.getStrokeWidth() / 2, P + outLinePaint.getStrokeWidth() / 2); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java index 466dec1cc3..564fcd2325 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java @@ -94,7 +94,7 @@ public int set(ChatMessageCell cell, MessageObject messageObject, @NonNull TLRPC if (topicClosed) { maxWidth -= AndroidUtilities.dp(18); } - topicNameLayout = StaticLayoutEx.createStaticLayout(title, 0, title.length(), Theme.chat_topicTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false, TextUtils.TruncateAt.END, maxWidth, 2, false); + topicNameLayout = StaticLayoutEx.createStaticLayout(title, Theme.chat_topicTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false, TextUtils.TruncateAt.END, maxWidth, 2, false); topicHeight = AndroidUtilities.dp(4 + 4.5f) + Math.min(AndroidUtilities.dp(24), topicNameLayout == null ? 0 : topicNameLayout.getHeight()); float textWidth = 0; int lineCount = topicNameLayout == null ? 0 : topicNameLayout.getLineCount(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java index 52bba9adb7..c020b6c666 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java @@ -20,6 +20,7 @@ import android.os.Build; import android.os.Handler; import android.os.Message; +import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java index c253edbec5..55a9a6093b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java @@ -226,7 +226,7 @@ public void setParticipant(ChatObject.VideoParticipant videoParticipant, TLRPC.T if (peerId > 0) { currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId); currentChat = null; - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); name = UserObject.getFirstName(currentUser); avatarImageView.getImageReceiver().setCurrentAccount(currentAccount); @@ -237,7 +237,7 @@ public void setParticipant(ChatObject.VideoParticipant videoParticipant, TLRPC.T } else { currentChat = AccountInstance.getInstance(currentAccount).getMessagesController().getChat(-peerId); currentUser = null; - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentChat != null) { name = currentChat.title; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java index 90c56efe65..17779ef95f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java @@ -284,7 +284,7 @@ protected void onAttachedToWindow() { Theme.getColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(service.getChat().id)]), Theme.getColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(service.getChat().id)]) ); - avatarDrawable.setInfo(service.getChat()); + avatarDrawable.setInfo(currentAccount, service.getChat()); avatarImageView.setImage(ImageLocation.getForLocal(service.getChat().photo.photo_small), "50_50", avatarDrawable, null); String titleStr; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java index 410a4774b2..24d9552127 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java @@ -18,16 +18,12 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.text.Layout; -import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.ReplacementSpan; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java index 41a344bc75..954dba51da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -538,7 +538,7 @@ public int getBottomOffset(int tag) { hideFloatingButton(true, false); } - sharedMediaLayout = new SharedMediaLayout(context, dialogId, sharedMediaPreloader, 0, null, currentChatInfo, currentUserInfo, false, this, new SharedMediaLayout.Delegate() { + sharedMediaLayout = new SharedMediaLayout(context, dialogId, sharedMediaPreloader, 0, null, currentChatInfo, currentUserInfo, initialTab, this, new SharedMediaLayout.Delegate() { @Override public void scrollToSharedMedia() { @@ -784,7 +784,7 @@ protected void onTabScroll(boolean scrolling) { TLRPC.User user = getMessagesController().getUser(encryptedChat.user_id); if (user != null) { nameTextView[0].setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarObject = user; } } @@ -797,7 +797,7 @@ protected void onTabScroll(boolean scrolling) { avatarDrawable.setScaleSize(.8f); } else { nameTextView[0].setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarObject = user; } } @@ -805,7 +805,7 @@ protected void onTabScroll(boolean scrolling) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null) { nameTextView[0].setText(chat.title); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarObject = chat; } } @@ -938,7 +938,7 @@ private void updateMediaCount() { return; } - if (id < 0 || mediaCount[id] < 0) { + if (id < 0 || id < mediaCount.length && mediaCount[id] < 0) { return; } if (id == SharedMediaLayout.TAB_PHOTOVIDEO) { @@ -965,6 +965,10 @@ private void updateMediaCount() { } else if (id == SharedMediaLayout.TAB_GIF) { showSubtitle(i, true, true); subtitleTextView[i].setText(LocaleController.formatPluralString("GIFs", mediaCount[MediaDataController.MEDIA_GIF]), animated); + } else if (id == SharedMediaLayout.TAB_RECOMMENDED_CHANNELS) { + showSubtitle(i, true, true); + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(-dialogId); + subtitleTextView[i].setText(LocaleController.formatPluralString("Channels", rec == null ? 0 : rec.more + rec.chats.size()), animated); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java index ac1f16f655..810bc0b267 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java @@ -4,6 +4,8 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.text.Layout; import android.text.Spannable; @@ -136,7 +138,7 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i } }, 0, emoji.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); emojiDrawable = AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, document); - emojiDrawable.setColorFilter(Theme.getAnimatedEmojiColorFilter(resourcesProvider)); + emojiDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider), PorterDuff.Mode.SRC_IN)); emojiDrawable.addView(this); SpannableString stickerPack = new SpannableString(stickerPackName); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java index 89739fc33d..a48ea031da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java @@ -1005,6 +1005,10 @@ private void updateTrash(boolean enter) { } } + public boolean trashCenter() { + return false; + } + @Override protected void dispatchDraw(Canvas canvas) { final float scale = bounce.getScale(.05f); @@ -1012,9 +1016,13 @@ protected void dispatchDraw(Canvas canvas) { canvas.scale(scale, scale, getWidth() / 2f, getHeight() / 2f); if (getParent() instanceof View) { View p = (View) getParent(); - float px = p.getWidth() / 2f - getX(); - float py = p.getHeight() - dp(76) - getY(); - canvas.scale(trashScale, trashScale, px, py); + if (trashCenter()) { + canvas.scale(trashScale, trashScale, getWidth() / 2f, getHeight() / 2f); + } else { + float px = p.getWidth() / 2f - getX(); + float py = p.getHeight() - dp(76) - getY(); + canvas.scale(trashScale, trashScale, px, py); + } } super.dispatchDraw(canvas); canvas.restore(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java new file mode 100644 index 0000000000..1d9488f3cd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java @@ -0,0 +1,285 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Size; + +public class RoundView extends EntityView { + + private int anchor = -1; + private boolean mirrored = false; + private final AnimatedFloat mirrorT; + private Size baseSize; + + public TextureView textureView; + private FrameLayout.LayoutParams textureViewParams; + + public Bitmap thumbBitmap; + public final Rect src = new Rect(), dst = new Rect(); + + public RoundView(Context context, Point position, float angle, float scale, Size baseSize, String thumbPath) { + super(context, position); + setRotation(angle); + setScale(scale); + + this.baseSize = baseSize; + + thumbBitmap = BitmapFactory.decodeFile(thumbPath); + if (thumbBitmap != null) { + a = (float) thumbBitmap.getWidth() / thumbBitmap.getHeight(); + src.set(0, 0, thumbBitmap.getWidth(), thumbBitmap.getHeight()); + } + + textureView = new TextureView(context); + addView(textureView, textureViewParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + mirrorT = new AnimatedFloat(this, 0, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + + updatePosition(); + setWillNotDraw(false); + } + + private float a = 1.0f; + public void resizeTextureView(int w, int h) { + final float na = (float) w / h; + if (Math.abs(a - na) >= 0.0001f) { + a = na; + requestLayout(); + } + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int w = (int) baseSize.width; + final int h = (int) baseSize.height; + if (textureView != null) { + textureView.measure( + MeasureSpec.makeMeasureSpec(a >= 1.0f ? (int) (a * h) : w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(a >= 1.0f ? h : (int) (w / a), MeasureSpec.EXACTLY) + ); + } + setMeasuredDimension(w, h); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (textureView != null) { + final int t = ((bottom - top) - textureView.getMeasuredHeight()) / 2; + final int l = ((right - left) - textureView.getMeasuredWidth()) / 2; + textureView.layout(l, t, l + textureView.getMeasuredWidth(), t + textureView.getMeasuredHeight()); + } + } + + private final Path clipPath = new Path(); + + private boolean draw = true; + public void setDraw(boolean draw) { + if (this.draw != draw) { + this.draw = draw; + invalidate(); + } + } + + private boolean shown = true; + private AnimatedFloat shownT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + public void setShown(boolean shown, boolean animated) { + if (this.shown != shown) { + this.shown = shown; + if (!animated) { + shownT.set(shown, true); + } + invalidate(); + } + } + + private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (!draw) { + return false; + } + if (child == textureView) { + canvas.save(); + float mirrorT = this.mirrorT.set(mirrored); + canvas.scale(1 - mirrorT * 2, 1f, getMeasuredWidth() / 2f, 0); + canvas.skew(0, 4 * mirrorT * (1f - mirrorT) * .25f); + + final float show = shownT.set(shown); + + final float cx = child.getX() + child.getWidth() / 2f, cy = child.getY() + child.getHeight() / 2f, r = Math.min(child.getWidth() / 2f, child.getHeight() / 2f); + + if (show < 1) { + canvas.saveLayerAlpha(child.getX(), child.getY(), child.getX() + child.getWidth(), child.getY() + child.getHeight(), 0x80, Canvas.ALL_SAVE_FLAG); + clipPath.rewind(); + clipPath.addCircle(cx, cy, r, Path.Direction.CW); + canvas.clipPath(clipPath); + if (thumbBitmap != null) { + dst.set(0, 0, child.getWidth(), child.getHeight()); + canvas.drawBitmap(thumbBitmap, src, dst, null); + } + super.drawChild(canvas, child, drawingTime); + canvas.restore(); + } + + canvas.save(); + clipPath.rewind(); + clipPath.addCircle(cx, cy, r * show, Path.Direction.CW); + canvas.clipPath(clipPath); + if (thumbBitmap != null) { + dst.set(0, 0, child.getWidth(), child.getHeight()); + canvas.drawBitmap(thumbBitmap, src, dst, null); + } + final boolean res; + if (getParent() instanceof EntitiesContainerView && ((EntitiesContainerView) getParent()).drawForThumb) { + res = true; + } else { + res = super.drawChild(canvas, child, drawingTime); + } + + canvas.restore(); + + canvas.restore(); + return res; + } + return super.drawChild(canvas, child, drawingTime); + } + + public int getAnchor() { + return anchor; + } + + public void mirror() { + mirror(false); + } + + public void mirror(boolean animated) { + mirrored = !mirrored; + if (!animated) { + mirrorT.set(mirrored, true); + } + invalidate(); + } + + public boolean isMirrored() { + return mirrored; + } + + protected void updatePosition() { + float halfWidth = baseSize.width / 2.0f; + float halfHeight = baseSize.height / 2.0f; + setX(getPositionX() - halfWidth); + setY(getPositionY() - halfHeight); + updateSelectionView(); + } + + @Override + protected org.telegram.ui.Components.Rect getSelectionBounds() { + ViewGroup parentView = (ViewGroup) getParent(); + if (parentView == null) { + return new org.telegram.ui.Components.Rect(); + } + float scale = parentView.getScaleX(); + float width = getMeasuredWidth() * getScale() + AndroidUtilities.dp(64) / scale; + float height = getMeasuredHeight() * getScale() + AndroidUtilities.dp(64) / scale; + float left = (getPositionX() - width / 2.0f) * scale; + float right = left + width * scale; + return new org.telegram.ui.Components.Rect(left, (getPositionY() - height / 2.0f) * scale, right - left, height * scale); + } + + @Override + protected SelectionView createSelectionView() { + return new RoundViewSelectionView(getContext()); + } + + public Size getBaseSize() { + return baseSize; + } + + public class RoundViewSelectionView extends SelectionView { + + public RoundViewSelectionView(Context context) { + super(context); + } + + @Override + protected int pointInsideHandle(float x, float y) { + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dp(19.5f); + + float inset = radius + thickness; + float middle = inset + (getMeasuredHeight() - inset * 2) / 2.0f; + + if (x > inset - radius && y > middle - radius && x < inset + radius && y < middle + radius) { + return SELECTION_LEFT_HANDLE; + } else if (x > inset + (getMeasuredWidth() - inset * 2) - radius && y > middle - radius && x < inset + (getMeasuredWidth() - inset * 2) + radius && y < middle + radius) { + return SELECTION_RIGHT_HANDLE; + } + + float selectionRadius = getMeasuredWidth() / 2.0f; + + if (Math.pow(x - selectionRadius, 2) + Math.pow(y - selectionRadius, 2) < Math.pow(selectionRadius, 2)) { + return SELECTION_WHOLE_HANDLE; + } + + return 0; + } + + private final RectF arcRect = new RectF(); + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dpf2(5.66f); + + float inset = radius + thickness + AndroidUtilities.dp(15); + float mainRadius = getMeasuredWidth() / 2f - inset; + + arcRect.set(inset, inset, inset + mainRadius * 2, inset + mainRadius * 2); + canvas.drawArc(arcRect, 0, 180, false, paint); + canvas.drawArc(arcRect, 180, 180, false, paint); + + canvas.drawCircle(inset, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.restoreToCount(count); + } + } + + @Override + public boolean trashCenter() { + return true; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java index 5f984365f4..e1e60b6446 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java @@ -112,7 +112,7 @@ public UserCell(Context context) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(30)); - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); BackupImageView avatarImageView = new BackupImageView(context); avatarImageView.setRoundRadius(AndroidUtilities.dp(40)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java index 9295aab8d3..fc539d416a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java @@ -400,14 +400,14 @@ public void update(int mask) { } if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } if (currentUser != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java index 51a304f288..1ee2bb14d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java @@ -324,6 +324,11 @@ public Adapter(int currentAccount, boolean drawHeader, Theme.ResourcesProvider r LocaleController.formatString("ConnectedAccountsLimitSubtitle", R.string.ConnectedAccountsLimitSubtitle, 4), 16, 4 )); + limits.add(new Limit( + LocaleController.getString(R.string.SimilarChannelsLimitTitle), + LocaleController.formatString(R.string.SimilarChannelsLimitSubtitle, messagesController.recommendedChannelsLimitPremium), + messagesController.recommendedChannelsLimitDefault, messagesController.recommendedChannelsLimitPremium + )); rowCount = 0; headerRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java index 236cdfe089..f150719434 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java @@ -18,7 +18,7 @@ public class HelloParticles { - private static String[] hellos = new String[] { + private static final String[] hellos = new String[] { "Hello", "Привіт", "Привет", "Bonjour", "Hola", "Ciao", "Olá", "여보세요", "你好", "Salve", "Sveiki", "Halo", "გამარჯობა", "Hallå", "Salam", "Tere", "Dia dhuit", "こんにちは", "Сайн уу", "Bongu", "Ahoj", "γεια", "Zdravo", "नमस्ते", "Habari", "Hallo", "ជំរាបសួរ", "مرحبًا", "ನಮಸ್ಕಾರ", @@ -120,12 +120,7 @@ private class Particle { float inProgress; public void draw(Canvas canvas, int index, long time) { - if (!paused) { - float speed = AndroidUtilities.dp(4) * (dt / 660f) * speedScale; -// x += vecX * speed; -// y += vecY * speed; - if (inProgress != 1f) { inProgress += dt / duration; if (inProgress > 1f) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 3be324633c..a06c831e85 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -17,6 +17,7 @@ import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.style.RelativeSizeSpan; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; @@ -100,7 +101,7 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in setIconValue(currentValue, false); - limitIcon.setPadding(dp(24), dp(6), dp(24), dp(14)); + limitIcon.setPadding(dp(19), dp(6), dp(19), dp(14)); addView(limitIcon, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.LEFT)); } @@ -269,7 +270,8 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { public void setIconValue(int currentValue, boolean animated) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); - spannableStringBuilder.append("d ").setSpan(new ColoredImageSpan(icon), 0, 1, 0); + spannableStringBuilder.append("d").setSpan(new ColoredImageSpan(icon), 0, 1, 0); + spannableStringBuilder.append(" ").setSpan(new RelativeSizeSpan(0.8f), 1, 2, 0); spannableStringBuilder.append(Integer.toString(currentValue)); limitIcon.setText(spannableStringBuilder, animated); limitIcon.requestLayout(); 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 b1c1aa414e..56edb64113 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 @@ -63,10 +63,10 @@ import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatEditActivity; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BottomSheetWithRecyclerListView; -import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -80,12 +80,15 @@ import org.telegram.ui.Components.Premium.boosts.BoostPagerBottomSheet; import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.Components.Premium.boosts.ReassignBoostBottomSheet; +import org.telegram.ui.Components.Reactions.ChatCustomReactionsEditActivity; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.ChannelBoostUtilities; +import org.telegram.ui.Stories.DarkThemeResourceProvider; import org.telegram.ui.Stories.recorder.StoryRecorder; import java.util.ArrayList; @@ -116,6 +119,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public static final int TYPE_BOOSTS_FOR_POSTING = 18; public static final int TYPE_BOOSTS_FOR_USERS = 19; public static final int TYPE_BOOSTS_FOR_COLOR = 20; + public static final int TYPE_BOOSTS_FOR_REACTIONS = 21; private boolean canSendLink; private int linkRow = -1; @@ -189,6 +193,7 @@ public static String limitTypeToServerString(int type) { private TLRPC.Chat fromChat; FireworksOverlay fireworksOverlay; Runnable statisticClickRunnable; + private int requiredLvl = 0; public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(fragment, false, hasFixedSize(type), false, resourcesProvider); @@ -208,7 +213,7 @@ public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, fireworksOverlay = new FireworksOverlay(getContext()); container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { ((ViewGroup) premiumButtonView.getParent()).removeView(premiumButtonView); recyclerListView.setPadding(0, 0, 0, 0); actionBtn = new TextView(context); @@ -374,12 +379,12 @@ protected void onDraw(Canvas canvas) { AvatarDrawable fromAvatarDrawable = new AvatarDrawable(); TLRPC.Chat fromChat = MessagesController.getInstance(currentAccount).getChat(-canApplyBoost.replaceDialogId); - fromAvatarDrawable.setInfo(fromChat); + fromAvatarDrawable.setInfo(currentAccount, fromChat); fromAvatar.setForUserOrChat(fromChat, fromAvatarDrawable); AvatarDrawable toAvatarDrawable = new AvatarDrawable(); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - toAvatarDrawable.setInfo(chat); + toAvatarDrawable.setInfo(currentAccount, chat); toAvatar.setForUserOrChat(chat, toAvatarDrawable); AlertDialog.Builder builder = new AlertDialog.Builder(context); @@ -396,7 +401,7 @@ protected void onDraw(Canvas canvas) { } return; } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { AndroidUtilities.addToClipboard(getBoostLink()); dismiss(); return; @@ -563,6 +568,10 @@ private void sendInviteMessages() { dismiss(); } + public void setRequiredLvl(int requiredLvl) { + this.requiredLvl = requiredLvl; + } + public void updatePremiumButtonText() { if (type == TYPE_BOOSTS_FOR_USERS) { if (BoostRepository.isMultiBoostsAvailable()) { @@ -575,7 +584,7 @@ public void updatePremiumButtonText() { } else { premiumButtonView.buttonTextView.setText(LocaleController.getString("BoostChannel", R.string.BoostChannel)); } - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d "); spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_copy_filled), 0, 1, 0); spannableStringBuilder.append(LocaleController.getString("CopyLink", R.string.CopyLink)); @@ -691,7 +700,7 @@ private static boolean hasFixedSize(int type) { if (type == TYPE_PIN_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || type == TYPE_LARGE_FILE || type == TYPE_ACCOUNTS || type == TYPE_FOLDER_INVITES || type == TYPE_SHARED_FOLDERS || type == TYPE_STORIES_COUNT || type == TYPE_STORIES_WEEK || - type == TYPE_STORIES_MONTH || type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + type == TYPE_STORIES_MONTH || type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { return true; } return false; @@ -724,6 +733,28 @@ public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.boostByChannelCreated) { TLRPC.Chat chat = (TLRPC.Chat) args[0]; boolean isGiveaway = (boolean) args[1]; + BaseFragment lastFragment = getBaseFragment().getParentLayout().getLastFragment(); + if (lastFragment instanceof ChatCustomReactionsEditActivity) { + List fragmentStack = getBaseFragment().getParentLayout().getFragmentStack(); + BaseFragment chatEditFragment = fragmentStack.size() >= 2 ? fragmentStack.get(fragmentStack.size() - 2) : null; + BaseFragment profileFragment = fragmentStack.size() >= 3 ? fragmentStack.get(fragmentStack.size() - 3) : null; + BaseFragment chatFragment = fragmentStack.size() >= 4 ? fragmentStack.get(fragmentStack.size() - 4) : null; + if (chatEditFragment instanceof ChatEditActivity) { + getBaseFragment().getParentLayout().removeFragmentFromStack(chatEditFragment); + } + dismiss(); + if (isGiveaway) { + if (profileFragment instanceof ProfileActivity) { + getBaseFragment().getParentLayout().removeFragmentFromStack(profileFragment); + } + lastFragment.finishFragment(); + BoostDialogs.showBulletin(chatFragment, chat, true); + } else { + lastFragment.finishFragment(); + BoostDialogs.showBulletin(profileFragment, chat, false); + } + return; + } if (isGiveaway) { if (StoryRecorder.isVisible()) { ChatActivity chatFragment = ChatActivity.of(-chat.id); @@ -826,7 +857,11 @@ public void onClick(@NonNull View view) { arrow.setSpan(span, 0, arrow.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(TextUtils.concat(text, " ", AndroidUtilities.replaceCharSequence(">", link, arrow))); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + if (resourcesProvider instanceof DarkThemeResourceProvider) { + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + } else { + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + } textView.setGravity(Gravity.CENTER_HORIZONTAL); textView.setOnClickListener(v -> BoostPagerBottomSheet.show(getBaseFragment(), dialogId, resourcesProvider)); orDividerView.setOnClickListener(v -> textView.performClick()); @@ -1066,6 +1101,8 @@ public HeaderView(Context context) { "ChannelNeedBoostsForColorDescription", R.string.ChannelNeedBoostsForColorDescription, MessagesController.getInstance(currentAccount).channelColorLevelMin ); + } else if (type == TYPE_BOOSTS_FOR_REACTIONS) { + descriptionStr = LocaleController.formatPluralString("ReactionReachLvlForReaction", requiredLvl, requiredLvl); } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { premiumLocked = true; if (!canSendLink) { @@ -1147,7 +1184,7 @@ public HeaderView(Context context) { percent = defaultLimit / (float) premiumLimit; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { currentValue = 0; } @@ -1160,7 +1197,7 @@ public void invalidate() { super.invalidate(); } }; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { if (boostsStatus != null) { limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.boostedNow); } @@ -1187,7 +1224,7 @@ public void invalidate() { limitPreviewView.setDelayedAnimation(); } - addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0, 0)); + addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, -4, 0, -4, 0)); title = new TextView(context); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -1199,6 +1236,8 @@ public void invalidate() { } else { title.setText(LocaleController.getString("BoostingIncreaseLevel", R.string.BoostingIncreaseLevel)); } + } else if (type == TYPE_BOOSTS_FOR_REACTIONS) { + title.setText(LocaleController.getString(R.string.ReactionCustomReactions)); } else if (type == TYPE_BOOSTS_FOR_COLOR) { title.setText(LocaleController.getString(R.string.BoostingEnableColor)); } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { @@ -1224,8 +1263,8 @@ public void invalidate() { titleLinearLayout.setOrientation(HORIZONTAL); titleLinearLayout.setWeightSum(1f); titleLinearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 1, 0)); - titleLinearLayout.addView(boostCounterView); - addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, premiumLocked ? 8 : 22, 12, 10)); + titleLinearLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 2, 0, 0)); + addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, premiumLocked ? 8 : 22, 12, 9)); } else { addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, premiumLocked ? 8 : 22, 0, 0)); @@ -1239,7 +1278,7 @@ public void invalidate() { backupImageView.setRoundRadius(AndroidUtilities.dp(14)); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); backupImageView.setForUserOrChat(chat, avatarDrawable); frameLayout.addView(backupImageView, LayoutHelper.createFrame(28, 28)); TextView textView = new TextView(getContext()); @@ -1254,9 +1293,14 @@ public void invalidate() { frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 36, 0, 12, 0)); rootLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, Gravity.BOTTOM, 18, 0, 18, 0)); + + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(100); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + rootLayout.setLayoutTransition(layoutTransition); rootLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, -30, 2, 18, 0)); - addView(rootLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 38, Gravity.CENTER, 0, 0, 0, 12)); + addView(rootLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 38, Gravity.CENTER, 0, -4, 0, 12)); ScaleStateListAnimator.apply(rootLayout); rootLayout.setOnClickListener(v -> { getBaseFragment().presentFragment(ChatActivity.of(dialogId)); @@ -1270,13 +1314,17 @@ public void invalidate() { description.setText(AndroidUtilities.replaceTags(descriptionStr)); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); description.setGravity(Gravity.CENTER_HORIZONTAL); + description.setLineSpacing(description.getLineSpacingExtra(), description.getLineSpacingMultiplier() * 1.1f); if (type == TYPE_BOOSTS_FOR_POSTING) { description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); } else { description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); } - addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); - + if (type == TYPE_BOOSTS_FOR_USERS) { + addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, -2, 24, 17)); + } else { + addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); + } updatePremiumButtonText(); } @@ -1293,8 +1341,8 @@ public void recreateTitleAndDescription() { titleLinearLayout.setOrientation(HORIZONTAL); titleLinearLayout.setWeightSum(1f); titleLinearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 1, 0)); - titleLinearLayout.addView(boostCounterView); - addView(titleLinearLayout, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, 22, 12, 10)); + titleLinearLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 2, 0, 0)); + addView(titleLinearLayout, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, 22, 12, 9)); } else { int titleIndex = indexOfChild(title); removeView(title); @@ -1303,15 +1351,16 @@ public void recreateTitleAndDescription() { title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); title.setGravity(Gravity.CENTER); - addView(title, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 22, 0, 10)); + addView(title, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 22, 0, 0)); } removeView(description); description = new TextView(getContext()); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + description.setLineSpacing(description.getLineSpacingExtra(), description.getLineSpacingMultiplier() * 1.1f); description.setGravity(Gravity.CENTER_HORIZONTAL); description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - addView(description, descriptionIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); + addView(description, descriptionIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, -2, 24, 17)); } } @@ -1480,7 +1529,7 @@ private static LimitParams getLimitParams(int type, int currentAccount) { limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitDefault; limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitPremium; limitParams.icon = R.drawable.filled_limit_boost; @@ -1555,7 +1604,7 @@ private void updateRows() { } } } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { linkRow = rowCount++; if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable) { bottomRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index cc40b1f0c9..cb738343ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -38,6 +38,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.BottomPagesView; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -45,6 +46,7 @@ import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.ThemePreviewActivity; import java.util.ArrayList; @@ -57,6 +59,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati float containerViewsProgress; float progressToFullscreenView; float progressToGradient; + boolean fullscreenNext; boolean containerViewsForward; ViewPager viewPager; FrameLayout content; @@ -290,12 +293,16 @@ private void checkPage() { if (selectedFullscreen && nextFullscreen) { progressToGradient = 1f; progressToFullscreenView = progress == 0 ? 1f : progress; + fullscreenNext = true; } else if (selectedFullscreen) { progressToGradient = progressToFullscreenView = 1f - progress; + fullscreenNext = true; } else if (nextFullscreen) { progressToGradient = progressToFullscreenView = progress; + fullscreenNext = false; } else { progressToGradient = progressToFullscreenView = 0; + fullscreenNext = true; } int localGradientAlpha = (int) (255 * (1f - progressToFullscreenView)); @@ -340,7 +347,15 @@ public void onPageScrollStateChanged(int i) { } } if ((onlySelectedType || forceAbout) && fragment != null) { - fragment.presentFragment(new PremiumPreviewFragment(PremiumPreviewFragment.featureTypeToServerString(featureData.type))); + BaseFragment premiumFragment = new PremiumPreviewFragment(PremiumPreviewFragment.featureTypeToServerString(featureData.type)); + if (fragment instanceof ThemePreviewActivity) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + fragment.showAsSheet(premiumFragment, params); + } else { + fragment.presentFragment(premiumFragment); + } } else { PremiumPreviewFragment.buyPremium(fragment, selectedTier, PremiumPreviewFragment.featureTypeToServerString(featureData.type)); } @@ -479,6 +494,8 @@ private void setButtonText() { } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS) { premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.UnlockPremiumIcons)); premiumButtonView.setIcon(R.raw.unlock_icon); + } else { + premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.AboutTelegramPremium)); } } else { premiumButtonView.buttonTextView.setText(PremiumPreviewFragment.getPremiumButtonText(currentAccount, selectedTier)); @@ -678,6 +695,15 @@ void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { title.setText(LocaleController.getString(R.string.PremiumPreviewTranslations)); description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewTranslationsDescription))); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER) { + title.setText(LocaleController.getString(R.string.PremiumPreviewWallpaper)); + description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewWallpaperDescription))); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_NAME_COLOR) { + title.setText(LocaleController.getString(R.string.PremiumPreviewProfileColor)); + description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewProfileColorDescription))); + } else { + title.setText(featureData.title); + description.setText(AndroidUtilities.replaceTags(featureData.description)); } topViewOnFullHeight = false; } else { @@ -809,7 +835,7 @@ void checkTopOffset() { } else { closeLayout.setVisibility(View.VISIBLE); } - content.setTranslationX(content.getMeasuredWidth() * progressToGradient); + content.setTranslationX(fullscreenNext ? content.getMeasuredWidth() * progressToGradient : -content.getMeasuredWidth() * progressToGradient); if (localOffset != topCurrentOffset) { topCurrentOffset = localOffset; for (int i = 0; i < viewPager.getChildCount(); i++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java index 80e4d070d6..95dfa49ff4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java @@ -219,6 +219,18 @@ private void generateBitmaps() { stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; + } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER) { + int res; + if (i == 0) { + res = R.raw.premium_object_user; + } else if (i == 1) { + res = R.raw.cache_photos; + } else { + res = R.raw.cache_profile_photos; + } + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); + svg = true; + continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS) { int res; if (i == 0) { @@ -525,6 +537,7 @@ public void genPosition(long time) { type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS || type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS || type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI || + type == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER || type == PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS ) { randomRotate = (int) (45 * ((Utilities.fastRandom.nextInt() % 100) / 100f)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java index d728c621c5..c055a6b23b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java @@ -3,7 +3,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -38,7 +37,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.Locale; public class StoriesPageView extends BaseListPageView { 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 04019e1a1f..0e348a4ac7 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 @@ -35,7 +35,7 @@ public BoostCounterView(Context context, Theme.ResourcesProvider resourcesProvid countText = new AnimatedTextView.AnimatedTextDrawable(false, false, true); countText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); countText.setCallback(this); - countText.setTextSize(dp(11)); + countText.setTextSize(dp(11.5f)); countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); countText.setTextColor(Color.WHITE); countText.setText(""); @@ -109,6 +109,7 @@ protected void onDraw(Canvas canvas) { } canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(10), dp(10), bgPaint); + AndroidUtilities.rectTmp2.set(0, 0, AndroidUtilities.dp(20), AndroidUtilities.dp(19)); countText.setBounds(AndroidUtilities.rectTmp2); countText.draw(canvas); if (countScale != 1) { 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 64ea478d74..8ba91f29ea 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 @@ -127,6 +127,9 @@ public static void showBulletin(FrameLayout container, Theme.ResourcesProvider r } public static void showBulletin(final BaseFragment baseFragment, final TLRPC.Chat chat, final boolean isGiveaway) { + if (baseFragment == null) { + return; + } BulletinFactory bulletinFactory = BulletinFactory.of(baseFragment); showBulletin(bulletinFactory, baseFragment.getResourceProvider(), chat, isGiveaway); } 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 119a2625eb..d9540ae320 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 @@ -107,7 +107,7 @@ public GiftInfoBottomSheet(BaseFragment fragment, boolean needFocus, boolean has this.giftCode = giftCode; this.slug = slug; setApplyTopPadding(false); - setApplyBottomPadding(true); + setApplyBottomPadding(false); fixNavigationBar(); updateTitle(); adapter.init(fragment, giftCode, slug); 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 386348ff9d..cf28bbc47b 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 @@ -3,6 +3,7 @@ import static org.telegram.tgnet.TLRPC.TL_payments_checkedGiftCode.NO_USER_ID; import android.content.Context; +import android.graphics.Color; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.view.Gravity; @@ -110,6 +111,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int break; case HOLDER_TYPE_BUTTON: view = new ActionBtnCell(context, resourcesProvider); + view.setPadding(0,0,0, AndroidUtilities.dp(14)); break; case HOLDER_TYPE_EMPTY: view = new View(context); @@ -167,7 +169,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi cell.setText(LocaleController.getString("BoostingLinkNotActivated", R.string.BoostingLinkNotActivated)); } else { //activated link - cell.setText(""); + cell.setFixedSize(14); + cell.setText(null); } return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java index 6ec4cf4db2..ed15c92af9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java @@ -11,6 +11,7 @@ import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java index 55f8401004..59107741c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java @@ -1,5 +1,6 @@ package org.telegram.ui.Components.Premium.boosts.cells; +import static org.telegram.messenger.AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD; import static org.telegram.messenger.AndroidUtilities.dp; import android.annotation.SuppressLint; @@ -186,12 +187,12 @@ public void setGiftLinkToUserText(long toUserId, Utilities.Callback on TLRPC.User toUser = MessagesController.getInstance(UserConfig.selectedAccount).getUser(toUserId); SpannableStringBuilder userName = new SpannableStringBuilder(); userName.append("**"); - userName.append(Emoji.replaceEmoji(UserObject.getUserName(toUser), subtitleView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(12), false)); + userName.append(Emoji.replaceEmoji(UserObject.getUserName(toUser), subtitleView.getPaint().getFontMetricsInt(), false)); userName.append("**"); descriptionStart = AndroidUtilities.replaceSingleTag( descriptionStart.toString().replace("**%1$s**", userName), - Theme.key_chat_messageLinkIn, 0, + Theme.key_chat_messageLinkIn, REPLACING_TAG_TYPE_LINKBOLD, () -> onObjectClicked.run(toUser), resourcesProvider ); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java index 5ee5d736b9..4ad6ce2089 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java @@ -56,11 +56,11 @@ public LinkCell(@NonNull Context context, BaseFragment fragment, Theme.Resources linkContainer.setOnClickListener(v -> AndroidUtilities.addToClipboard(link)); imageView = new ImageView(getContext()); - imageView.setImageResource(R.drawable.msg_copy); + imageView.setImageResource(R.drawable.menu_copy_s); imageView.setColorFilter(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); imageView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); imageView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(20), 0, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_listSelector, resourcesProvider), (int) (255 * 0.3f)))); - addView(imageView, LayoutHelper.createFrame(40, 40, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 15, 0, 15, 0)); + addView(imageView, LayoutHelper.createFrame(40, 40, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 15, 0, 17, 0)); imageView.setOnClickListener(v -> AndroidUtilities.addToClipboard(link)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java index 51fa8e5804..5b208ff3a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java @@ -6,6 +6,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -24,6 +25,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; @@ -161,7 +163,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.clipPath(roundPath); } super.dispatchDraw(canvas); - linePaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + linePaint.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_divider, resourcesProvider), Color.WHITE, 0.1f)); linePaint.setStrokeWidth(AndroidUtilities.dp(1)); float oneRow = getHeight() / (tableRow4.getVisibility() == VISIBLE ? 5f : 4f); for (int i = 1; i <= 4; i++) { 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 7f6e833f8a..652b603d31 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 @@ -8,7 +8,6 @@ import static org.telegram.messenger.LocaleController.getString; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -30,6 +29,7 @@ import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageLocation; @@ -371,7 +371,7 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int private int getChatColor(TLRPC.Chat chat, Theme.ResourcesProvider resourcesProvider) { final int color; - int colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + int colorId = ChatObject.getColorId(chat); if (colorId < 7) { color = Theme.getColor(Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AddReactionsSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AddReactionsSpan.java new file mode 100644 index 0000000000..12fb4c64b7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AddReactionsSpan.java @@ -0,0 +1,89 @@ +package org.telegram.ui.Components.Reactions; + +import static android.graphics.Canvas.ALL_SAVE_FLAG; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ReplacementSpan; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; + +public class AddReactionsSpan extends ReplacementSpan { + + private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final RectF rectF = new RectF(); + private StaticLayout layout; + private float width, height; + private int alpha; + + public AddReactionsSpan(float textSize, Theme.ResourcesProvider resourcesProvider) { + textPaint.setTextSize(dp(textSize)); + textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText5, resourcesProvider)); + } + + public void makeLayout() { + if (layout == null) { + layout = new StaticLayout(LocaleController.getString("ReactionAddReactionsHint", R.string.ReactionAddReactionsHint), textPaint, AndroidUtilities.displaySize.x, LocaleController.isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL, 1, 0, false); + width = layout.getLineWidth(0); + height = layout.getHeight(); + } + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + makeLayout(); + return (int) (dp(8) + width); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float _x, int top, int _y, int bottom, @NonNull Paint paint) { + makeLayout(); + rectF.set(canvas.getClipBounds()); + canvas.saveLayerAlpha(rectF, alpha, ALL_SAVE_FLAG); + float transY = (top + (bottom - top) / 2f - height / 2f); + canvas.translate(_x + dp(4), transY); + layout.draw(canvas); + canvas.restore(); + } + + public void show(View parent) { + ValueAnimator valueAnimator = ValueAnimator.ofInt(alpha, 255); + valueAnimator.addUpdateListener(animator -> { + alpha = (int) animator.getAnimatedValue(); + parent.invalidate(); + }); + valueAnimator.setDuration(200); + valueAnimator.start(); + } + + public void hide(View parent, Runnable after) { + ValueAnimator valueAnimator = ValueAnimator.ofInt(alpha, 0); + valueAnimator.addUpdateListener(animator -> { + alpha = (int) animator.getAnimatedValue(); + parent.invalidate(); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + after.run(); + } + }); + valueAnimator.setDuration(200); + valueAnimator.start(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java new file mode 100644 index 0000000000..cddb46a996 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java @@ -0,0 +1,128 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Stories.RoundRectOutlineProvider; + +@SuppressLint("ViewConstructor") +public class BackSpaceButtonView extends FrameLayout { + + private final Theme.ResourcesProvider resourcesProvider; + private final ImageView backspaceButton; + private boolean backspacePressed; + private boolean backspaceOnce; + private Utilities.Callback onBackspace; + + public BackSpaceButtonView(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + backspaceButton = new ImageView(context) { + private long lastClick = 0; + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (System.currentTimeMillis() < lastClick + 350) { + return false; + } + lastClick = System.currentTimeMillis(); + backspacePressed = true; + backspaceOnce = false; + postBackspaceRunnable(350); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) { + backspacePressed = false; + if (!backspaceOnce) { + if (onBackspace != null) { + onBackspace.run(false); + backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + } + } + super.onTouchEvent(event); + return true; + } + }; + backspaceButton.setHapticFeedbackEnabled(true); + backspaceButton.setImageResource(R.drawable.smiles_tab_clear); + backspaceButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelBackspace), PorterDuff.Mode.MULTIPLY)); + backspaceButton.setScaleType(ImageView.ScaleType.CENTER); + backspaceButton.setContentDescription(LocaleController.getString("AccDescrBackspace", R.string.AccDescrBackspace)); + backspaceButton.setFocusable(true); + backspaceButton.setOnClickListener(v -> { + + }); + addView(backspaceButton, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); + + int rippleColor = Theme.getColor(Theme.key_listSelector); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(36), getThemedColor(Theme.key_windowBackgroundWhite), rippleColor); + if (Build.VERSION.SDK_INT >= 21) { + backspaceButton.setBackground(drawable); + backspaceButton.setOutlineProvider(new RoundRectOutlineProvider(18)); + backspaceButton.setElevation(AndroidUtilities.dp(1)); + backspaceButton.setClipToOutline(true); + } else { + Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); + combinedDrawable.setIconSize(AndroidUtilities.dp(36), AndroidUtilities.dp(36)); + drawable = combinedDrawable; + backspaceButton.setBackground(drawable); + } + + setClickable(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY) + ); + } + + public void setOnBackspace(Utilities.Callback onBackspace) { + this.onBackspace = onBackspace; + } + + private void postBackspaceRunnable(final int time) { + AndroidUtilities.runOnUIThread(() -> { + if (!backspacePressed) { + return; + } + if (onBackspace != null) { + onBackspace.run(time < 300); + backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + backspaceOnce = true; + postBackspaceRunnable(Math.max(50, time - 100)); + }, time); + } + + private int getThemedColor(int key) { + if (resourcesProvider != null) { + return resourcesProvider.getColor(key); + } + return Theme.getColor(key); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java new file mode 100644 index 0000000000..8d27acfc48 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java @@ -0,0 +1,735 @@ +package org.telegram.ui.Components.Reactions; + +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.getString; +import static org.telegram.ui.Components.Reactions.ReactionsUtils.addReactionToEditText; +import static org.telegram.ui.Components.Reactions.ReactionsUtils.createAnimatedEmojiSpan; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.Editable; +import android.text.Layout; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.SelectAnimatedEmojiDialog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; + +public class ChatCustomReactionsEditActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + public final static int SELECT_TYPE_NONE = 2, + SELECT_TYPE_SOME = 1, + SELECT_TYPE_ALL = 0; + + private SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; + private FrameLayout bottomDialogLayout; + private BackSpaceButtonView backSpaceButtonView; + private TextCheckCell enableReactionsCell; + private LinearLayout switchLayout; + private LinearLayout contentLayout; + private CustomReactionEditText editText; + private UpdateReactionsButton actionButton; + private ScrollView scrollView; + + private final HashMap selectedEmojisMap = new LinkedHashMap<>(); + private final List selectedEmojisIds = new ArrayList<>(); + private final HashMap initialSelectedEmojis = new LinkedHashMap<>(); + private final List allAvailableReactions = new ArrayList<>(); + + private final int maxReactionsCount = getMessagesController().boostsChannelLevelMax; + private boolean emojiKeyboardVisible = false; + private final TLRPC.ChatFull info; + private final long chatId; + private TLRPC.Chat currentChat; + private TL_stories.TL_premium_boostsStatus boostsStatus; + private int selectedCustomReactions; + private int selectedType = -1; + private boolean isPaused; + private final Runnable checkAfterFastDeleteRunnable = () -> checkMaxCustomReactions(false); + + public ChatCustomReactionsEditActivity(long chatId, TLRPC.ChatFull info) { + super(); + this.chatId = chatId; + this.info = info; + } + + @Override + public boolean onFragmentCreate() { + currentChat = getMessagesController().getChat(chatId); + if (currentChat == null) { + currentChat = MessagesStorage.getInstance(currentAccount).getChatSync(chatId); + if (currentChat != null) { + getMessagesController().putChat(currentChat, true); + } else { + return false; + } + } + + if (info == null) { + return false; + } + + getMessagesController().getBoostsController().getBoostsStats(-chatId, boostsStatus -> { + this.boostsStatus = boostsStatus; + boolean hasChanges = !selectedEmojisMap.keySet().equals(initialSelectedEmojis.keySet()); + if (hasChanges) { + checkMaxCustomReactions(false); + } + }); + getNotificationCenter().addObserver(this, NotificationCenter.reactionsDidLoad); + allAvailableReactions.addAll(getMediaDataController().getEnabledReactionsList()); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + return super.onFragmentCreate(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public View createView(Context context) { + actionBar.setTitle(LocaleController.getString("Reactions", R.string.Reactions)); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (!checkChangesBeforeExit()) { + finishFragment(); + } + } + } + }); + + FrameLayout rootLayout = new FrameLayout(context); + scrollView = new ScrollView(context); + scrollView.setFillViewport(true); + + contentLayout = new LinearLayout(context); + contentLayout.setOrientation(LinearLayout.VERTICAL); + + scrollView.addView(contentLayout); + + enableReactionsCell = new TextCheckCell(context); + enableReactionsCell.setHeight(56); + enableReactionsCell.setBackgroundColor(Theme.getColor(enableReactionsCell.isChecked() ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); + enableReactionsCell.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + enableReactionsCell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); + enableReactionsCell.setOnClickListener(v -> { + setCheckedEnableReactionCell(enableReactionsCell.isChecked() ? SELECT_TYPE_NONE : SELECT_TYPE_SOME, true); + }); + contentLayout.addView(enableReactionsCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); + infoCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + infoCell.setTopPadding(12); + infoCell.setBottomPadding(16); + infoCell.setText(LocaleController.getString("ReactionAddEmojiFromAnyPack", R.string.ReactionAddEmojiFromAnyPack)); + contentLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + HeaderCell headerCell = new HeaderCell(context); + headerCell.setText(LocaleController.getString("AvailableReactions", R.string.AvailableReactions)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + headerCell.setTextSize(15); + headerCell.setTopMargin(14); + + switchLayout = new LinearLayout(context); + switchLayout.setOrientation(LinearLayout.VERTICAL); + + contentLayout.addView(switchLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + switchLayout.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + editText = new CustomReactionEditText(context, getResourceProvider(), maxReactionsCount) { + @Override + protected void onLineCountChanged(int oldLineCount, int newLineCount) { + if (newLineCount > oldLineCount) { + scrollView.smoothScrollBy(0, AndroidUtilities.dp(30)); + } + } + + @Override + public boolean onTextContextMenuItem(int id) { + if (id == R.id.menu_delete || id == android.R.id.cut) { + return deleteSelectedEmojis(); + } else if (id == android.R.id.paste || id == android.R.id.copy) { + return false; + } + return super.onTextContextMenuItem(id); + } + }; + editText.setOnFocused(this::showKeyboard); + + switchLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(200); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + switchLayout.setLayoutTransition(layoutTransition); + + TextInfoPrivacyCell infoCell2 = new TextInfoPrivacyCell(context); + infoCell2.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + infoCell2.setTopPadding(12); + infoCell2.setBottomPadding(70); + infoCell2.setText(AndroidUtilities.replaceSingleTag( + LocaleController.getString("ReactionCreateOwnPack", R.string.ReactionCreateOwnPack), + Theme.key_chat_messageLinkIn, 0, + () -> presentFragment(ChatActivity.of(429000)), + getResourceProvider() + )); + switchLayout.addView(infoCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + actionButton = new UpdateReactionsButton(context, getResourceProvider()); + actionButton.setDefaultState(); + actionButton.setOnClickListener(v -> { + if (actionButton.isLoading()) { + return; + } + + if (boostsStatus != null && boostsStatus.level < selectedCustomReactions) { + ReactionsUtils.showLimitReachedDialogForReactions(-chatId, selectedCustomReactions, boostsStatus); + return; + } + + actionButton.setLoading(true); + getMessagesController().setCustomChatReactions(chatId, selectedType, grabReactions(false), error -> { + if (isFinishing()) { + return; + } + actionButton.setLoading(false); + if (error.text.equals("CHAT_NOT_MODIFIED")) { + finishFragment(); + } else { + Runnable runnable = () -> { + if (boostsStatus != null && error.text.equals("BOOSTS_REQUIRED")) { + ReactionsUtils.showLimitReachedDialogForReactions(-chatId, selectedCustomReactions, boostsStatus); + } else { + String errText = error.text; + if (error.text.equals("REACTIONS_TOO_MANY")) { + errText = formatPluralString("ReactionMaxCountError", maxReactionsCount); + } + BulletinFactory.of(ChatCustomReactionsEditActivity.this).createErrorBulletin(errText).show(); + } + }; + AndroidUtilities.runOnUIThread(runnable, boostsStatus == null ? 200 : 0); + } + }, this::finishFragment); + }); + rootLayout.addView(scrollView); + rootLayout.addView(actionButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 13, 0, 13, 13)); + rootLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + bottomDialogLayout = new FrameLayout(context) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (emojiKeyboardVisible && changed) { + //support screen rotation + actionButton.setTranslationY(-bottomDialogLayout.getMeasuredHeight()); + updateScrollViewMarginBottom(bottomDialogLayout.getMeasuredHeight()); + scrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + } + }; + + bottomDialogLayout.setVisibility(View.INVISIBLE); + rootLayout.addView(bottomDialogLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + int i = 0; + if (info.available_reactions instanceof TLRPC.TL_chatReactionsAll) { + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_ALL, false); + initialSelectedEmojis.putAll(selectedEmojisMap); + } else if (info.available_reactions instanceof TLRPC.TL_chatReactionsSome) { + TLRPC.TL_chatReactionsSome reactionsSome = (TLRPC.TL_chatReactionsSome) info.available_reactions; + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.Reaction reaction : reactionsSome.reactions) { + if (reaction instanceof TLRPC.TL_reactionEmoji) { + TLRPC.TL_reactionEmoji reactionEmoji = ((TLRPC.TL_reactionEmoji) reaction); + TLRPC.TL_availableReaction availableReaction = getMediaDataController().getReactionsMap().get(reactionEmoji.emoticon); + if (availableReaction == null) { + continue; + } + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + } else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { + addReactionToEditText((TLRPC.TL_reactionCustomEmoji) reaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + } + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_SOME, false); + initialSelectedEmojis.putAll(selectedEmojisMap); + } else if (info.available_reactions instanceof TLRPC.TL_chatReactionsNone) { + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_NONE, false); + } + enableReactionsCell.setTextAndCheck(LocaleController.getString("EnableReactions", R.string.EnableReactions), selectedType != SELECT_TYPE_NONE, false); + editText.addReactionsSpan(); + + fragmentView = rootLayout; + return rootLayout; + } + + private void initSelectAnimatedEmojiDialog() { + if (selectAnimatedEmojiDialog != null) { + return; + } + int accentColor = Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, getResourceProvider()); + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(this, getContext(), false, null, SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS, false, getResourceProvider(), 16, accentColor) { + + private boolean firstLayout = true; + + { + setDrawBackground(false); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (firstLayout) { + firstLayout = false; + selectAnimatedEmojiDialog.onShow(null); + } + } + + protected void onEmojiSelected(View view, Long documentId, TLRPC.Document document, Integer until) { + if (selectedEmojisMap.containsKey(documentId)) { + selectedEmojisIds.remove(documentId); + AnimatedEmojiSpan removedSpan = selectedEmojisMap.remove(documentId); + removedSpan.setRemoved(() -> { + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + AnimatedEmojiSpan[] spans = spanned.getSpans(0, spanned.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + if (span == removedSpan) { + int selectionEnd = editText.getEditTextSelectionEnd(); + int spanEnd = spanned.getSpanEnd(span); + int spanStart = spanned.getSpanStart(span); + editText.getText().delete(spanStart, spanEnd); + int spanDiff = spanEnd - spanStart; + editText.setSelection(spanEnd <= selectionEnd ? selectionEnd - spanDiff : selectionEnd); + break; + } + } + }); + animateChangesInNextRows(removedSpan); + selectAnimatedEmojiDialog.setMultiSelected(documentId, true); + checkMaxCustomReactions(false); + } else { + if (selectedEmojisMap.size() >= maxReactionsCount) { + BulletinFactory.of(ChatCustomReactionsEditActivity.this).createErrorBulletin(formatPluralString("ReactionMaxCountError", maxReactionsCount)).show(); + return; + } + try { + int selectionEnd = editText.getEditTextSelectionEnd(); + SpannableString spannable = new SpannableString("b"); + AnimatedEmojiSpan span = createAnimatedEmojiSpan(document, documentId, editText.getFontMetricsInt()); + span.cacheType = AnimatedEmojiDrawable.getCacheTypeForEnterView(); + span.setAdded(); + selectedEmojisIds.add(selectionEnd, documentId); + selectedEmojisMap.put(documentId, span); + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editText.getText().insert(selectionEnd, spannable); + editText.setSelection(selectionEnd + spannable.length()); + selectAnimatedEmojiDialog.setMultiSelected(documentId, true); + checkMaxCustomReactions(true); + animateChangesInNextRows(span); + } catch (Exception e) { + FileLog.e(e); + } + } + } + }; + + selectAnimatedEmojiDialog.setAnimationsEnabled(false); + selectAnimatedEmojiDialog.setClipChildren(false); + selectAnimatedEmojiDialog.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + bottomDialogLayout.addView(selectAnimatedEmojiDialog, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + backSpaceButtonView = new BackSpaceButtonView(getContext(), getResourceProvider()); + backSpaceButtonView.setOnBackspace(isFast -> { + if (deleteSelectedEmojis()) { + return; + } + int selectionEnd = editText.getEditTextSelectionEnd(); + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + AnimatedEmojiSpan[] spans = spanned.getSpans(0, spanned.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + int removedSpanEnd = spanned.getSpanEnd(span); + if (removedSpanEnd == selectionEnd) { + selectedEmojisMap.remove(span.documentId); + selectedEmojisIds.remove(span.documentId); + selectAnimatedEmojiDialog.unselect(span.documentId); + if (isFast) { + editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); + AndroidUtilities.cancelRunOnUIThread(checkAfterFastDeleteRunnable); + AndroidUtilities.runOnUIThread(checkAfterFastDeleteRunnable, 350); + } else { + span.setRemoved(() -> { + Editable editable = editText.getText(); + int spanStart = editable.getSpanStart(span); + int spanEnd = editable.getSpanEnd(span); + int spanDiff = spanEnd - spanStart; + if (spanStart == -1 || spanEnd == -1) { + return; + } + editText.getText().delete(spanStart, spanEnd); + editText.setSelection(Math.min(selectionEnd - spanDiff, editText.getText().length())); + }); + animateChangesInNextRows(span); + checkMaxCustomReactions(false); + } + break; + } + } + }); + bottomDialogLayout.addView(backSpaceButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 8, 8)); + for (Long selectedEmojisId : selectedEmojisIds) { + selectAnimatedEmojiDialog.setMultiSelected(selectedEmojisId, false); + } + } + + private void animateChangesInNextRows(AnimatedEmojiSpan actionSpan) { + Editable editable = editText.getText(); + Layout layout = editText.getLayout(); + int deleteLine = layout.getLineForOffset(editable.getSpanStart(actionSpan)); + int nextLine = deleteLine + 1; + if (nextLine < layout.getLineCount()) { + int newLineStart = layout.getLineStart(nextLine); + AnimatedEmojiSpan[] spans = editable.getSpans(newLineStart, editable.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + span.setAnimateChanges(); + } + } + } + + private boolean deleteSelectedEmojis() { + int selectionEnd = editText.getEditTextSelectionEnd(); + int selectionStart = editText.getEditTextSelectionStart(); + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + if (editText.hasSelection()) { + AnimatedEmojiSpan[] spans = spanned.getSpans(selectionStart, selectionEnd, AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + selectedEmojisMap.remove(span.documentId); + selectedEmojisIds.remove(span.documentId); + selectAnimatedEmojiDialog.unselect(span.documentId); + } + editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); + checkMaxCustomReactions(false); + return true; + } + return false; + } + + @Override + public boolean canBeginSlide() { + if (checkChangesBeforeExit()) { + return false; + } + return super.canBeginSlide(); + } + + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + super.onTransitionAnimationEnd(isOpen, backward); + if (isOpen && selectedType != SELECT_TYPE_NONE) { + editText.setFocusableInTouchMode(true); + } + if (isOpen && !backward) { + initSelectAnimatedEmojiDialog(); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512), 200); + } + } + + private void setCheckedEnableReactionCell(int selectType, boolean animated) { + if (selectedType == selectType) { + return; + } + + boolean checked = selectType == SELECT_TYPE_SOME || selectType == SELECT_TYPE_ALL; + enableReactionsCell.setChecked(checked); + int clr = Theme.getColor(checked ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked); + if (animated) { + if (checked) { + enableReactionsCell.setBackgroundColorAnimated(true, clr); + } else { + enableReactionsCell.setBackgroundColorAnimatedReverse(clr); + } + } else { + enableReactionsCell.setBackgroundColor(clr); + } + + this.selectedType = selectType; + + if (selectType == SELECT_TYPE_SOME || selectType == SELECT_TYPE_ALL) { + switchLayout.setVisibility(View.VISIBLE); + actionButton.setVisibility(View.VISIBLE); + if (animated) { + actionButton.animate().setListener(null).cancel(); + switchLayout.animate().setListener(null).cancel(); + switchLayout.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + editText.setFocusableInTouchMode(true); + } + }).start(); + actionButton.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + if (selectedEmojisMap.isEmpty()) { + selectAnimatedEmojiDialog.clearSelectedDocuments(); + editText.setText(""); + int i = 0; + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + editText.addReactionsSpan(); + selectAnimatedEmojiDialog.notifyDataSetChanged(); + checkMaxCustomReactions(false); + } + } + } else { + if (animated) { + closeKeyboard(); + actionButton.animate().setListener(null).cancel(); + switchLayout.animate().setListener(null).cancel(); + actionButton.animate().alpha(0f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + actionButton.setVisibility(View.INVISIBLE); + } + }).start(); + switchLayout.animate().alpha(0f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + editText.setFocusableInTouchMode(false); + switchLayout.setVisibility(View.INVISIBLE); + } + }).start(); + } else { + switchLayout.setVisibility(View.INVISIBLE); + actionButton.setVisibility(View.INVISIBLE); + } + } + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + AndroidUtilities.cancelRunOnUIThread(checkAfterFastDeleteRunnable); + if (selectedType == SELECT_TYPE_NONE) { + getMessagesController().setCustomChatReactions(chatId, selectedType, new ArrayList<>(), null, null); + } + } + + @Override + public void onResume() { + super.onResume(); + if (isPaused) { + isPaused = false; + editText.setFocusable(true); + editText.setFocusableInTouchMode(true); + if (emojiKeyboardVisible) { + editText.removeReactionsSpan(false); + AndroidUtilities.runOnUIThread(() -> editText.requestFocus(), 250); + } + } + } + + @Override + public void onPause() { + isPaused = true; + editText.setFocusable(false); + super.onPause(); + } + + @Override + public boolean onBackPressed() { + if (closeKeyboard()) { + return false; + } + if (checkChangesBeforeExit()) { + return false; + } + return super.onBackPressed(); + } + + private boolean checkChangesBeforeExit() { + boolean hasChanges = !selectedEmojisMap.keySet().equals(initialSelectedEmojis.keySet()); + if (boostsStatus != null && boostsStatus.level < selectedCustomReactions) { + hasChanges = false; + } + if (selectedType == SELECT_TYPE_NONE) { + hasChanges = false; + } + if (hasChanges) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), getResourceProvider()); + builder.setTitle(getString("UnsavedChanges", R.string.UnsavedChanges)); + String text = getString("ReactionApplyChangesDialog", R.string.ReactionApplyChangesDialog); + builder.setMessage(text); + builder.setPositiveButton(getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> { + actionButton.performClick(); + }); + builder.setNegativeButton(getString("Discard", R.string.Discard), (dialogInterface, i) -> finishFragment()); + builder.show(); + } + return hasChanges; + } + + private void checkMaxCustomReactions(boolean withToast) { + if (boostsStatus == null) { + return; + } + if (selectedType == SELECT_TYPE_ALL) { + selectedType = SELECT_TYPE_SOME; + } + selectedCustomReactions = grabReactions(true).size(); + if (boostsStatus.level < selectedCustomReactions) { + if (withToast) { + CharSequence text = replaceTags(formatPluralString("ReactionReachLvlForReactionShort", selectedCustomReactions, selectedCustomReactions)); + BulletinFactory.of(this) + .createSimpleBulletin(R.raw.chats_infotip, text) + .show(); + } + actionButton.setLvlRequiredState(selectedCustomReactions); + } else { + actionButton.removeLvlRequiredState(); + } + } + + private List grabReactions(boolean onlyCustom) { + List reactions = new ArrayList<>(); + List customReactions = new ArrayList<>(); + for (Long documentId : selectedEmojisIds) { + boolean isReactionEmoji = false; + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + if (documentId == availableReaction.activate_animation.id) { + TLRPC.TL_reactionEmoji emojiReaction = new TLRPC.TL_reactionEmoji(); + emojiReaction.emoticon = availableReaction.reaction; + reactions.add(emojiReaction); + isReactionEmoji = true; + break; + } + } + + if (!isReactionEmoji) { + TLRPC.TL_reactionCustomEmoji customEmoji = new TLRPC.TL_reactionCustomEmoji(); + customEmoji.document_id = documentId; + reactions.add(customEmoji); + customReactions.add(customEmoji); + } + } + if (onlyCustom) { + return customReactions; + } + return reactions; + } + + private void showKeyboard() { + if (!emojiKeyboardVisible) { + emojiKeyboardVisible = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + updateScrollViewMarginBottom(bottomDialogLayout.getMeasuredHeight()); + bottomDialogLayout.setVisibility(View.VISIBLE); + bottomDialogLayout.setTranslationY(bottomDialogLayout.getMeasuredHeight()); + bottomDialogLayout.animate().setListener(null).cancel(); + bottomDialogLayout.animate().translationY(0).withLayer().setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setUpdateListener(animation -> { + actionButton.setTranslationY(-(float) animation.getAnimatedValue() * bottomDialogLayout.getMeasuredHeight()); + }).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + scrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }).start(); + } + } + + private boolean closeKeyboard() { + if (emojiKeyboardVisible) { + emojiKeyboardVisible = false; + editText.clearFocus(); + updateScrollViewMarginBottom(0); + bottomDialogLayout.animate().setListener(null).cancel(); + bottomDialogLayout.animate().translationY(bottomDialogLayout.getMeasuredHeight()).setDuration(350).withLayer().setInterpolator(CubicBezierInterpolator.DEFAULT).setUpdateListener(animation -> { + actionButton.setTranslationY(-(1f - (float) animation.getAnimatedValue()) * bottomDialogLayout.getMeasuredHeight()); + }).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + bottomDialogLayout.setVisibility(View.INVISIBLE); + } + }).start(); + return true; + } + return false; + } + + private void updateScrollViewMarginBottom(int margin) { + ViewGroup.MarginLayoutParams marginLayoutParams = ((ViewGroup.MarginLayoutParams) scrollView.getLayoutParams()); + marginLayoutParams.bottomMargin = margin; + scrollView.setLayoutParams(marginLayoutParams); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index 74295e18a6..78cbb7cb31 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -164,7 +164,8 @@ public void setAlpha(float alpha) { // sizeNotifierFrameLayout.setFitsSystemWindows(true); containerView = new ContainerView(context); - selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(baseFragment, context, false, null, SelectAnimatedEmojiDialog.TYPE_REACTIONS, type != TYPE_STORY, resourcesProvider, 16) { + int dialogType = reactionsContainerLayout.showExpandableReactions() ? SelectAnimatedEmojiDialog.TYPE_EXPANDABLE_REACTIONS : SelectAnimatedEmojiDialog.TYPE_REACTIONS; + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(baseFragment, context, false, null, dialogType, type != TYPE_STORY, resourcesProvider, 16) { @Override public boolean prevWindowKeyboardVisible() { @@ -343,9 +344,15 @@ private void createTransition(boolean enter) { } windowView.getLocationOnScreen(windowLocation); float y = location[1] - windowLocation[1] - AndroidUtilities.dp(44) - AndroidUtilities.dp(52) - (selectAnimatedEmojiDialog.includeHint ? AndroidUtilities.dp(26) : 0) + reactionsContainerLayout.getTopOffset(); + + if (reactionsContainerLayout.showExpandableReactions()) { + y = location[1] - windowLocation[1] - AndroidUtilities.dp(12); + } + if (y + containerView.getMeasuredHeight() > windowView.getMeasuredHeight() - AndroidUtilities.dp(32)) { y = windowView.getMeasuredHeight() - AndroidUtilities.dp(32) - containerView.getMeasuredHeight(); } + if (y < AndroidUtilities.dp(16)) { y = AndroidUtilities.dp(16); } @@ -733,9 +740,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } int height = size; -// if (height * 1.2 < MeasureSpec.getSize(heightMeasureSpec)) { -// height *= 1.2; -// } + if (reactionsContainerLayout.showExpandableReactions()) { + int rows = (int) Math.ceil(reactions.size() / 8f); + if (rows <= 8) { + height = rows * AndroidUtilities.dp(36) + AndroidUtilities.dp(8); + } else { + height = AndroidUtilities.dp(36) * 8 - AndroidUtilities.dp(8); + } + } super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } @@ -811,7 +823,8 @@ protected void dispatchDraw(Canvas canvas) { } int top = (int) (selectAnimatedEmojiDialog.getX() + selectAnimatedEmojiDialog.emojiGridView.getX()); int left = (int) (selectAnimatedEmojiDialog.getY() + selectAnimatedEmojiDialog.emojiGridView.getY()); - canvas.clipRect(left, top + AndroidUtilities.dp(36) * enterTransitionProgress, left + selectAnimatedEmojiDialog.emojiGridView.getMeasuredHeight(), top + selectAnimatedEmojiDialog.emojiGridView.getMeasuredWidth()); + boolean isEmojiTabsVisible = selectAnimatedEmojiDialog.emojiTabs.getParent() != null; + canvas.clipRect(left, isEmojiTabsVisible ? top + AndroidUtilities.dp(36) * enterTransitionProgress : 0, left + selectAnimatedEmojiDialog.emojiGridView.getMeasuredWidth(), top + selectAnimatedEmojiDialog.emojiGridView.getMeasuredHeight()); for (int i = -1; i < reactionsContainerLayout.recyclerListView.getChildCount(); i++) { View child; if (i == -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java new file mode 100644 index 0000000000..a9bd07b048 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java @@ -0,0 +1,165 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Paint; +import android.os.Build; +import android.text.InputFilter; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.util.TypedValue; +import android.view.ActionMode; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.Menu; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.core.view.GestureDetectorCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.EditTextCaption; + +@SuppressLint("ViewConstructor") +public class CustomReactionEditText extends EditTextCaption { + + private final Theme.ResourcesProvider resourcesProvider; + private final GestureDetectorCompat gestureDetector; + private Runnable onFocused; + + public CustomReactionEditText(Context context, Theme.ResourcesProvider resourcesProvider, int maxLength) { + super(context, resourcesProvider); + this.resourcesProvider = resourcesProvider; + this.gestureDetector = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(@NonNull MotionEvent e) { + return true; + } + }); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + setIncludeFontPadding(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setShowSoftInputOnFocus(false); + } + setSingleLine(false); + setMaxLines(50); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(maxLength); + setFilters(inputFilters); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); + setGravity(Gravity.BOTTOM); + setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(4), AndroidUtilities.dp(18), AndroidUtilities.dp(12)); + setTextColor(getThemedColor(Theme.key_chat_messagePanelText)); + setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkOut)); + setHighlightColor(getThemedColor(Theme.key_chat_inTextSelectionHighlight)); + setHintColor(getThemedColor(Theme.key_chat_messagePanelHint)); + setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); + setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); + setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + setFallbackLineSpacing(false); + } + setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus) { + removeReactionsSpan(true); + if (onFocused != null) { + onFocused.run(); + } + } else { + addReactionsSpan(); + } + }); + setTextIsSelectable(true); + setLongClickable(false); + setFocusableInTouchMode(false); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (gestureDetector.onTouchEvent(event)) { + if(!isLongClickable()) { + return false; + } + } + return super.dispatchTouchEvent(event); + } + + @Override + protected void onSelectionChanged(int selStart, int selEnd) { + super.onSelectionChanged(selStart, selEnd); + if (hasSelection()) { + AddReactionsSpan[] spans = getText().getSpans(selStart, selEnd, AddReactionsSpan.class); + if (spans.length != 0) { + setSelection(selStart, selEnd - 1); + } + } + } + + @Override + protected void extendActionMode(ActionMode actionMode, Menu menu) { + menu.clear(); + menu.add(R.id.menu_delete, R.id.menu_delete, 0, LocaleController.getString("Delete", R.string.Delete)); + } + + public void setOnFocused(Runnable onFocused) { + this.onFocused = onFocused; + } + + public void addReactionsSpan() { + setLongClickable(false); + SpannableStringBuilder spannableText = new SpannableStringBuilder(getText()); + AddReactionsSpan[] spans = spannableText.getSpans(0, spannableText.length(), AddReactionsSpan.class); + if (spans.length == 0) { + SpannableStringBuilder builder = new SpannableStringBuilder("x"); + AddReactionsSpan span = new AddReactionsSpan(15, resourcesProvider); + span.show(this); + builder.setSpan(span, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + setText(getText().append(builder)); + } + } + + public void removeReactionsSpan(boolean animate) { + SpannableStringBuilder spannableText = new SpannableStringBuilder(getText()); + AddReactionsSpan[] spans = spannableText.getSpans(0, spannableText.length(), AddReactionsSpan.class); + for (AddReactionsSpan span : spans) { + Runnable action = () -> { + getText().delete(getText().getSpanStart(span), getText().getSpanEnd(span)); + setCursorVisible(true); + setLongClickable(true); + }; + if (animate) { + setCursorVisible(false); + span.hide(this, action); + } else { + action.run(); + } + } + } + + public int getEditTextSelectionEnd() { + int selectionEnd = getSelectionEnd(); + if (selectionEnd < 0) { + selectionEnd = 0; + } + return selectionEnd; + } + + public int getEditTextSelectionStart() { + int selectionStart = getSelectionStart(); + if (selectionStart < 0) { + selectionStart = 0; + } + return selectionStart; + } + + public int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } + + public Paint.FontMetricsInt getFontMetricsInt() { + return getPaint().getFontMetricsInt(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java index 6d5713f4ea..59c923449b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java @@ -144,14 +144,14 @@ public ReactionsEffectOverlay(Context context, BaseFragment fragment, ReactionsC if (chat == null) { continue; } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageReceiver.setForUserOrChat(chat, avatarDrawable); } else { user = MessagesController.getInstance(currentAccount).getUser(peerId); if (user == null) { continue; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageReceiver.setForUserOrChat(user, avatarDrawable); } @@ -225,8 +225,8 @@ public ReactionsEffectOverlay(Context context, BaseFragment fragment, ReactionsC fromHeight = holderView.loopImageView.getWidth() * holderView.getScaleX(); } else if (reactionButton != null) { cell.getLocationInWindow(loc); - fromX = loc[0] + cell.reactionsLayoutInBubble.x + reactionButton.x + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageX()); - fromY = loc[1] + cell.reactionsLayoutInBubble.y + reactionButton.y + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageY()); + fromX = loc[0] + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageX()); + fromY = loc[1] + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageY()); fromHeight = reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageHeight(); } else if (cell != null) { ((View) cell.getParent()).getLocationInWindow(loc); @@ -315,11 +315,11 @@ protected void dispatchDraw(Canvas canvas) { cell.getLocationInWindow(loc); ReactionsLayoutInBubble.ReactionButton reactionButton = cell.getReactionButton(reaction); - toX = loc[0] + cell.reactionsLayoutInBubble.x; - toY = loc[1] + cell.reactionsLayoutInBubble.y; + toX = loc[0]; + toY = loc[1]; if (reactionButton != null) { - toX += reactionButton.x + reactionButton.drawingImageRect.left; - toY += reactionButton.y + reactionButton.drawingImageRect.top; + toX += reactionButton.drawingImageRect.left; + toY += reactionButton.drawingImageRect.top; } if (chatActivity != null) { toY += chatActivity.drawingChatLisViewYoffset; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java index ef0f86d56c..f20c5ecd70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java @@ -316,8 +316,6 @@ public void draw(Canvas canvas, float animationProgress, String drawOnlyReaction totalX = totalX * (animationProgress) + fromX * (1f - animationProgress); totalY = totalY * (animationProgress) + fromY * (1f - animationProgress); } - canvas.save(); - canvas.translate(totalX, totalY); for (int i = 0; i < reactionButtons.size(); i++) { ReactionButton reactionButton = reactionButtons.get(i); if (reactionButton.reaction.equals(scrimViewReaction) || (drawOnlyReaction != null && !reactionButton.reaction.equals(drawOnlyReaction))) { @@ -330,27 +328,24 @@ public void draw(Canvas canvas, float animationProgress, String drawOnlyReaction x = reactionButton.x * animationProgress + reactionButton.animateFromX * (1f - animationProgress); y = reactionButton.y * animationProgress + reactionButton.animateFromY * (1f - animationProgress); } - canvas.translate(x, y); float alpha = 1f; if (animationProgress != 1f && reactionButton.animationType == ANIMATION_TYPE_IN) { float s = 0.5f + 0.5f * animationProgress; alpha = animationProgress; - canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f); + canvas.scale(s, s, totalX + x + reactionButton.width / 2f, totalY + y + reactionButton.height / 2f); } - reactionButton.draw(canvas, reactionButton.animationType == ANIMATION_TYPE_MOVE ? animationProgress : 1f, alpha, drawOnlyReaction != null); + reactionButton.draw(canvas, totalX + x, totalY + y, reactionButton.animationType == ANIMATION_TYPE_MOVE ? animationProgress : 1f, alpha, drawOnlyReaction != null); canvas.restore(); } for (int i = 0; i < outButtons.size(); i++) { ReactionButton reactionButton = outButtons.get(i); - canvas.save(); - canvas.translate(reactionButton.x, reactionButton.y); float s = 0.5f + 0.5f * (1f - animationProgress); - canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f); - outButtons.get(i).draw(canvas, 1f, (1f - animationProgress), false); + canvas.save(); + canvas.scale(s, s, totalX + reactionButton.x + reactionButton.width / 2f, totalY + reactionButton.y + reactionButton.height / 2f); + outButtons.get(i).draw(canvas, totalX + reactionButton.x, totalY + reactionButton.y, 1f, (1f - animationProgress), false); canvas.restore(); } - canvas.restore(); } public void recordDrawingState() { @@ -584,12 +579,12 @@ public ReactionButton(ReactionButton reuseFrom, TLRPC.ReactionCount reactionCoun counterDrawable.gravity = Gravity.LEFT; } - public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlayScrim) { + public void draw(Canvas canvas, float x, float y, float progress, float alpha, boolean drawOverlayScrim) { wasDrawn = true; ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; if (isSmall && imageReceiver != null) { imageReceiver.setAlpha(alpha); - drawingImageRect.set(0, 0, AndroidUtilities.dp(14), AndroidUtilities.dp(14)); + drawingImageRect.set((int) x, (int) y, AndroidUtilities.dp(14), AndroidUtilities.dp(14)); imageReceiver.setImageCoords(drawingImageRect); imageReceiver.setRoundRadius(0); drawImage(canvas, alpha); @@ -625,11 +620,11 @@ public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlay if (progress != 1f && animationType == ANIMATION_TYPE_MOVE) { w = (int) (width * progress + animateFromWidth * (1f - progress)); } - AndroidUtilities.rectTmp.set(0, 0, w, height); + AndroidUtilities.rectTmp.set(x, y, x + w, y + height); float rad = height / 2f; if (drawServiceShaderBackground > 0) { Paint paint1 = getThemedPaint(Theme.key_paint_chatActionBackground); - Paint paint2 = Theme.chat_actionBackgroundGradientDarkenPaint; + Paint paint2 = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); int oldAlpha = paint1.getAlpha(); int oldAlpha2 = paint2.getAlpha(); paint1.setAlpha((int) (oldAlpha * alpha * drawServiceShaderBackground)); @@ -650,32 +645,32 @@ public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlay canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint); if (imageReceiver != null) { - int size, x; + int size, X; if (animatedEmojiDrawable != null) { size = AndroidUtilities.dp(24); - x = AndroidUtilities.dp(6); + X = AndroidUtilities.dp(6); imageReceiver.setRoundRadius(AndroidUtilities.dp(6)); } else { size = AndroidUtilities.dp(20); - x = AndroidUtilities.dp(8); + X = AndroidUtilities.dp(8); imageReceiver.setRoundRadius(0); } - int y = (int) ((height - size) / 2f); - drawingImageRect.set(x, y, x + size, y + size); + int Y = (int) ((height - size) / 2f); + drawingImageRect.set((int) x + X, (int) y + Y, (int) x + X + size, (int) y + Y + size); imageReceiver.setImageCoords(drawingImageRect); drawImage(canvas, alpha); } if (counterDrawable != null && (count != 0 || counterDrawable.countChangeProgress != 1f)) { canvas.save(); - canvas.translate(AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0); + canvas.translate(x + AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); counterDrawable.draw(canvas); canvas.restore(); } if (avatarsDrawable != null) { canvas.save(); - canvas.translate(AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0); + canvas.translate(x + AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); avatarsDrawable.setAlpha(alpha); avatarsDrawable.setTransitionProgress(progress); avatarsDrawable.onDraw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java index 1e4f6ff22a..7fb97beb54 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java @@ -1,11 +1,32 @@ package org.telegram.ui.Components.Reactions; +import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_REACTIONS; + +import android.graphics.Paint; +import android.os.Bundle; +import android.text.Editable; +import android.text.SpannableString; import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.EditTextCaption; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.SelectAnimatedEmojiDialog; +import org.telegram.ui.StatisticActivity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; public class ReactionsUtils { @@ -23,7 +44,7 @@ public static boolean compare(TLRPC.Reaction reaction, ReactionsLayoutInBubble.V return false; } - public static boolean compare(TLRPC.Reaction reaction, TLRPC.Reaction reaction2) { + public static boolean compare(TLRPC.Reaction reaction, TLRPC.Reaction reaction2) { if (reaction instanceof TLRPC.TL_reactionEmoji && reaction2 instanceof TLRPC.TL_reactionEmoji && TextUtils.equals(((TLRPC.TL_reactionEmoji) reaction).emoticon, ((TLRPC.TL_reactionEmoji) reaction2).emoticon)) { return true; } @@ -47,10 +68,10 @@ public static TLRPC.Reaction toTLReaction(ReactionsLayoutInBubble.VisibleReactio } public static CharSequence reactionToCharSequence(TLRPC.Reaction reaction) { - if (reaction instanceof TLRPC.TL_reactionEmoji){ + if (reaction instanceof TLRPC.TL_reactionEmoji) { return ((TLRPC.TL_reactionEmoji) reaction).emoticon; } - if (reaction instanceof TLRPC.TL_reactionCustomEmoji){ + if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d"); spannableStringBuilder.setSpan(new AnimatedEmojiSpan(((TLRPC.TL_reactionCustomEmoji) reaction).document_id, null), 0, 1, 0); return spannableStringBuilder; @@ -89,4 +110,112 @@ public static void applyForStoryViews(TLRPC.Reaction oldReaction, TLRPC.Reaction views.reactions.add(reactionCount); } } + + public static void showLimitReachedDialogForReactions(long dialogId, int lvl, TL_stories.TL_premium_boostsStatus boostsStatus) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null || boostsStatus == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(fragment, fragment.getContext(), TYPE_BOOSTS_FOR_REACTIONS, UserConfig.selectedAccount, fragment.getResourceProvider()); + limitReachedBottomSheet.setRequiredLvl(lvl); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = fragment.getMessagesController().getChat(-dialogId); + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = fragment.getMessagesController().getChatFull(-dialogId); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + } + fragment.presentFragment(new StatisticActivity(args)); + }); + limitReachedBottomSheet.show(); + } + + public static SpannableString createSpannableText(AnimatedEmojiSpan span, String key) { + SpannableString spannable = new SpannableString(key); + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return spannable; + } + + public static AnimatedEmojiSpan createAnimatedEmojiSpan(TLRPC.Document document, Long documentId, Paint.FontMetricsInt fontMetricsInt) { + AnimatedEmojiSpan span; + if (document != null) { + span = new AnimatedEmojiSpan(document, 1.0f, fontMetricsInt); + } else { + span = new AnimatedEmojiSpan(documentId, 1.0f, fontMetricsInt); + } + span.cacheType = AnimatedEmojiDrawable.getCacheTypeForEnterView(); + return span; + } + + public static void addReactionToEditText(TLRPC.TL_availableReaction availableReaction, HashMap selectedEmojis, List selectedEmojisIds, Editable editText, SelectAnimatedEmojiDialog selectAnimatedEmojiDialog, Paint.FontMetricsInt fontMetricsInt) { + long id = availableReaction.activate_animation.id; + AnimatedEmojiSpan span = createAnimatedEmojiSpan(availableReaction.activate_animation, id, fontMetricsInt); + selectedEmojis.put(id, span); + selectedEmojisIds.add(id); + editText.append(createSpannableText(span, "e")); + if (selectAnimatedEmojiDialog != null) { + selectAnimatedEmojiDialog.setMultiSelected(id, false); + } + } + + public static void addReactionToEditText(TLRPC.TL_reactionCustomEmoji customEmoji, HashMap selectedEmojis, List selectedEmojisIds, Editable editText, SelectAnimatedEmojiDialog selectAnimatedEmojiDialog, Paint.FontMetricsInt fontMetricsInt) { + AnimatedEmojiSpan span = createAnimatedEmojiSpan(null, customEmoji.document_id, fontMetricsInt); + selectedEmojis.put(customEmoji.document_id, span); + selectedEmojisIds.add(customEmoji.document_id); + editText.append(createSpannableText(span, "e")); + if (selectAnimatedEmojiDialog != null) { + selectAnimatedEmojiDialog.setMultiSelected(customEmoji.document_id, false); + } + } + + public static List startPreloadReactions(TLRPC.Chat currentChat, TLRPC.ChatFull chatFull) { + List result = new ArrayList<>(); + if (chatFull == null || !ChatObject.isChannelAndNotMegaGroup(currentChat)) { + return result; + } + if (chatFull.available_reactions instanceof TLRPC.TL_chatReactionsSome) { + TLRPC.TL_chatReactionsSome reactionsSome = (TLRPC.TL_chatReactionsSome) chatFull.available_reactions; + for (TLRPC.Reaction reaction : reactionsSome.reactions) { + AnimatedEmojiDrawable animatedEmojiDrawable = null; + if (reaction instanceof TLRPC.TL_reactionEmoji) { + TLRPC.TL_reactionEmoji reactionEmoji = ((TLRPC.TL_reactionEmoji) reaction); + TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsMap().get(reactionEmoji.emoticon); + if (availableReaction == null) { + continue; + } + TLRPC.Document document = availableReaction.activate_animation; + animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), document); + } else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { + TLRPC.TL_reactionCustomEmoji customEmoji = (TLRPC.TL_reactionCustomEmoji) reaction; + animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), customEmoji.document_id); + } + if (animatedEmojiDrawable != null) { + result.add(animatedEmojiDrawable); + animatedEmojiDrawable.addView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } + } else if (chatFull.available_reactions instanceof TLRPC.TL_chatReactionsAll) { + for (TLRPC.TL_availableReaction availableReaction : MediaDataController.getInstance(UserConfig.selectedAccount).getEnabledReactionsList()) { + if (availableReaction == null) { + continue; + } + TLRPC.Document document = availableReaction.activate_animation; + AnimatedEmojiDrawable animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), document); + result.add(animatedEmojiDrawable); + animatedEmojiDrawable.addView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } + return result; + } + + public static void stopPreloadReactions(List list) { + for (AnimatedEmojiDrawable animatedEmojiDrawable : list) { + animatedEmojiDrawable.removeView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java new file mode 100644 index 0000000000..861cb02d19 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java @@ -0,0 +1,44 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.SpannableStringBuilder; +import android.text.Spanned; + +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +@SuppressLint("ViewConstructor") +public class UpdateReactionsButton extends ButtonWithCounterView { + + private SpannableStringBuilder lock; + + public UpdateReactionsButton(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + } + + public UpdateReactionsButton(Context context, boolean filled, Theme.ResourcesProvider resourcesProvider) { + super(context, filled, resourcesProvider); + } + + public void setDefaultState() { + setText(new SpannableStringBuilder(LocaleController.getString("ReactionUpdateReactionsBtn", R.string.ReactionUpdateReactionsBtn)), false); + lock = new SpannableStringBuilder("l"); + ColoredImageSpan coloredImageSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); + coloredImageSpan.setTopOffset(1); + lock.setSpan(coloredImageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + public void setLvlRequiredState(int lvl) { + SpannableStringBuilder buttonLockedText = new SpannableStringBuilder(); + buttonLockedText.append(lock).append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", lvl)); + setSubText(buttonLockedText, true); + } + + public void removeLvlRequiredState() { + setSubText(null, true); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index 5e93a2cab2..d5dbee1ce7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -170,6 +170,7 @@ public void set(ReactionsContainerLayout object, Float value) { HashSet lastVisibleViews = new HashSet<>(); HashSet lastVisibleViewsTmp = new HashSet<>(); private boolean allReactionsAvailable; + private boolean showExpandableReactions; private boolean allReactionsIsDefault; private Paint selectedPaint; ChatScrimPopupContainerLayout parentLayout; @@ -325,6 +326,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int switch (viewType) { default: case VIEW_TYPE_REACTION: + case VIEW_TYPE_CUSTOM_REACTION: view = new ReactionHolderView(context, true); break; case VIEW_TYPE_PREMIUM_BUTTON: @@ -371,7 +373,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_REACTION) { + if (holder.getItemViewType() == VIEW_TYPE_REACTION || holder.getItemViewType() == VIEW_TYPE_CUSTOM_REACTION) { ReactionHolderView h = (ReactionHolderView) holder.itemView; h.setScaleX(1); h.setScaleY(1); @@ -395,6 +397,7 @@ public int getItemViewType(int position) { private static final int VIEW_TYPE_REACTION = 0; private static final int VIEW_TYPE_PREMIUM_BUTTON = 1; private static final int VIEW_TYPE_CUSTOM_EMOJI_BUTTON = 2; + private static final int VIEW_TYPE_CUSTOM_REACTION = 3; @Override public void notifyDataSetChanged() { @@ -402,7 +405,8 @@ public void notifyDataSetChanged() { oldItems.addAll(items); items.clear(); for (int i = 0; i < visibleReactionsList.size(); i++) { - items.add(new InnerItem(VIEW_TYPE_REACTION, visibleReactionsList.get(i))); + ReactionsLayoutInBubble.VisibleReaction visibleReaction = visibleReactionsList.get(i); + items.add(new InnerItem(visibleReaction.emojicon == null ? VIEW_TYPE_CUSTOM_REACTION : VIEW_TYPE_REACTION, visibleReaction)); } if (showUnlockPremiumButton()) { items.add(new InnerItem(VIEW_TYPE_PREMIUM_BUTTON, null)); @@ -427,7 +431,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; InnerItem innerItem = (InnerItem) o; - if (viewType == innerItem.viewType && viewType == VIEW_TYPE_REACTION) { + if (viewType == innerItem.viewType && (viewType == VIEW_TYPE_REACTION || viewType == VIEW_TYPE_CUSTOM_REACTION)) { return reaction != null && reaction.equals(innerItem.reaction); } return viewType == innerItem.viewType; @@ -512,6 +516,10 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R MediaDataController.getInstance(currentAccount).preloadDefaultReactions(); } + public boolean showExpandableReactions() { + return showExpandableReactions; + } + private void animatePullingBack() { if (pullingLeftOffset != 0) { pullingDownBackAnimator = ValueAnimator.ofFloat(pullingLeftOffset, 0); @@ -565,7 +573,7 @@ private void invalidateLoopViews() { } public boolean showCustomEmojiReaction() { - return !MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable; + return (!MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable) || showExpandableReactions; } private boolean showUnlockPremiumButton() { @@ -1083,6 +1091,7 @@ public void setMessage(MessageObject message, TLRPC.ChatFull chatFull) { fillRecentReactionsList(visibleReactions); } filterReactions(visibleReactions); + showExpandableReactions = !allReactionsAvailable && visibleReactions.size() > 16; setVisibleReactionsList(visibleReactions); if (message != null && message.messageOwner.reactions != null && message.messageOwner.reactions.results != null) { @@ -1840,7 +1849,7 @@ protected void dispatchDraw(Canvas canvas) { public void checkPlayLoopImage() { ImageReceiver imageReceiver = loopImageView.animatedEmojiDrawable != null ? loopImageView.animatedEmojiDrawable.getImageReceiver() : loopImageView.imageReceiver; if (imageReceiver != null && imageReceiver.getLottieAnimation() != null) { - if (reactionsWindow != null || pressed) { + if (reactionsWindow != null || pressed || !allReactionsIsDefault) { imageReceiver.getLottieAnimation().start(); } else { if (imageReceiver.getLottieAnimation().getCurrentFrame() <= 2) { 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 d165674f08..e5bf8e323c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java @@ -17,18 +17,17 @@ import androidx.core.math.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; -import xyz.nextalone.nagram.NaConfig; -import xyz.nextalone.nagram.helper.PeerColorHelper; - public class ReplyMessageLine { private final RectF rectF = new RectF(); @@ -108,6 +107,7 @@ public void setBackgroundColor(int backgroundColor) { private int wasMessageId; private int wasColorId; private void resolveColor(MessageObject messageObject, int colorId, Theme.ResourcesProvider resourcesProvider) { + final boolean dark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); if (wasColorId != colorId) { final int msgId = messageObject != null ? messageObject.getId() : 0; if (msgId == wasMessageId) { @@ -129,9 +129,9 @@ private void resolveColor(MessageObject messageObject, int colorId, Theme.Resour hasColor2 = hasColor3 = false; return; } - color1 = peerColor.getColor1(); - color2 = peerColor.getColor2(); - color3 = peerColor.getColor3(); + color1 = peerColor.getColor1(dark); + color2 = peerColor.getColor2(dark); + color3 = peerColor.getColor3(dark); hasColor2 = color2 != color1; hasColor3 = color3 != color1; if (hasColor3) { @@ -147,12 +147,13 @@ private void resolveColor(MessageObject messageObject, int colorId, Theme.Resour public static final int TYPE_LINK = 3; public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat currentChat, Theme.ResourcesProvider resourcesProvider, final int type) { + final boolean dark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); reversedOut = false; emojiDocumentId = 0; if (messageObject == null) { hasColor2 = hasColor3 = false; color1 = color2 = color3 = Theme.getColor(Theme.key_chat_inReplyLine, resourcesProvider); - backgroundColor = Theme.multAlpha(color1, Theme.isCurrentThemeDark() ? 0.12f : 0.10f); + backgroundColor = Theme.multAlpha(color1, dark ? 0.12f : 0.10f); return nameColorAnimated.set(nameColor = Theme.getColor(Theme.key_chat_inReplyNameText, resourcesProvider)); } else if (type != TYPE_REPLY && ( messageObject.overrideLinkColor >= 0 || @@ -170,47 +171,28 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat } else if (messageObject.isSponsored() && messageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = messageObject.sponsoredChatInvite.color; } else if (messageObject.isSponsored() && messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { - if ((messageObject.sponsoredChatInvite.chat.flags2 & 64) != 0) { - colorId = messageObject.sponsoredChatInvite.chat.color; - } else { - colorId = (int) (messageObject.sponsoredChatInvite.chat.id % 7); - } + colorId = ChatObject.getColorId(messageObject.sponsoredChatInvite.chat); } else if (messageObject.messageOwner != null && messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.from_id != null) { long dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.fwd_from.from_id); if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + colorId = ChatObject.getColorId(chat); } } else { TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(dialogId); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + colorId = UserObject.getColorId(user); } } } else if (DialogObject.isEncryptedDialog(messageObject.getDialogId()) && currentUser != null) { TLRPC.User user = messageObject.isOutOwner() ? UserConfig.getInstance(messageObject.currentAccount).getCurrentUser() : currentUser; if (user == null) user = currentUser; - if ((user.flags2 & 128) != 0) { - colorId = user.color; - } else { - colorId = (int) (user.id % 7); - } + colorId = UserObject.getColorId(user); } else if (messageObject.isFromUser() && currentUser != null) { - if ((currentUser.flags2 & 128) != 0) { - colorId = currentUser.color; - } else { - colorId = (int) (currentUser.id % 7); - } - if (currentUser.self) { - colorId = PeerColorHelper.replaceColor(colorId); - } + colorId = UserObject.getColorId(currentUser); } else if (messageObject.isFromChannel() && currentChat != null) { - if ((currentChat.flags2 & 64) != 0) { - colorId = currentChat.color; - } else { - colorId = (int) (currentChat.id % 7); - } + colorId = ChatObject.getColorId(currentChat); } else { colorId = 0; } @@ -234,34 +216,24 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat } else if (DialogObject.isEncryptedDialog(messageObject.replyMessageObject.getDialogId())) { TLRPC.User user = messageObject.replyMessageObject.isOutOwner() ? UserConfig.getInstance(messageObject.replyMessageObject.currentAccount).getCurrentUser() : currentUser; if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); - if ((user.flags2 & 64) != 0) { - emojiDocumentId = user.background_emoji_id; - } + colorId = UserObject.getColorId(user); + emojiDocumentId = UserObject.getEmojiId(user); } else { colorId = 0; } } else if (messageObject.replyMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(messageObject.replyMessageObject.messageOwner.from_id.user_id); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); - if ((user.flags2 & 64) != 0) { - emojiDocumentId = user.background_emoji_id; - } - if (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool() && user.self) { - colorId = NaConfig.INSTANCE.getUseLocalQuoteColorColor().Int(); - emojiDocumentId = NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().Long(); - } + colorId = UserObject.getColorId(user); + emojiDocumentId = UserObject.getEmojiId(user); } else { colorId = 0; } } else if (messageObject.replyMessageObject.isFromChannel()) { TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(messageObject.replyMessageObject.messageOwner.from_id.channel_id); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); - if ((chat.flags2 & 32) != 0) { - emojiDocumentId = chat.background_emoji_id; - } + colorId = ChatObject.getColorId(chat); + emojiDocumentId = ChatObject.getEmojiId(chat); } else { colorId = 0; } @@ -294,7 +266,7 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat reversedOut = true; color1 = Theme.multAlpha(color1, .35f); } - backgroundColor = Theme.multAlpha(color3, Theme.isCurrentThemeDark() ? 0.12f : 0.10f); + backgroundColor = Theme.multAlpha(color3, dark ? 0.12f : 0.10f); nameColor = Theme.getColor(Theme.key_chat_outReplyNameText, resourcesProvider); } if (type == TYPE_REPLY && messageObject != null && messageObject.overrideLinkEmoji != -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java index 4db532954d..2536b7506a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -48,6 +48,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -347,7 +348,7 @@ public void addStickerTab(TLRPC.Chat chat) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(14)); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(UserConfig.selectedAccount, chat); BackupImageView imageView = stickerTabView.imageView; imageView.setLayerNum(imageReceiversPlayingNum); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java index e3011ff288..d55ac5441b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java @@ -121,6 +121,10 @@ public void run() { } }; + protected int processColor(int color) { + return color; + } + public ScrollSlidingTextTabStrip(Context context) { this(context, null); } @@ -144,6 +148,16 @@ public void setAlpha(float alpha) { super.setAlpha(alpha); ScrollSlidingTextTabStrip.this.invalidate(); } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + if (setInitialTab && idToPosition.indexOfKey(selectedTabId) >= 0 && tabsContainer.getChildAt(idToPosition.get(selectedTabId)) != null) { + scrollToChild(idToPosition.get(selectedTabId), false); + setInitialTab = false; + } + } }; tabsContainer.setOrientation(LinearLayout.HORIZONTAL); tabsContainer.setPadding(AndroidUtilities.dp(7), 0, AndroidUtilities.dp(7), 0); @@ -163,8 +177,8 @@ private void setAnimationProgressInernal(TextView newTab, TextView prevTab, floa if (newTab == null || prevTab == null) { return; } - int newColor = Theme.getColor(activeTextColorKey, resourcesProvider); - int prevColor = Theme.getColor(unactiveTextColorKey, resourcesProvider); + int newColor = processColor(Theme.getColor(activeTextColorKey, resourcesProvider)); + int prevColor = processColor(Theme.getColor(unactiveTextColorKey, resourcesProvider)); int r1 = Color.red(newColor); int g1 = Color.green(newColor); @@ -281,7 +295,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { }; tab.setWillNotDraw(false); tab.setGravity(Gravity.CENTER); - tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Theme.getColor(activeTextColorKey, resourcesProvider), .15f), 3)); + tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(processColor(Theme.getColor(activeTextColorKey, resourcesProvider)), .15f), 3)); tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); tab.setSingleLine(true); tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -337,7 +351,7 @@ public void scrollTo(int pageId, int position1, View v) { if (delegate != null) { delegate.onPageSelected(pageId, scrollingForward); } - scrollToChild(position1); + scrollToChild(position1, true); } public void scrollTo(int pageId) { @@ -349,7 +363,7 @@ public void finishAddingTabs() { for (int a = 0; a < count; a++) { TextView tab = (TextView) tabsContainer.getChildAt(a); tab.setTag(currentPosition == a ? activeTextColorKey : unactiveTextColorKey); - tab.setTextColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider)); + tab.setTextColor(processColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider))); if (a == 0) { tab.getLayoutParams().width = count == 1 ? LayoutHelper.WRAP_CONTENT : 0; } @@ -361,14 +375,27 @@ public void setColors(int line, int active, int unactive, int selector) { activeTextColorKey = active; unactiveTextColorKey = unactive; selectorColorKey = selector; - selectorDrawable.setColor(Theme.getColor(tabLineColorKey, resourcesProvider)); + selectorDrawable.setColor(processColor(Theme.getColor(tabLineColorKey, resourcesProvider))); + } + + public void updateColors() { + int count = tabsContainer.getChildCount(); + for (int a = 0; a < count; a++) { + TextView tab = (TextView) tabsContainer.getChildAt(a); + tab.setTextColor(processColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider))); + tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(processColor(Theme.getColor(activeTextColorKey, resourcesProvider)), .15f), 3)); + } + selectorDrawable.setColor(processColor(Theme.getColor(tabLineColorKey, resourcesProvider))); + invalidate(); } public int getCurrentTabId() { return selectedTabId; } + private boolean setInitialTab; public void setInitialTabId(int id) { + setInitialTab = true; selectedTabId = id; int pos = idToPosition.get(id); TextView child = (TextView) tabsContainer.getChildAt(pos); @@ -434,7 +461,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - private void scrollToChild(int position) { + private void scrollToChild(int position, boolean smooth) { if (tabCount == 0 || scrollingToChild == position) { return; } @@ -447,9 +474,17 @@ private void scrollToChild(int position) { int left = child.getLeft(); int width = child.getMeasuredWidth(); if (left - AndroidUtilities.dp(50) < currentScrollX) { - smoothScrollTo(left - AndroidUtilities.dp(50), 0); + if (smooth) { + smoothScrollTo(left - AndroidUtilities.dp(50), 0); + } else { + scrollTo(left - AndroidUtilities.dp(50), 0); + } } else if (left + width + AndroidUtilities.dp(21) > currentScrollX + getWidth()) { - smoothScrollTo(left + width, 0); + if (smooth) { + smoothScrollTo(left + width, 0); + } else { + scrollTo(left + width, 0); + } } } @@ -532,7 +567,7 @@ public void selectTabWithId(int id, float progress) { child.setTag(unactiveTextColorKey); nextChild.setTag(activeTextColorKey); } - scrollToChild(tabsContainer.indexOfChild(nextChild)); + scrollToChild(tabsContainer.indexOfChild(nextChild), true); } if (progress >= 1.0f) { currentPosition = position; @@ -561,9 +596,9 @@ public void onPageScrolled(int position, int first) { tabsContainer.getChildAt(a).setSelected(a == position); } if (first == position && position > 1) { - scrollToChild(position - 1); + scrollToChild(position - 1, true); } else { - scrollToChild(position); + scrollToChild(position, true); } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 0661e78608..1823e552a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -132,7 +132,7 @@ public SearchViewPager(Context context, DialogsActivity fragment, int type, int itemAnimator.setMoveInterpolator(new OvershootInterpolator(1.1f)); itemAnimator.setTranslationInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - dialogsSearchAdapter = new DialogsSearchAdapter(context, fragment, type, initialDialogsType, itemAnimator, fragment.getAllowGlobalSearch()) { + dialogsSearchAdapter = new DialogsSearchAdapter(context, fragment, type, initialDialogsType, itemAnimator, fragment.getAllowGlobalSearch(), null) { @Override public void notifyDataSetChanged() { int itemCount = getCurrentItemCount(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java index c7e183cc64..300834d3d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java @@ -9,16 +9,12 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.dynamicanimation.animation.FloatPropertyCompat; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index fbd92291fe..e3fcd105e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -100,6 +100,7 @@ import org.telegram.ui.Adapters.SearchAdapterHelper; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HintDialogCell; +import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Cells.ShareTopicCell; import org.telegram.ui.ChatActivity; @@ -148,11 +149,13 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi private SwitchView switchView; private int containerViewTop = -1; private boolean fullyShown = false; + private boolean includeStory; private ChatActivity parentFragment; private Activity parentActivity; private boolean darkTheme; + public boolean forceDarkThemeForHint; private RectF rect = new RectF(); private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -462,16 +465,17 @@ public ShareAlert(final Context context, ArrayList messages, fina } public ShareAlert(final Context context, ArrayList messages, final String text, boolean channel, final String copyLink, boolean fullScreen, Theme.ResourcesProvider resourcesProvider) { - this(context, null, messages, text, null, channel, copyLink, null, fullScreen, false, resourcesProvider); + this(context, null, messages, text, null, channel, copyLink, null, fullScreen, false, false, resourcesProvider); } public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall) { - this(context, fragment, messages, text, text2, channel, copyLink, copyLink2, fullScreen, forCall, null); + this(context, fragment, messages, text, text2, channel, copyLink, copyLink2, fullScreen, forCall, false, null); } - public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall, Theme.ResourcesProvider resourcesProvider) { + public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall, boolean includeStory, Theme.ResourcesProvider resourcesProvider) { super(context, true, resourcesProvider); this.resourcesProvider = resourcesProvider; + this.includeStory = includeStory; if (context instanceof Activity) { parentActivity = (Activity) context; @@ -870,6 +874,7 @@ public void requestLayout() { } private boolean lightStatusBar = AndroidUtilities.computePerceivedBrightness(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)) > .721f; + private final AnimatedFloat pinnedToTop = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @Override protected void onDraw(Canvas canvas) { @@ -880,37 +885,44 @@ protected void onDraw(Canvas canvas) { int height = getMeasuredHeight() + AndroidUtilities.dp(30 + 30) + backgroundPaddingTop; int statusBarHeight = 0; float radProgress = 1.0f; + float pinAlpha = 0; if (!isFullscreen && Build.VERSION.SDK_INT >= 21) { - top += AndroidUtilities.statusBarHeight; y += AndroidUtilities.statusBarHeight; - height -= AndroidUtilities.statusBarHeight; - - if (fullHeight) { - if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight * 2) { - int diff = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight * 2 - top - backgroundPaddingTop); - top -= diff; - height += diff; - radProgress = 1.0f - Math.min(1.0f, (diff * 2) / (float) AndroidUtilities.statusBarHeight); - } - if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight) { - statusBarHeight = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight - top - backgroundPaddingTop); - } - } + final boolean pinnedToTop = fullHeight && top + backgroundPaddingTop < AndroidUtilities.statusBarHeight; + top = AndroidUtilities.lerp(top + AndroidUtilities.statusBarHeight, -backgroundPaddingTop, pinAlpha = this.pinnedToTop.set(pinnedToTop)); +// top += AndroidUtilities.statusBarHeight; +// height -= AndroidUtilities.statusBarHeight; +// +// if (fullHeight) { +// if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight * 2) { +// int diff = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight * 2 - top - backgroundPaddingTop); +// top -= diff; +// height += diff; +// radProgress = 1.0f - Math.min(1.0f, (diff * 2) / (float) AndroidUtilities.statusBarHeight); +// } +// if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight) { +// statusBarHeight = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight - top - backgroundPaddingTop); +// } +// } } shadowDrawable.setBounds(0, top, getMeasuredWidth(), height); shadowDrawable.draw(canvas); - if (radProgress != 1.0f) { - Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)); - rect1.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); - canvas.drawRoundRect(rect1, AndroidUtilities.dp(12) * radProgress, AndroidUtilities.dp(12) * radProgress, Theme.dialogs_onlineCirclePaint); - } +// if (radProgress != 1.0f) { +// Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)); +// Theme.dialogs_onlineCirclePaint.setAlpha((int) (Theme.dialogs_onlineCirclePaint.getAlpha() * pinAlpha)); +// rect1.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); +// canvas.drawRoundRect(rect1, AndroidUtilities.dp(12) * radProgress, AndroidUtilities.dp(12) * radProgress, Theme.dialogs_onlineCirclePaint); +// } - int w = AndroidUtilities.dp(36); - rect1.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); - Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_scrollUp : Theme.key_sheet_scrollUp)); - canvas.drawRoundRect(rect1, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); + if (pinAlpha < 1) { + int w = AndroidUtilities.dp(36); + rect1.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); + Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_scrollUp : Theme.key_sheet_scrollUp)); + Theme.dialogs_onlineCirclePaint.setAlpha((int) (Theme.dialogs_onlineCirclePaint.getAlpha() * (1f - pinAlpha))); + canvas.drawRoundRect(rect1, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int flags = getSystemUiVisibility(); @@ -1126,7 +1138,7 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -1176,7 +1188,7 @@ public int getSpanSize(int position) { if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); searchGridView.setHasFixedSize(true); searchGridView.setItemAnimator(null); @@ -1194,11 +1206,15 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { searchGridView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - RecyclerListView.Holder holder = (RecyclerListView.Holder) parent.getChildViewHolder(view); + final RecyclerListView.Holder holder = (RecyclerListView.Holder) parent.getChildViewHolder(view); if (holder != null) { - int pos = holder.getAdapterPosition(); - outRect.left = pos % 4 == 0 ? 0 : AndroidUtilities.dp(4); - outRect.right = pos % 4 == 3 ? 0 : AndroidUtilities.dp(4); + if (holder.getItemViewType() != 5) { + outRect.left = outRect.right = 0; + } else { + final int pos = holder.getAdapterPosition(); + outRect.left = pos % 4 == 0 ? 0 : AndroidUtilities.dp(4); + outRect.right = pos % 4 == 3 ? 0 : AndroidUtilities.dp(4); + } } else { outRect.left = AndroidUtilities.dp(4); outRect.right = AndroidUtilities.dp(4); @@ -1501,7 +1517,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_dialogFloatingButton)); 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); @@ -1523,6 +1539,15 @@ protected void onDraw(Canvas canvas) { DialogsSearchAdapter.loadRecentSearch(currentAccount, 0, new DialogsSearchAdapter.OnRecentSearchLoaded() { @Override public void setRecentSearch(ArrayList arrayList, LongSparseArray hashMap) { + if (arrayList != null) { + for (int i = 0; i < arrayList.size(); ++i) { + DialogsSearchAdapter.RecentSearchObject recentSearchObject = arrayList.get(i); + if (recentSearchObject.object instanceof TLRPC.Chat && !ChatObject.canWriteToChat((TLRPC.Chat) recentSearchObject.object)) { + arrayList.remove(i); + i--; + } + } + } recentSearchObjects = arrayList; recentSearchObjectsById = hashMap; for (int a = 0; a < recentSearchObjects.size(); a++) { @@ -1544,7 +1569,13 @@ public void setRecentSearch(ArrayList a AndroidUtilities.updateViewVisibilityAnimated(searchGridView, false, 1f, false); } - private void selectDialog(ShareDialogCell cell, TLRPC.Dialog dialog) { + private void selectDialog(View cell, TLRPC.Dialog dialog) { + if (dialog instanceof ShareDialogsAdapter.MyStoryDialog) { + LongSparseArray dids = new LongSparseArray<>(); + dids.put(Long.MAX_VALUE, dialog); + onSend(dids, 1, null); + return; + } if (topicsGridView.getVisibility() != View.GONE || parentActivity == null) { return; } @@ -1584,8 +1615,10 @@ private void selectDialog(ShareDialogCell cell, TLRPC.Dialog dialog) { if (selectedDialogs.indexOfKey(dialog.id) >= 0) { selectedDialogs.remove(dialog.id); selectedDialogTopics.remove(dialog); - if (cell != null) { - cell.setChecked(false, true); + if (cell instanceof ProfileSearchCell) { + ((ProfileSearchCell) cell).setChecked(false, true); + } else if (cell instanceof ShareDialogCell) { + ((ShareDialogCell) cell).setChecked(false, true); } updateSelectedCount(1); } else { @@ -1665,8 +1698,10 @@ public void didReceivedNotification(int id, int account, Object... args) { } selectedDialogs.put(dialog.id, dialog); - if (cell != null) { - cell.setChecked(true, true); + if (cell instanceof ProfileSearchCell) { + ((ProfileSearchCell) cell).setChecked(true, true); + } else if (cell instanceof ShareDialogCell) { + ((ShareDialogCell) cell).setChecked(true, true); } updateSelectedCount(2); long selfUserId = UserConfig.getInstance(currentAccount).clientUserId; @@ -2351,6 +2386,10 @@ public void dismiss() { private class ShareDialogsAdapter extends RecyclerListView.SelectionAdapter { + private class MyStoryDialog extends TLRPC.Dialog { + { id = Long.MAX_VALUE; } + } + private Context context; private int currentCount; private ArrayList dialogs = new ArrayList<>(); @@ -2365,6 +2404,11 @@ public void fetchDialogs() { dialogs.clear(); dialogsMap.clear(); long selfUserId = UserConfig.getInstance(currentAccount).clientUserId; + if (includeStory) { + MyStoryDialog d = new MyStoryDialog(); + dialogs.add(d); + dialogsMap.put(d.id, d); + } if (!MessagesController.getInstance(currentAccount).dialogsForward.isEmpty()) { TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogsForward.get(0); dialogs.add(dialog); @@ -2579,7 +2623,12 @@ public class ShareSearchAdapter extends RecyclerListView.SelectionAdapter { public ShareSearchAdapter(Context context) { this.context = context; - searchAdapterHelper = new SearchAdapterHelper(false); + searchAdapterHelper = new SearchAdapterHelper(false) { + @Override + protected boolean filter(TLObject obj) { + return !(obj instanceof TLRPC.Chat) || ChatObject.canWriteToChat((TLRPC.Chat) obj); + } + }; searchAdapterHelper.setDelegate(new SearchAdapterHelper.SearchAdapterHelperDelegate() { @Override public void onDataSetChanged(int searchId) { @@ -2969,11 +3018,15 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: { + case 5: { view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE, resourcesProvider); view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); break; } + case 0: { + view = new ProfileSearchCell(context, resourcesProvider).useCustomPaints(); + break; + } default: case 1: { view = new View(context); @@ -3001,11 +3054,11 @@ public boolean supportsPredictiveItemAnimations() { }; layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); - horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true) { + horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true, resourcesProvider) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { HintDialogCell cell = (HintDialogCell) holder.itemView; - if (darkTheme) { + if (darkTheme || forceDarkThemeForHint) { cell.setColors(Theme.key_voipgroup_nameText, Theme.key_voipgroup_inviteMembersBackground); } @@ -3079,16 +3132,19 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { - ShareDialogCell cell = (ShareDialogCell) holder.itemView; + if (holder.getItemViewType() == 0 || holder.getItemViewType() == 5) { +// ShareDialogCell cell = (ShareDialogCell) holder.itemView; +// ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; CharSequence name = null; + TLObject object = null; + TLRPC.EncryptedChat ec = null; long id = 0; if (TextUtils.isEmpty(lastSearchText)) { if (recentDialogsStartRow >= 0 && position >= recentDialogsStartRow) { int p = position - recentDialogsStartRow; DialogsSearchAdapter.RecentSearchObject recentSearchObject = recentSearchObjects.get(p); - TLObject object = recentSearchObject.object; + object = recentSearchObject.object; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; id = user.id; @@ -3099,6 +3155,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { name = chat.title; } else if (object instanceof TLRPC.TL_encryptedChat) { TLRPC.TL_encryptedChat chat = (TLRPC.TL_encryptedChat) object; + ec = chat; TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(chat.user_id); if (user != null) { id = user.id; @@ -3114,9 +3171,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { name = spannableStringBuilder; } } - } - cell.setDialog((int) id, selectedDialogs.indexOfKey(id) >= 0, name); + if (holder.itemView instanceof ProfileSearchCell) { + ((ProfileSearchCell) holder.itemView).setData(object, ec, name, null, false, false); + ((ProfileSearchCell) holder.itemView).useSeparator = position < getItemCount() - 2; + } else if (holder.itemView instanceof ShareDialogCell) { + ((ShareDialogCell) holder.itemView).setDialog((int) id, selectedDialogs.indexOfKey(id) >= 0, name); + } return; } position--; @@ -3127,7 +3188,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { position -= searchResult.size(); ArrayList arrayList = searchAdapterHelper.getLocalServerSearch(); - TLObject object = arrayList.get(position); + object = arrayList.get(position); if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; id = user.id; @@ -3147,7 +3208,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } } } - cell.setDialog(id, selectedDialogs.indexOfKey(id) >= 0, name); + if (holder.itemView instanceof ProfileSearchCell) { + ((ProfileSearchCell) holder.itemView).setData(object, ec, name, null, false, false); + ((ProfileSearchCell) holder.itemView).useSeparator = position < getItemCount() - 2; + } else if (holder.itemView instanceof ShareDialogCell) { + ((ShareDialogCell) holder.itemView).setDialog((int) id, selectedDialogs.indexOfKey(id) >= 0, name); + } } else if (holder.getItemViewType() == 2) { ((RecyclerListView) holder.itemView).getAdapter().notifyDataSetChanged(); } @@ -3165,7 +3231,7 @@ public int getItemViewType(int position) { } else if (position == resentTitleCell) { return 3; } - return 0; + return TextUtils.isEmpty(lastSearchText) ? 0 : 5; } public boolean isSearching() { @@ -3176,6 +3242,10 @@ public int getSpanSize(int spanCount, int position) { if (position == hintsCell || position == resentTitleCell || position == firstEmptyViewCell || position == lastFilledItem) { return spanCount; } + final int viewType = getItemViewType(position); + if (viewType == 0) { + return spanCount; + } return 1; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index 93c2722b72..8a2a398c01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -1,5 +1,6 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.MediaDataController.MEDIA_PHOTOVIDEO; import android.animation.Animator; @@ -13,15 +14,18 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.os.Bundle; import android.text.Layout; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; @@ -78,6 +82,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; @@ -117,11 +122,14 @@ import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.DialogsActivity; import org.telegram.ui.PhotoViewer; +import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.UserListPoller; import org.telegram.ui.Stories.ViewsForPeerStoriesRequester; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.TopicsFragment; import java.util.ArrayList; import java.util.Collections; @@ -147,6 +155,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public static final int TAB_GROUPUSERS = 7; public static final int TAB_STORIES = 8; public static final int TAB_ARCHIVED_STORIES = 9; + public static final int TAB_RECOMMENDED_CHANNELS = 10; public static final int FILTER_PHOTOS_AND_VIDEOS = 0; public static final int FILTER_PHOTOS_ONLY = 1; @@ -371,7 +380,7 @@ public void drawListForBlur(Canvas blurCanvas) { if (mediaPages[i] != null && mediaPages[i].getVisibility() == View.VISIBLE) { for (int j = 0; j < mediaPages[i].listView.getChildCount(); j++) { View child = mediaPages[i].listView.getChildAt(j); - if (child.getY() < mediaPages[i].listView.blurTopPadding + AndroidUtilities.dp(100)) { + if (child.getY() < mediaPages[i].listView.blurTopPadding + dp(100)) { int restore = blurCanvas.save(); blurCanvas.translate(mediaPages[i].getX() + child.getX(), getY() + mediaPages[i].getY() + mediaPages[i].listView.getY() + child.getY()); child.draw(blurCanvas); @@ -424,11 +433,11 @@ protected void dispatchDraw(Canvas canvas) { boolean isVisible = false; RecyclerListView.FastScroll fastScroll = listView.getFastScroll(); if (fastScroll != null) { - float y = fastScroll.getScrollBarY() + AndroidUtilities.dp(36); + float y = fastScroll.getScrollBarY() + dp(36); if (selectedType == TAB_ARCHIVED_STORIES) { - y += AndroidUtilities.dp(64); + y += dp(64); } - float x = (getMeasuredWidth() - fastScrollHintView.getMeasuredWidth() - AndroidUtilities.dp(16)); + float x = (getMeasuredWidth() - fastScrollHintView.getMeasuredWidth() - dp(16)); fastScrollHintView.setPivotX(fastScrollHintView.getMeasuredWidth()); fastScrollHintView.setPivotY(0); fastScrollHintView.setTranslationX(x); @@ -501,6 +510,7 @@ public void updateFastScrollVisibility(MediaPage mediaPage, boolean animated) { private SharedDocumentsAdapter audioAdapter; private GifAdapter gifAdapter; private CommonGroupsAdapter commonGroupsAdapter; + private ChannelRecommendationsAdapter channelRecommendationsAdapter; private ChatUsersAdapter chatUsersAdapter; private StoriesAdapter storiesAdapter; private StoriesAdapter animationSupportingStoriesAdapter; @@ -528,7 +538,7 @@ public void updateFastScrollVisibility(MediaPage mediaPage, boolean animated) { private ArrayList cache = new ArrayList<>(10); private ArrayList audioCellCache = new ArrayList<>(10); private ArrayList audioCache = new ArrayList<>(10); - private ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip; + public ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip; private View shadowLine; private ChatActionCell floatingDateView; private AnimatorSet floatingDateAnimation; @@ -1027,7 +1037,7 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj object.clipTopAddition = 0; object.starOffset = sharedMediaData[0].startOffset; if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { - object.clipTopAddition += AndroidUtilities.dp(36); + object.clipTopAddition += dp(36); } if (PhotoViewer.isShowingImage(messageObject)) { @@ -1035,10 +1045,10 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj if (pinnedHeader != null) { int top = 0; if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { - top += fragmentContextView.getHeight() - AndroidUtilities.dp(2.5f); + top += fragmentContextView.getHeight() - dp(2.5f); } if (view instanceof SharedDocumentCell) { - top += AndroidUtilities.dp(8f); + top += dp(8f); } final int topOffset = top - object.viewY; if (topOffset > view.getHeight()) { @@ -1046,7 +1056,7 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj } else { int bottomOffset = object.viewY - listView.getHeight(); if (view instanceof SharedDocumentCell) { - bottomOffset -= AndroidUtilities.dp(8f); + bottomOffset -= dp(8f); } if (bottomOffset >= 0) { listView.scrollBy(0, bottomOffset + view.getHeight()); @@ -1258,7 +1268,7 @@ public boolean hasInternet() { return profileActivity.getConnectionsManager().getConnectionState() == ConnectionsManager.ConnectionStateConnected; } - public SharedMediaLayout(Context context, long did, SharedMediaPreloader preloader, int commonGroupsCount, ArrayList sortedUsers, TLRPC.ChatFull chatInfo, TLRPC.UserFull userInfo, boolean membersFirst, BaseFragment parent, Delegate delegate, int viewType, Theme.ResourcesProvider resourcesProvider) { + public SharedMediaLayout(Context context, long did, SharedMediaPreloader preloader, int commonGroupsCount, ArrayList sortedUsers, TLRPC.ChatFull chatInfo, TLRPC.UserFull userInfo, int initialTab, BaseFragment parent, Delegate delegate, int viewType, Theme.ResourcesProvider resourcesProvider) { super(context); this.viewType = viewType; this.resourcesProvider = resourcesProvider; @@ -1271,14 +1281,16 @@ public SharedMediaLayout(Context context, long did, SharedMediaPreloader preload int[] mediaCount = preloader.getLastMediaCount(); topicId = sharedMediaPreloader.topicId; hasMedia = new int[]{mediaCount[0], mediaCount[1], mediaCount[2], mediaCount[3], mediaCount[4], mediaCount[5], topicId == 0 ? commonGroupsCount : 0}; - if (userInfo != null && userInfo.stories_pinned_available || chatInfo != null && chatInfo.stories_pinned_available || isStoriesView()) { - initialTab = getInitialTab(); - } else if (membersFirst && topicId == 0) { - initialTab = TAB_GROUPUSERS; + if (initialTab == TAB_RECOMMENDED_CHANNELS) { + this.initialTab = initialTab; + } else if (userInfo != null && userInfo.stories_pinned_available || chatInfo != null && chatInfo.stories_pinned_available || isStoriesView()) { + this.initialTab = getInitialTab(); + } else if (initialTab != -1 && topicId == 0) { + this.initialTab = initialTab; } else { for (int a = 0; a < hasMedia.length; a++) { if (hasMedia[a] == -1 || hasMedia[a] > 0) { - initialTab = a; + this.initialTab = a; break; } } @@ -1314,6 +1326,7 @@ public SharedMediaLayout(Context context, long did, SharedMediaPreloader preload profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.messagePlayingDidStart); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); + profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); for (int a = 0; a < 10; a++) { //cellCache.add(new SharedPhotoVideoCell(context)); @@ -1428,14 +1441,14 @@ public void onLayout(int l, int t, int r, int b) { searchItem.setTranslationX(parent.getMeasuredWidth() - searchItem.getRight()); } }); - searchItem.setTranslationY(AndroidUtilities.dp(10)); + searchItem.setTranslationY(dp(10)); searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); searchItem.setVisibility(isStoriesView() ? View.GONE : View.INVISIBLE); photoVideoOptionsItem = new ImageView(context); photoVideoOptionsItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - photoVideoOptionsItem.setTranslationY(AndroidUtilities.dp(10)); + photoVideoOptionsItem.setTranslationY(dp(10)); photoVideoOptionsItem.setVisibility(View.INVISIBLE); Drawable calendarDrawable = ContextCompat.getDrawable(context, R.drawable.ic_ab_other).mutate(); @@ -1455,7 +1468,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (dividerView.getParent() != null) { dividerView.setVisibility(View.GONE); super.onMeasure(widthMeasureSpec, heightMeasureSpec); - dividerView.getLayoutParams().width = getMeasuredWidth() - AndroidUtilities.dp(16); + dividerView.getLayoutParams().width = getMeasuredWidth() - dp(16); dividerView.setVisibility(View.VISIBLE); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } else { @@ -1618,7 +1631,7 @@ public void onClick(View view) { } } - optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -AndroidUtilities.dp(56)); + optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -dp(56)); } }); @@ -1644,7 +1657,7 @@ public void onClick(View view) { backDrawable.setColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); closeButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 1)); closeButton.setContentDescription(LocaleController.getString("Close", R.string.Close)); - actionModeLayout.addView(closeButton, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(closeButton, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(closeButton); closeButton.setOnClickListener(v -> closeActionMode()); @@ -1672,11 +1685,19 @@ public void onClick(View view) { actionModeViews.add(forwardNoQuoteItem); forwardNoQuoteItem.setOnClickListener(v -> onActionBarItemClick(v, forward_noquote)); + gotoItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); + gotoItem.setIcon(R.drawable.msg_message); + gotoItem.setContentDescription(LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); + gotoItem.setDuplicateParentStateEnabled(false); + actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeViews.add(gotoItem); + gotoItem.setOnClickListener(v -> onActionBarItemClick(v, gotochat)); + forwardItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); forwardItem.setIcon(R.drawable.msg_forward); forwardItem.setContentDescription(LocaleController.getString("Forward", R.string.Forward)); forwardItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(forwardItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(forwardItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(forwardItem); forwardItem.setOnClickListener(v -> onActionBarItemClick(v, forward)); @@ -1686,7 +1707,7 @@ public void onClick(View view) { deleteItem.setIcon(R.drawable.msg_delete); deleteItem.setContentDescription(LocaleController.getString("Delete", R.string.Delete)); deleteItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(deleteItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(deleteItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(deleteItem); deleteItem.setOnClickListener(v -> onActionBarItemClick(v, delete)); @@ -1710,10 +1731,11 @@ public void notifyDataSetChanged() { linksSearchAdapter = new MediaSearchAdapter(context, 3); groupUsersSearchAdapter = new GroupUsersSearchAdapter(context); commonGroupsAdapter = new CommonGroupsAdapter(context); + channelRecommendationsAdapter = new ChannelRecommendationsAdapter(context); chatUsersAdapter = new ChatUsersAdapter(context); if (topicId == 0) { chatUsersAdapter.sortedUsers = sortedUsers; - chatUsersAdapter.chatInfo = membersFirst ? chatInfo : null; + chatUsersAdapter.chatInfo = initialTab == TAB_GROUPUSERS ? chatInfo : null; } storiesAdapter = new StoriesAdapter(context, false) { @Override @@ -1814,7 +1836,7 @@ protected void calculateExtraLayoutSpace(RecyclerView.State state, int[] extraLa if (mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_STORIES || mediaPage.selectedType == TAB_ARCHIVED_STORIES) { extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], SharedPhotoVideoCell.getItemSize(1) * 2); } else if (mediaPage.selectedType == TAB_FILES) { - extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], AndroidUtilities.dp(56f) * 2); + extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], dp(56f) * 2); } } @@ -1915,6 +1937,25 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { UserListPoller poller; + float lastY, startY; + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (profileActivity != null && profileActivity.isInPreviewMode()) { + lastY = event.getY(); + if (event.getAction() == MotionEvent.ACTION_UP) { + profileActivity.finishPreviewFragment(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + float dy = startY - lastY; + profileActivity.movePreviewFragment(dy); + if (dy < 0) { + startY = lastY; + } + } + return true; + } + return super.dispatchTouchEvent(event); + } + @Override protected void dispatchDraw(Canvas canvas) { if (getAdapter() == archivedStoriesAdapter && getChildCount() > 0) { @@ -1929,10 +1970,10 @@ protected void dispatchDraw(Canvas canvas) { } if (archivedHintPaint == null) { archivedHintPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - archivedHintPaint.setTextSize(AndroidUtilities.dp(14)); + archivedHintPaint.setTextSize(dp(14)); archivedHintPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); } - int width = getMeasuredWidth() - AndroidUtilities.dp(60); + int width = getMeasuredWidth() - dp(60); if (archivedHintLayout == null || archivedHintLayout.getWidth() != width) { archivedHintLayout = new StaticLayout(LocaleController.getString(isArchivedOnlyStoriesView() ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); archivedHintLayoutWidth = 0; @@ -1946,7 +1987,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.save(); canvas.translate( (getWidth() - archivedHintLayoutWidth) / 2f - archivedHintLayoutLeft, - top - (AndroidUtilities.dp(64) + archivedHintLayout.getHeight()) / 2f + top - (dp(64) + archivedHintLayout.getHeight()) / 2f ); archivedHintLayout.draw(canvas); canvas.restore(); @@ -2274,8 +2315,8 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { mediaPages[a].listView.setFastScrollEnabled(RecyclerListView.FastScroll.DATE_TYPE); mediaPages[a].listView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING); - mediaPages[a].listView.setPinnedSectionOffsetY(-AndroidUtilities.dp(2)); - mediaPages[a].listView.setPadding(0, AndroidUtilities.dp(2), 0, 0); + mediaPages[a].listView.setPinnedSectionOffsetY(-dp(2)); + mediaPages[a].listView.setPadding(0, dp(2), 0, 0); mediaPages[a].listView.setItemAnimator(null); mediaPages[a].listView.setClipToPadding(false); mediaPages[a].listView.setSectionsType(RecyclerListView.SECTIONS_TYPE_DATE); @@ -2329,11 +2370,11 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie outRect.left = 0; outRect.bottom = 0; if (!mediaPage.layoutManager.isFirstRow(position)) { - outRect.top = AndroidUtilities.dp(2); + outRect.top = dp(2); } else { outRect.top = 0; } - outRect.right = mediaPage.layoutManager.isLastInRow(position) ? 0 : AndroidUtilities.dp(2); + outRect.right = mediaPage.layoutManager.isLastInRow(position) ? 0 : dp(2); } else if (view instanceof SharedPhotoVideoCell2) { SharedPhotoVideoCell2 cell = (SharedPhotoVideoCell2) view; final int position = mediaPage.listView.getChildAdapterPosition(cell), spanCount = mediaPage.layoutManager.getSpanCount(); @@ -2393,7 +2434,11 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (!profileActivity.getMessagesController().checkCanOpenChat(args, profileActivity)) { return; } - profileActivity.presentFragment(new ChatActivity(args)); + if (chat.forum) { + profileActivity.presentFragment(TopicsFragment.getTopicsOrChat(profileActivity, args)); + } else { + profileActivity.presentFragment(new ChatActivity(args)); + } } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { onItemClick(position, view, ((SharedDocumentCell) view).getMessage(), 0, mediaPage.selectedType); } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { @@ -2418,6 +2463,12 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (messageObject != null) { onItemClick(position, view, messageObject, 0, mediaPage.selectedType); } + } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { + if (view instanceof ProfileSearchCell && position >= 0 && position < channelRecommendationsAdapter.chats.size()) { + Bundle args = new Bundle(); + args.putLong("chat_id", channelRecommendationsAdapter.chats.get(position).id); + profileActivity.presentFragment(new ChatActivity(args)); + } } }); mediaPages[a].listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -2442,51 +2493,77 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { invalidateBlur(); } }); - mediaPages[a].listView.setOnItemLongClickListener((view, position) -> { - if (photoVideoChangeColumnsAnimation) { - return false; - } - if (isActionModeShowed) { - mediaPage.listView.clickItem(view, position); - return true; - } - if (mediaPage.selectedType == TAB_GROUPUSERS && view instanceof UserCell) { - final TLRPC.ChatParticipant participant; - int index = position; - if (!chatUsersAdapter.sortedUsers.isEmpty()) { - if (position >= chatUsersAdapter.sortedUsers.size()) { - return false; - } - index = chatUsersAdapter.sortedUsers.get(position); - } - if (index < 0 || index >= chatUsersAdapter.chatInfo.participants.participants.size()) { + mediaPages[a].listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListenerExtended() { + @Override + public boolean onItemClick(View view, int position, float x, float y) { + if (photoVideoChangeColumnsAnimation) { return false; } - participant = chatUsersAdapter.chatInfo.participants.participants.get(index); - RecyclerListView listView = (RecyclerListView) view.getParent(); - for (int i = 0; i < listView.getChildCount(); ++i) { - View child = listView.getChildAt(i); - if (listView.getChildAdapterPosition(child) == position) { - view = child; - break; + if (isActionModeShowed) { + mediaPage.listView.clickItem(view, position); + return true; + } + if (mediaPage.selectedType == TAB_GROUPUSERS && view instanceof UserCell) { + final TLRPC.ChatParticipant participant; + int index = position; + if (!chatUsersAdapter.sortedUsers.isEmpty()) { + if (position >= chatUsersAdapter.sortedUsers.size()) { + return false; + } + index = chatUsersAdapter.sortedUsers.get(position); + } + if (index < 0 || index >= chatUsersAdapter.chatInfo.participants.participants.size()) { + return false; + } + participant = chatUsersAdapter.chatInfo.participants.participants.get(index); + RecyclerListView listView = (RecyclerListView) view.getParent(); + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == position) { + view = child; + break; + } + } + return onMemberClick(participant, true, view); + } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { + return onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); + } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { + return onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); + } else if ((mediaPage.selectedType == TAB_VOICE || mediaPage.selectedType == TAB_AUDIO) && view instanceof SharedAudioCell) { + return onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); + } else if (mediaPage.selectedType == TAB_GIF && view instanceof ContextLinkCell) { + return onItemLongClick((MessageObject) ((ContextLinkCell) view).getParentObject(), view, 0); + } else if ((mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_ARCHIVED_STORIES || mediaPage.selectedType == TAB_STORIES && isStoriesView()) && view instanceof SharedPhotoVideoCell2) { + MessageObject messageObject = ((SharedPhotoVideoCell2) view).getMessageObject(); + if (messageObject != null) { + return onItemLongClick(messageObject, view, mediaPage.selectedType); + } + } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { + Bundle args = new Bundle(); + args.putLong("chat_id", channelRecommendationsAdapter.chats.get(position).id); + final BaseFragment fragment = new ChatActivity(args); + if (profileActivity instanceof ProfileActivity) { + ((ProfileActivity) profileActivity).prepareBlurBitmap(); } + profileActivity.presentFragmentAsPreview(fragment); + return true; } - return onMemberClick(participant, true, view); - } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { - return onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); - } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { - return onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); - } else if ((mediaPage.selectedType == TAB_VOICE || mediaPage.selectedType == TAB_AUDIO) && view instanceof SharedAudioCell) { - return onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); - } else if (mediaPage.selectedType == TAB_GIF && view instanceof ContextLinkCell) { - return onItemLongClick((MessageObject) ((ContextLinkCell) view).getParentObject(), view, 0); - } else if ((mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_ARCHIVED_STORIES || mediaPage.selectedType == TAB_STORIES && isStoriesView()) && view instanceof SharedPhotoVideoCell2) { - MessageObject messageObject = ((SharedPhotoVideoCell2) view).getMessageObject(); - if (messageObject != null) { - return onItemLongClick(messageObject, view, mediaPage.selectedType); + return false; + } + + @Override + public void onMove(float dx, float dy) { + if (profileActivity != null && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + profileActivity.movePreviewFragment(dy); + } + } + + @Override + public void onLongClickRelease() { + if (profileActivity != null && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + profileActivity.finishPreviewFragment(); } } - return false; }); if (a == 0 && scrollToPositionOnRecreate != -1) { layoutManager.scrollToPositionWithOffset(scrollToPositionOnRecreate, scrollToOffsetOnRecreate); @@ -2567,7 +2644,7 @@ protected void onDraw(Canvas canvas) { floatingDateView.setCustomDate((int) (System.currentTimeMillis() / 1000), false, false); floatingDateView.setAlpha(0.0f); floatingDateView.setOverrideColor(Theme.key_chat_mediaTimeBackground, Theme.key_chat_mediaTimeText); - floatingDateView.setTranslationY(-AndroidUtilities.dp(48)); + floatingDateView.setTranslationY(-dp(48)); addView(floatingDateView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 48 + 4, 0, 0)); if (!isStoriesView()) { @@ -2585,7 +2662,7 @@ protected void onDraw(Canvas canvas) { shadowLine = new View(context); shadowLine.setBackgroundColor(getThemedColor(Theme.key_divider)); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1); - layoutParams.topMargin = isStoriesView() ? 0 : AndroidUtilities.dp(48) - 1; + layoutParams.topMargin = isStoriesView() ? 0 : dp(48) - 1; addView(shadowLine, layoutParams); updateTabs(false); @@ -2851,7 +2928,7 @@ private void startPinchToMediaColumnsCount(boolean pinchScaleUp) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - changeColumnsTab == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(2 + 64) : AndroidUtilities.dp(2), + changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(2 + 64) : dp(2), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); @@ -3052,7 +3129,7 @@ private void animateToMediaColumnsCount(int newColumnsCount) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - AndroidUtilities.dp(2) + (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(64) : 0)), + dp(2) + (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : 0)), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); @@ -3136,8 +3213,17 @@ protected void dispatchDraw(Canvas canvas) { } } + protected int processColor(int color) { + return color; + } + private ScrollSlidingTextTabStripInner createScrollingTextTabStrip(Context context) { - ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip = new ScrollSlidingTextTabStripInner(context, resourcesProvider); + ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip = new ScrollSlidingTextTabStripInner(context, resourcesProvider) { + @Override + protected int processColor(int color) { + return SharedMediaLayout.this.processColor(color); + } + }; if (initialTab != -1) { scrollSlidingTextTabStrip.setInitialTabId(initialTab); initialTab = -1; @@ -3256,7 +3342,7 @@ private void hideFloatingDateView(boolean animated) { floatingDateAnimation.setDuration(180); floatingDateAnimation.playTogether( ObjectAnimator.ofFloat(floatingDateView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(floatingDateView, View.TRANSLATION_Y, -AndroidUtilities.dp(48) + additionalFloatingTranslation)); + ObjectAnimator.ofFloat(floatingDateView, View.TRANSLATION_Y, -dp(48) + additionalFloatingTranslation)); floatingDateAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); floatingDateAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -3279,17 +3365,17 @@ private void scrollToTop() { case 1: case 2: case 4: - height = AndroidUtilities.dp(56); + height = dp(56); break; case 3: - height = AndroidUtilities.dp(100); + height = dp(100); break; case 5: - height = AndroidUtilities.dp(60); + height = dp(60); break; case 6: default: - height = AndroidUtilities.dp(58); + height = dp(58); break; } int scrollDistance; @@ -3358,13 +3444,13 @@ private void checkLoadMoreScroll(MediaPage mediaPage, RecyclerListView recyclerV if (archivedStoriesAdapter.storiesList != null && firstVisibleItem + visibleItemCount > archivedStoriesAdapter.storiesList.getLoadedCount() - mediaColumnsCount[1]) { archivedStoriesAdapter.load(false); } - } else if (mediaPage.selectedType == 6) { + } else if (mediaPage.selectedType == TAB_COMMON_GROUPS) { if (visibleItemCount > 0) { if (!commonGroupsAdapter.endReached && !commonGroupsAdapter.loading && !commonGroupsAdapter.chats.isEmpty() && firstVisibleItem + visibleItemCount >= totalItemCount - 5) { commonGroupsAdapter.getChats(commonGroupsAdapter.chats.get(commonGroupsAdapter.chats.size() - 1).id, 100); } } - } else { + } else if (mediaPage.selectedType != TAB_RECOMMENDED_CHANNELS) { final int threshold; if (mediaPage.selectedType == 0) { threshold = 3; @@ -3525,6 +3611,7 @@ public void onDestroy() { profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.messagePlayingDidStart); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); + profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); if (storiesAdapter != null && storiesAdapter.storiesList != null) { storiesAdapter.destroy(); @@ -3878,10 +3965,10 @@ public void setPadding(int left, int top, int right, int bottom) { mediaPages[a].setTranslationY(topPadding - lastMeasuredTopPadding); } if (fragmentContextView != null) { - fragmentContextView.setTranslationY(AndroidUtilities.dp(48) + top); + fragmentContextView.setTranslationY(dp(48) + top); } additionalFloatingTranslation = top; - floatingDateView.setTranslationY((floatingDateView.getTag() == null ? -AndroidUtilities.dp(48) : 0) + additionalFloatingTranslation); + floatingDateView.setTranslationY((floatingDateView.getTag() == null ? -dp(48) : 0) + additionalFloatingTranslation); } @Override @@ -3967,7 +4054,7 @@ public boolean onTouchEvent(MotionEvent ev) { fwdRestrictedHint.hide(); } } - if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking && ev.getY() >= AndroidUtilities.dp(48)) { + if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking && ev.getY() >= dp(48)) { startedTrackingPointerId = ev.getPointerId(0); maybeStartTracking = true; startedTrackingX = (int) ev.getX(); @@ -4186,7 +4273,7 @@ public boolean closeActionMode(boolean uncheckAnimated) { } public void setVisibleHeight(int height) { - height = Math.max(height, AndroidUtilities.dp(120)); + height = Math.max(height, dp(120)); for (int a = 0; a < mediaPages.length; a++) { float t = -(getMeasuredHeight() - height) / 2f; mediaPages[a].emptyView.setTranslationY(t); @@ -4599,6 +4686,12 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + } else if (id == NotificationCenter.channelRecommendationsLoaded) { + long chatId = (long) args[0]; + if (chatId == -dialog_id) { + channelRecommendationsAdapter.update(); + updateTabs(true); + } } } @@ -4891,6 +4984,7 @@ private void updateTabs(boolean animated) { if (!delegate.isFragmentOpened()) { animated = false; } + boolean hasRecommendations = false; int changed = 0; if (((DialogObject.isUserDialog(dialog_id) || DialogObject.isChatDialog(dialog_id)) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || info != null && info.stories_pinned_available || isStoriesView()) && includeStories()) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { changed++; @@ -4926,6 +5020,10 @@ private void updateTabs(boolean animated) { if ((hasMedia[6] <= 0) == scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { changed++; } + hasRecommendations = DialogObject.isChatDialog(dialog_id) && MessagesController.ChannelRecommendations.hasRecommendations(profileActivity.getCurrentAccount(), -dialog_id); + if (hasRecommendations != scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { + changed++; + } } if (changed > 0) { if (animated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -4986,8 +5084,8 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta } if (!isStoriesView()) { if (chatUsersAdapter.chatInfo != null) { - if (!scrollSlidingTextTabStrip.hasTab(7)) { - scrollSlidingTextTabStrip.addTextTab(7, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_GROUPUSERS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_GROUPUSERS, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); } } if (hasMedia[0] > 0) { @@ -5028,43 +5126,55 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta scrollSlidingTextTabStrip.addTextTab(0, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView, longClickListener); } } + if (!scrollSlidingTextTabStrip.hasTab(TAB_PHOTOVIDEO)) { + if (hasMedia[1] == 0 && hasMedia[2] == 0 && hasMedia[3] == 0 && hasMedia[4] == 0 && hasMedia[5] == 0 && hasMedia[6] == 0 && chatUsersAdapter.chatInfo == null) { + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); + } else { + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView); + } + } } if (hasMedia[1] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(1)) { - scrollSlidingTextTabStrip.addTextTab(1, LocaleController.getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_FILES)) { + scrollSlidingTextTabStrip.addTextTab(TAB_FILES, LocaleController.getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); } } if (!DialogObject.isEncryptedDialog(dialog_id)) { if (hasMedia[3] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(3)) { - scrollSlidingTextTabStrip.addTextTab(3, LocaleController.getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_LINKS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_LINKS, LocaleController.getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); } } if (hasMedia[4] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(4)) { - scrollSlidingTextTabStrip.addTextTab(4, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } else { if (hasMedia[4] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(4)) { - scrollSlidingTextTabStrip.addTextTab(4, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } if (hasMedia[2] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(2)) { - scrollSlidingTextTabStrip.addTextTab(2, LocaleController.getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_VOICE)) { + scrollSlidingTextTabStrip.addTextTab(TAB_VOICE, LocaleController.getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); } } if (hasMedia[5] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(5)) { - scrollSlidingTextTabStrip.addTextTab(5, LocaleController.getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_GIF)) { + scrollSlidingTextTabStrip.addTextTab(TAB_GIF, LocaleController.getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); } } if (hasMedia[6] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(6)) { - scrollSlidingTextTabStrip.addTextTab(6, LocaleController.getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_COMMON_GROUPS, LocaleController.getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); + } + } + if (hasRecommendations) { + if (!scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_RECOMMENDED_CHANNELS, LocaleController.getString(R.string.SimilarChannelsTab), idToView); } } } @@ -5184,7 +5294,7 @@ private void switchToCurrentSelectedMode(boolean animated) { mediaPages[a].listView.setPinnedHeaderShadowDrawable(null); mediaPages[a].listView.setPadding( mediaPages[a].listView.getPaddingLeft(), - AndroidUtilities.dp(2) + (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(64) : 0), + dp(2) + (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? dp(64) : 0), mediaPages[a].listView.getPaddingRight(), mediaPages[a].listView.getPaddingBottom() ); @@ -5194,7 +5304,7 @@ private void switchToCurrentSelectedMode(boolean animated) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(photoVideoAdapter); } - layoutParams.leftMargin = layoutParams.rightMargin = -AndroidUtilities.dp(1); + layoutParams.leftMargin = layoutParams.rightMargin = -dp(1); if (sharedMediaData[0].fastScrollDataLoaded && !sharedMediaData[0].fastScrollPeriods.isEmpty()) { fastScrollVisible = true; } @@ -5260,8 +5370,13 @@ private void switchToCurrentSelectedMode(boolean animated) { mediaPages[a].listView.setAdapter(archivedStoriesAdapter); } spanCount = mediaColumnsCount[1]; + } else if (mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { + if (currentAdapter != channelRecommendationsAdapter) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(channelRecommendationsAdapter); + } } - if (mediaPages[a].selectedType == TAB_PHOTOVIDEO || mediaPages[a].selectedType == TAB_STORIES || mediaPages[a].selectedType == TAB_ARCHIVED_STORIES || mediaPages[a].selectedType == TAB_VOICE || mediaPages[a].selectedType == TAB_GIF || mediaPages[a].selectedType == TAB_COMMON_GROUPS || mediaPages[a].selectedType == TAB_GROUPUSERS && !delegate.canSearchMembers()) { + if (mediaPages[a].selectedType == TAB_PHOTOVIDEO || mediaPages[a].selectedType == TAB_STORIES || mediaPages[a].selectedType == TAB_ARCHIVED_STORIES || mediaPages[a].selectedType == TAB_VOICE || mediaPages[a].selectedType == TAB_GIF || mediaPages[a].selectedType == TAB_COMMON_GROUPS || mediaPages[a].selectedType == TAB_GROUPUSERS && !delegate.canSearchMembers() || mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { if (animated) { searchItemState = 2; } else { @@ -5308,7 +5423,7 @@ private void switchToCurrentSelectedMode(boolean animated) { archivedStoriesAdapter.load(false); mediaPages[a].emptyView.showProgress(storiesList != null && (storiesList.isLoading() || hasInternet() && storiesList.getCount() > 0), animated); fastScrollVisible = storiesList != null && storiesList.getCount() > 0; - } else { + } else if (mediaPages[a].selectedType != TAB_RECOMMENDED_CHANNELS) { if (!sharedMediaData[mediaPages[a].selectedType].loading && !sharedMediaData[mediaPages[a].selectedType].endReached[0] && sharedMediaData[mediaPages[a].selectedType].messages.isEmpty()) { sharedMediaData[mediaPages[a].selectedType].loading = true; documentsAdapter.notifyDataSetChanged(); @@ -6036,7 +6151,7 @@ public EmptyStubView(Context context, Theme.ResourcesProvider resourcesProvider) emptyTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); emptyTextView.setGravity(Gravity.CENTER); emptyTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); addView(emptyTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 24, 0, 0)); } @@ -6046,12 +6161,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int rotation = manager.getDefaultDisplay().getRotation(); ignoreRequestLayout = true; if (AndroidUtilities.isTablet()) { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); } else { if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), 0); + emptyTextView.setPadding(dp(40), 0, dp(40), 0); } else { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); } } ignoreRequestLayout = false; @@ -6779,6 +6894,165 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { } } + private class ChannelRecommendationsAdapter extends RecyclerListView.SelectionAdapter { + + private final Context mContext; + private final ArrayList chats = new ArrayList<>(); + private int more; + + public ChannelRecommendationsAdapter(Context context) { + mContext = context; + update(); + } + + public void update() { + if (profileActivity == null || !DialogObject.isChatDialog(dialog_id)) { + return; + } + TLRPC.Chat chat = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChat(-dialog_id); + if (chat == null || !ChatObject.isChannelAndNotMegaGroup(chat)) { + return; + } + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChannelRecommendations(chat.id); + chats.clear(); + if (rec != null) { + chats.addAll(rec.chats); + more = UserConfig.getInstance(profileActivity.getCurrentAccount()).isPremium() ? 0 : rec.more; + } else { + more = 0; + } + notifyDataSetChanged(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == 0; + } + + @Override + public int getItemCount() { + return chats.size(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + if (viewType == 1) { + MoreRecommendationsCell cell = new MoreRecommendationsCell(profileActivity == null ? UserConfig.selectedAccount : profileActivity.getCurrentAccount(), mContext, resourcesProvider, () -> { + if (profileActivity != null) { + profileActivity.presentFragment(new PremiumPreviewFragment("similar_channels")); + } + }); + cell.setOnClickListener(v -> { + if (chats.size() <= 0) return; + Bundle args = new Bundle(); + args.putLong("chat_id", chats.get(chats.size() - 1).id); + profileActivity.presentFragment(new ChatActivity(args)); + }); + view = cell; + } else { // 0 + view = new ProfileSearchCell(mContext, resourcesProvider); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ProfileSearchCell cell = null; + if (holder.getItemViewType() == 0) { + cell = (ProfileSearchCell) holder.itemView; + } else if (holder.getItemViewType() == 1) { + cell = ((MoreRecommendationsCell) holder.itemView).channelCell; + } + if (cell != null) { + TLRPC.Chat chat = chats.get(position); + cell.setData(chat, null, null, null, false, false); + cell.useSeparator = position != chats.size() - 1; + } + } + + @Override + public int getItemViewType(int position) { + if (more > 0 && position == getItemCount() - 1) { + return 1; + } + return 0; + } + } + + private static class MoreRecommendationsCell extends FrameLayout { + + private final int currentAccount; + private final Theme.ResourcesProvider resourcesProvider; + + public final ProfileSearchCell channelCell; + + private final View gradientView; + private final ButtonWithCounterView button; + private final LinkSpanDrawable.LinksTextView textView; + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + channelCell.setOnClickListener(l); + } + + public MoreRecommendationsCell(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, Runnable onPremiumClick) { + super(context); + + this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + + channelCell = new ProfileSearchCell(context, resourcesProvider); + channelCell.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_ALL)); + addView(channelCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + gradientView = new View(context); + gradientView.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[] { + Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), .4f), + Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider) + })); + addView(gradientView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 60)); + + button = new ButtonWithCounterView(context, resourcesProvider); + SpannableStringBuilder buttonText = new SpannableStringBuilder(); + buttonText.append(LocaleController.getString(R.string.MoreSimilarButton)); + buttonText.append(" "); + SpannableString lock = new SpannableString("l"); + lock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + buttonText.append(lock); + button.setText(buttonText, false); + addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 14, 38, 14, 0)); + button.setOnClickListener(v -> { + if (onPremiumClick != null) { + onPremiumClick.run(); + } + }); + + textView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + textView.setGravity(Gravity.CENTER); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider)); + textView.setLineSpacing(dp(3), 1f); + SpannableStringBuilder text = AndroidUtilities.premiumText(LocaleController.getString(R.string.MoreSimilarText), () -> { + if (onPremiumClick != null) { + onPremiumClick.run(); + } + }); + SpannableString count = new SpannableString("" + MessagesController.getInstance(currentAccount).recommendedChannelsLimitPremium); + count.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, count.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(AndroidUtilities.replaceCharSequence("%s", text, count)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 24, 96, 24, 12)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(145), MeasureSpec.EXACTLY)); + } + } + private class CommonGroupsAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; @@ -7716,7 +7990,7 @@ public boolean canZoomOut() { protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == fragmentContextView) { canvas.save(); - canvas.clipRect(0, mediaPages[0].getTop(), child.getMeasuredWidth(),mediaPages[0].getTop() + child.getMeasuredHeight() + AndroidUtilities.dp(12)); + canvas.clipRect(0, mediaPages[0].getTop(), child.getMeasuredWidth(),mediaPages[0].getTop() + child.getMeasuredHeight() + dp(12)); boolean b = super.drawChild(canvas, child, drawingTime); canvas.restore(); return b; @@ -7724,7 +7998,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return super.drawChild(canvas, child, drawingTime); } - private class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { + public class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { protected Paint backgroundPaint; public int backgroundColor = Color.TRANSPARENT; @@ -7798,7 +8072,7 @@ public InternalListView(Context context) { @Override public void updateClip(int[] clip) { - clip[0] = getPaddingTop() - AndroidUtilities.dp(2) - hintPaddingTop; + clip[0] = getPaddingTop() - dp(2) - hintPaddingTop; clip[1] = getMeasuredHeight() - getPaddingBottom(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java index 8cfe7ac356..610559b139 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java @@ -479,6 +479,8 @@ public int getBackgroundTranslationY() { return emojiHeight; } return backgroundTranslationY; + } else if (backgroundDrawable instanceof ChatBackgroundDrawable) { + return backgroundTranslationY; } return 0; } @@ -498,6 +500,8 @@ public int getBackgroundSizeY() { } else { offset = backgroundTranslationY != 0 ? 0 : -keyboardHeight; } + } else if (backgroundDrawable instanceof ChatBackgroundDrawable) { + offset = backgroundTranslationY; } return getMeasuredHeight() - offset; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java index 7de5f6732c..a49fb323f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java @@ -99,19 +99,15 @@ public static StaticLayout createStaticLayout2(CharSequence source, TextPaint pa .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE); return builder.build(); } else { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); + return createStaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); } } public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines) { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); + return createStaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); } - public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, canContainUrl); - } - - public static StaticLayout createStaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerWidth, Layout.Alignment align, float spacingMult, float spacingAdd, boolean includePad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { + public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int outerWidth, Layout.Alignment align, float spacingMult, float spacingAdd, boolean includePad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { /*if (Build.VERSION.SDK_INT >= 14) { init(); try { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java index ed36642213..caf86c1ed6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java @@ -447,7 +447,7 @@ public void draw(Canvas canvas) { // } } - private RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); + private final RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); private void drawSelectedHighlight(Canvas canvas) { float alpha = selectedAlpha.set(selectedCategoryIndex >= 0 ? 1 : 0); float index = selectedCategoryIndex >= 0 ? selectedIndex.set(selectedCategoryIndex) : selectedIndex.get(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index 8cf61eb16c..90a45305ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -1162,7 +1162,7 @@ public void onClick(View widget) { pickerBottomLayout.setBackground(null); setButton(null, null, -1); - premiumButtonView.setButton(LocaleController.getString("UnlockPremiumEmoji", R.string.UnlockPremiumEmoji), e -> { + premiumButtonView.setButton(LocaleController.getString(R.string.UnlockPremiumEmoji), e -> { if (parentFragment != null) { new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); } else if (getContext() instanceof LaunchActivity) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java index b38484d471..dcd66375e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java @@ -191,8 +191,8 @@ public int getOpacity() { }; } ColorStateList colorStateList = new ColorStateList( - new int[][]{StateSet.WILD_CARD}, - new int[]{0} + new int[][]{StateSet.WILD_CARD}, + new int[]{0} ); rippleDrawable = new RippleDrawable(colorStateList, null, maskDrawable); if (Build.VERSION.SDK_INT >= 23) { @@ -201,13 +201,11 @@ public int getOpacity() { rippleDrawable.setCallback(this); } if (isChecked && colorSet != 2 || !isChecked && colorSet != 1) { - int color = isChecked ? Theme.getColor(Theme.key_switchTrackBlueSelectorChecked, resourcesProvider) : Theme.getColor(Theme.key_switchTrackBlueSelector, resourcesProvider); - /*if (Build.VERSION.SDK_INT < 28) { - color = Color.argb(Color.alpha(color) * 2, Color.red(color), Color.green(color), Color.blue(color)); - }*/ + int color = Theme.getColor(isChecked ? Theme.key_switchTrackBlueSelectorChecked : Theme.key_switchTrackBlueSelector, resourcesProvider); + color = processColor(color); ColorStateList colorStateList = new ColorStateList( - new int[][]{StateSet.WILD_CARD}, - new int[]{color} + new int[][]{StateSet.WILD_CARD}, + new int[]{color} ); rippleDrawable.setColor(colorStateList); colorSet = isChecked ? 2 : 1; @@ -224,6 +222,10 @@ protected boolean verifyDrawable(Drawable who) { return super.verifyDrawable(who) || rippleDrawable != null && who == rippleDrawable; } + protected int processColor(int color) { + return color; + } + public void setColors(int track, int trackChecked, int thumb, int thumbChecked) { trackColorKey = track; trackCheckedColorKey = trackChecked; @@ -416,8 +418,8 @@ protected void onDraw(Canvas canvas) { colorProgress = progress; } - color1 = Theme.getColor(trackColorKey, resourcesProvider); - color2 = Theme.getColor(trackCheckedColorKey, resourcesProvider); + color1 = processColor(Theme.getColor(trackColorKey, resourcesProvider)); + color2 = processColor(Theme.getColor(trackCheckedColorKey, resourcesProvider)); if (a == 0 && iconDrawable != null && lastIconColor != (isChecked ? color2 : color1)) { iconDrawable.setColorFilter(new PorterDuffColorFilter(lastIconColor = (isChecked ? color2 : color1), PorterDuff.Mode.SRC_IN)); } @@ -471,8 +473,8 @@ protected void onDraw(Canvas canvas) { colorProgress = progress; } - color1 = Theme.getColor(thumbColorKey, resourcesProvider); - color2 = Theme.getColor(thumbCheckedColorKey, resourcesProvider); + color1 = processColor(Theme.getColor(thumbColorKey, resourcesProvider)); + color2 = processColor(Theme.getColor(thumbCheckedColorKey, resourcesProvider)); r1 = Color.red(color1); r2 = Color.red(color2); g1 = Color.green(color1); 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 9161dba4fc..819cabdfc0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java @@ -14,6 +14,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import androidx.annotation.NonNull; @@ -26,22 +27,34 @@ public class Text { private StaticLayout layout; private float width, left; - public Text(CharSequence text, int textSizeDp) { + public Text(CharSequence text, float textSizeDp) { this(text, textSizeDp, null); } - public Text(CharSequence text, int textSizeDp, Typeface typeface) { + public Text(CharSequence text, float textSizeDp, Typeface typeface) { paint.setTextSize(dp(textSizeDp)); paint.setTypeface(typeface); setText(text); } public void setText(CharSequence text) { - layout = new StaticLayout(text, paint, 99999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + layout = new StaticLayout(AndroidUtilities.replaceNewLines(text), paint, 99999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); width = layout.getLineCount() > 0 ? layout.getLineWidth(0) : 0; left = layout.getLineCount() > 0 ? layout.getLineLeft(0) : 0; } + private boolean hackClipBounds; + public Text hackClipBounds() { + this.hackClipBounds = true; + return this; + } + + private boolean doNotSave; + public Text doNotSave() { + this.doNotSave = true; + return this; + } + public float getTextSize() { return paint.getTextSize(); } @@ -72,23 +85,33 @@ public void draw(Canvas canvas, float x, float cy, int color, float alpha) { return; } paint.setColor(color); + final int wasAlpha = paint.getAlpha(); if (alpha != 1f) { - paint.setAlpha((int) (paint.getAlpha() * alpha)); + paint.setAlpha((int) (wasAlpha * alpha)); + } + if (!doNotSave) { + canvas.save(); } - canvas.save(); canvas.translate(x - left, cy - layout.getHeight() / 2f); draw(canvas); - canvas.restore(); + if (!doNotSave) { + canvas.restore(); + } + paint.setAlpha(wasAlpha); } public void draw(Canvas canvas, float x, float cy) { if (layout == null) { return; } - canvas.save(); + if (!doNotSave) { + canvas.save(); + } canvas.translate(x - left, cy - layout.getHeight() / 2f); draw(canvas); - canvas.restore(); + if (!doNotSave) { + canvas.restore(); + } } private LinearGradient ellipsizeGradient; @@ -99,11 +122,15 @@ public void draw(Canvas canvas) { if (layout == null) { return; } - if (ellipsizeWidth >= 0 && width > ellipsizeWidth) { + if (!doNotSave && ellipsizeWidth >= 0 && width > ellipsizeWidth) { canvas.saveLayerAlpha(0, 0, ellipsizeWidth, layout.getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); } - layout.draw(canvas); - if (ellipsizeWidth >= 0 && width > ellipsizeWidth) { + if (hackClipBounds) { + canvas.drawText(layout.getText().toString(), 0, -paint.getFontMetricsInt().ascent, paint); + } else { + layout.draw(canvas); + } + if (!doNotSave && ellipsizeWidth >= 0 && width > ellipsizeWidth) { if (ellipsizeGradient == null) { ellipsizeGradient = new LinearGradient(0, 0, dp(8), 0, new int[] { 0x00ffffff, 0xffffffff }, new float[] {0, 1}, Shader.TileMode.CLAMP); ellipsizeMatrix = new Matrix(); @@ -121,6 +148,10 @@ public void draw(Canvas canvas) { } } + public Paint.FontMetricsInt getFontMetricsInt() { + return paint.getFontMetricsInt(); + } + public float getWidth() { return ellipsizeWidth >= 0 ? Math.min(ellipsizeWidth, width) : width; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java index a0ae92c125..e846e29789 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java @@ -1,11 +1,15 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; @@ -35,6 +39,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.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -54,8 +59,11 @@ public class TranscribeButton { private Paint backgroundPaint, strokePaint; private Path progressClipPath; + private boolean drawLock; + private final AnimatedFloat animatedDrawLock; + private boolean loading; - private AnimatedFloat loadingFloat; + private final AnimatedFloat loadingFloat; private int inIconDrawableAlpha; private RLottieDrawable inIconDrawable; @@ -77,11 +85,11 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { start = SystemClock.elapsedRealtime(); this.parent = parent; this.seekBar = seekBar; - this.bounds = new Rect(0, 0, AndroidUtilities.dp(30), AndroidUtilities.dp(30)); + this.bounds = new Rect(0, 0, dp(30), dp(30)); this.pressBounds = new Rect(this.bounds); - this.pressBounds.inset(AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + this.pressBounds.inset(dp(8), dp(8)); - outIconDrawable = new RLottieDrawable(R.raw.transcribe_out, "transcribe_out", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); + outIconDrawable = new RLottieDrawable(R.raw.transcribe_out, "transcribe_out", dp(26), dp(26)); outIconDrawable.setCurrentFrame(0); outIconDrawable.setCallback(parent); outIconDrawable.setOnFinishCallback(() -> { @@ -92,7 +100,7 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { }, 19); outIconDrawable.setAllowDecodeSingleFrame(true); - inIconDrawable = new RLottieDrawable(R.raw.transcribe_in, "transcribe_in", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); + inIconDrawable = new RLottieDrawable(R.raw.transcribe_in, "transcribe_in", dp(26), dp(26)); inIconDrawable.setCurrentFrame(0); inIconDrawable.setCallback(parent); inIconDrawable.setMasterParent(parent); @@ -109,13 +117,24 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { premium = parent.getMessageObject() != null && UserConfig.getInstance(parent.getMessageObject().currentAccount).isPremium(); loadingFloat = new AnimatedFloat(parent, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + animatedDrawLock = new AnimatedFloat(parent, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + public void setLock(boolean drawLock, boolean animated) { + if (this.drawLock != drawLock && parent != null) { + parent.invalidate(); + } + this.drawLock = drawLock; + if (!animated) { + animatedDrawLock.set(drawLock, true); + } } public void setLoading(boolean loading, boolean animated) { this.loading = loading; seekBar.setLoading(loading); if (!animated) { - loadingFloat.set(this.loading ? 1 : 0, true); + loadingFloat.set(this.loading, true); } else { if (loadingFloat.get() <= 0f) { start = SystemClock.elapsedRealtime(); @@ -185,11 +204,14 @@ public boolean onTouch(int action, float x, float y) { } public void onTap() { + if (parent == null) { + return; + } clickedToOpen = false; boolean processClick, toOpen = !shouldBeOpen; if (!shouldBeOpen) { processClick = !loading; - if (premium && parent.getMessageObject().isSent()) { + if ((premium || canTranscribeTrial(parent.getMessageObject())) && parent.getMessageObject().isSent()) { setLoading(true, true); } } else { @@ -204,14 +226,22 @@ public void onTap() { pressed = false; if (processClick) { if (!premium && toOpen) { - if (parent.getDelegate() != null) { - parent.getDelegate().needShowPremiumBulletin(0); + if (canTranscribeTrial(parent.getMessageObject()) || parent.getMessageObject() != null && parent.getMessageObject().messageOwner != null && !TextUtils.isEmpty(parent.getMessageObject().messageOwner.voiceTranscription)) { + transcribePressed(parent.getMessageObject(), toOpen, parent.getDelegate()); + } else { + if (parent.getDelegate() != null) { + if (MessagesController.getInstance(parent.currentAccount).transcribeAudioTrialWeeklyNumber > 0) { + parent.getDelegate().needShowPremiumBulletin(3); + } else { + parent.getDelegate().needShowPremiumBulletin(0); + } + } } } else { if (toOpen) { clickedToOpen = true; } - transcribePressed(parent.getMessageObject(), toOpen); + transcribePressed(parent.getMessageObject(), toOpen, parent.getDelegate()); } } } @@ -237,7 +267,7 @@ public void setColor(int color, int grayColor, boolean isOut, float bgBack) { backgroundPaint.setColor(this.backgroundColor); backgroundPaint.setAlpha((int) (backgroundPaint.getAlpha() * (1f - bgBack))); if (newColor || selectorDrawable == null) { - selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), 0, this.rippleColor); + selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(dp(8), 0, this.rippleColor); selectorDrawable.setCallback(parent); } if (newColor) { @@ -287,7 +317,7 @@ public int height() { } public void draw(Canvas canvas, float alpha) { - this.pressBounds.set(this.bounds.left - AndroidUtilities.dp(8), this.bounds.top - AndroidUtilities.dp(8), this.bounds.right + AndroidUtilities.dp(8), this.bounds.bottom + AndroidUtilities.dp(8)); + this.pressBounds.set(this.bounds.left - dp(8), this.bounds.top - dp(8), this.bounds.right + dp(8), this.bounds.bottom + dp(8)); if (boundsPath == null) { boundsPath = new Path(); } else { @@ -341,7 +371,7 @@ public void draw(Canvas canvas, float alpha) { addCorner(progressClipPath, bounds.left, bounds.top, diameter, 4, from, to, 360 - b, 360 - a); addLine(progressClipPath, bounds.left + radius, bounds.top, bounds.centerX(), bounds.top, from, to, 360 - a, 360); - strokePaint.setStrokeWidth(AndroidUtilities.dp(1.5f)); + strokePaint.setStrokeWidth(dp(1.5f)); int wasAlpha = strokePaint.getAlpha(); strokePaint.setAlpha((int) (wasAlpha * alpha)); canvas.drawPath(progressClipPath, strokePaint); @@ -351,7 +381,8 @@ public void draw(Canvas canvas, float alpha) { } canvas.save(); - canvas.translate(bounds.centerX() + AndroidUtilities.dp(2 - 15), bounds.centerY() + AndroidUtilities.dp(-1 - 12)); + canvas.translate(bounds.centerX() + dp(2 - 15), bounds.centerY() + dp(-1 - 12)); + canvas.saveLayerAlpha(0, 0, dp(26), dp(26), 0xFF, Canvas.ALL_SAVE_FLAG); if (isOpen) { inIconDrawable.setAlpha((int) (inIconDrawableAlpha * alpha)); inIconDrawable.draw(canvas); @@ -359,6 +390,55 @@ public void draw(Canvas canvas, float alpha) { outIconDrawable.setAlpha((int) (outIconDrawableAlpha * alpha)); outIconDrawable.draw(canvas); } + drawLock(canvas); + canvas.restore(); + canvas.restore(); + } + + private Paint clipLockPaint; + private Paint lockPaint, lockStrokePaint; + private float lockHandlePathDensity; + private Path lockHandlePath; + + private void drawLock(Canvas canvas) { + final float alpha = animatedDrawLock.set(drawLock && !isOpen && !loading); + if (alpha <= 0) { + return; + } + + canvas.save(); + canvas.translate(dp(16 + 2), dp(10 + 2)); + if (clipLockPaint == null) { + clipLockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + clipLockPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + AndroidUtilities.rectTmp.set(0, -dp(.4f), dp(6.666f), dp(8.333f + .4f)); + canvas.scale(alpha, alpha, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2), dp(2), clipLockPaint); + if (lockPaint == null) { + lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + lockPaint.setColor(iconColor); + lockPaint.setAlpha((int) (0xFF * alpha)); + AndroidUtilities.rectTmp.set(0, dp(3.33f), dp(6.666f), dp(3.33f + 5)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1.33f), dp(1.33f), lockPaint); + if (lockHandlePath == null || Math.abs(lockHandlePathDensity - AndroidUtilities.density) > 0.1f) { + lockHandlePathDensity = AndroidUtilities.density; + lockHandlePath = new Path(); + lockHandlePath.moveTo(dp(1.66f), dp(3.33f)); + lockHandlePath.lineTo(dp(1.66f), dp(2)); + AndroidUtilities.rectTmp.set(dp(1.66f), dp(0.33f), dp(1.66f + 3.33f), dp(0.33f + 3.33f)); + lockHandlePath.arcTo(AndroidUtilities.rectTmp, -180, 180, false); + lockHandlePath.lineTo(dp(5), dp(3.33f)); + } + if (lockStrokePaint == null) { + lockStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + lockStrokePaint.setStyle(Paint.Style.STROKE); + } + lockStrokePaint.setStrokeWidth(dp(1)); + lockStrokePaint.setColor(iconColor); + lockStrokePaint.setAlpha((int) (0xFF * alpha)); + canvas.drawPath(lockHandlePath, lockStrokePaint); canvas.restore(); } @@ -575,7 +655,7 @@ public static boolean isTranscribing(MessageObject messageObject) { ); } - private static void transcribePressed(MessageObject messageObject, boolean open) { + private static void transcribePressed(MessageObject messageObject, boolean open, ChatMessageCell.ChatMessageCellDelegate delegate) { if (messageObject == null || messageObject.messageOwner == null || !messageObject.isSent()) { return; } @@ -603,6 +683,10 @@ private static void transcribePressed(MessageObject messageObject, boolean open) transcribeOperationsByDialogPosition = new HashMap<>(); } transcribeOperationsByDialogPosition.put((Integer) reqInfoHash(messageObject), messageObject); + int flags = 0; + if (!UserConfig.getInstance(account).isPremium()) { + flags |= ConnectionsManager.RequestFlagDoNotWaitFloodWait; + } ConnectionsManager.getInstance(account).sendRequest(req, (res, err) -> { String text; long id = 0; @@ -615,12 +699,39 @@ private static void transcribePressed(MessageObject messageObject, boolean open) if (TextUtils.isEmpty(text)) { text = !isFinal ? null : ""; } + if ((r.flags & 2) != 0) { + MessagesController.getInstance(account).updateTranscribeAudioTrialCurrentNumber(r.trial_remains_num); + MessagesController.getInstance(account).updateTranscribeAudioTrialCooldownUntil(r.trial_remains_until_date); + AndroidUtilities.runOnUIThread(() -> { + if (delegate != null) { + delegate.needShowPremiumBulletin(r.trial_remains_num > 0 ? 1 : 2); + } + }); + } if (transcribeOperationsById == null) { transcribeOperationsById = new HashMap<>(); } transcribeOperationsById.put(id, messageObject); messageObject.messageOwner.voiceTranscriptionId = id; } else { + if (err != null && err.text != null) { + if (err.text.startsWith("FLOOD_WAIT_")) { + MessagesController.getInstance(account).updateTranscribeAudioTrialCurrentNumber(0); + MessagesController.getInstance(account).updateTranscribeAudioTrialCooldownUntil(ConnectionsManager.getInstance(account).getCurrentTime() + Utilities.parseInt(err.text)); + AndroidUtilities.runOnUIThread(() -> { + if (transcribeOperationsByDialogPosition != null) { + transcribeOperationsByDialogPosition.remove((Integer) reqInfoHash(messageObject)); + } + if (delegate != null) { + delegate.needShowPremiumBulletin(3); + } + NotificationCenter.getInstance(account).postNotificationName(NotificationCenter.voiceTranscriptionUpdate, messageObject); + NotificationCenter.getInstance(account).postNotificationName(NotificationCenter.updateTranscriptionLock); + }); + return; + } + } + text = ""; isFinal = true; } @@ -638,7 +749,7 @@ private static void transcribePressed(MessageObject messageObject, boolean open) if (isFinal) { AndroidUtilities.runOnUIThread(() -> finishTranscription(messageObject, finalId, finalText), Math.max(0, minDuration - duration)); } - }); + }, flags); } } else { if (transcribeOperationsByDialogPosition != null) { @@ -695,4 +806,42 @@ public static void showOffTranscribe(MessageObject messageObject, boolean notify }); } } + + public static boolean canTranscribeTrial(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + ConnectionsManager cc = ConnectionsManager.getInstance(messageObject.currentAccount); + MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + if (mc.transcribeAudioTrialWeeklyNumber <= 0 || messageObject.getDuration() > mc.transcribeAudioTrialDurationMax) { + return false; + } + return mc.transcribeAudioTrialCooldownUntil == 0 || cc.getCurrentTime() > mc.transcribeAudioTrialCooldownUntil || mc.transcribeAudioTrialCurrentNumber > 0; + } + + public static int getTranscribeTrialCount(int currentAccount) { + ConnectionsManager cc = ConnectionsManager.getInstance(currentAccount); + MessagesController mc = MessagesController.getInstance(currentAccount); + if (mc.transcribeAudioTrialWeeklyNumber <= 0) { + return 0; + } + if (mc.transcribeAudioTrialCooldownUntil == 0 || cc.getCurrentTime() > mc.transcribeAudioTrialCooldownUntil) + return mc.transcribeAudioTrialWeeklyNumber; + return mc.transcribeAudioTrialCurrentNumber; + } + + public static boolean showTranscribeLock(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + if (!TextUtils.isEmpty(messageObject.messageOwner.voiceTranscription)) { + return false; + } + ConnectionsManager cc = ConnectionsManager.getInstance(messageObject.currentAccount); + MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + if (UserConfig.getInstance(messageObject.currentAccount).isPremium()) { + return false; + } + return mc.transcribeAudioTrialCooldownUntil != 0 && cc.getCurrentTime() <= mc.transcribeAudioTrialCooldownUntil && mc.transcribeAudioTrialCurrentNumber <= 0; + } } 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 75e1c00267..c830ea0d04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -576,7 +576,7 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj icon = 0; AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImageView.setForUserOrChat(user, avatarDrawable); avatarImageView.setVisibility(VISIBLE); timeLeft = 3000; @@ -601,7 +601,7 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj icon = 0; AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); - avatarDrawable.setInfo((TLObject) infoObject); + avatarDrawable.setInfo(currentAccount, (TLObject) infoObject); avatarImageView.setForUserOrChat((TLObject) infoObject, avatarDrawable); avatarImageView.setVisibility(VISIBLE); timeLeft = 3000; @@ -611,12 +611,12 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj String name; if (infoObject instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) infoObject; - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImageView.setForUserOrChat(user, avatarDrawable); name = ContactsController.formatName(user.first_name, user.last_name); } else { TLRPC.Chat chat = (TLRPC.Chat) infoObject; - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImageView.setForUserOrChat(chat, avatarDrawable); name = chat.title; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java index 28cb79dcd5..1edfda29e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java @@ -1,7 +1,10 @@ package org.telegram.ui.Components; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import androidx.annotation.NonNull; @@ -46,7 +49,7 @@ public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPr this.type = type; this.isPremium = isPremiumUser; int color1 = ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(0), 255); - int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; + int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; int color3 = vectorImageMarkup.background_colors.size() > 2 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(2), 255) : 0; int color4 = vectorImageMarkup.background_colors.size() > 3 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(3), 255) : 0; gradientTools.setColors(color1, color2, color3, color4); @@ -60,6 +63,7 @@ public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPr } animatedEmojiDrawable = new AnimatedEmojiDrawable(cacheType, UserConfig.selectedAccount, emojiMarkup.emoji_id); + animatedEmojiDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); } else if (vectorImageMarkup instanceof TLRPC.TL_videoSizeStickerMarkup) { sizeStickerMarkup = (TLRPC.TL_videoSizeStickerMarkup) vectorImageMarkup; imageReceiver = new ImageReceiver() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java index e16dfce990..886bbd11b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java @@ -4,6 +4,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -12,6 +13,8 @@ import android.util.Property; import android.view.View; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.ActionBar.Theme; @@ -55,7 +58,7 @@ public Float get(WallpaperCheckBoxView object) { public WallpaperCheckBoxView(Context context, boolean check, View parent, Theme.ResourcesProvider resourcesProvider) { super(context); - // this.resourcesProvider = resourcesProvider; + this.resourcesProvider = resourcesProvider; rect = new RectF(); if (check) { @@ -106,6 +109,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(maxTextSize + AndroidUtilities.dp(14 * 2 + 28), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); } + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float dimAmount; + public void setDimAmount(float dimAmount) { + this.dimAmount = dimAmount; + dimPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (0xFF * dimAmount))); + invalidate(); + } + @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -113,9 +124,11 @@ protected void onDraw(Canvas canvas) { canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, getThemedPaint(Theme.key_paint_chatActionBackground)); boolean hasGradient = resourcesProvider == null ? Theme.hasGradientService() : resourcesProvider.hasGradientService(); if (hasGradient) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + if (dimAmount > 0) { + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, dimPaint); } - textPaint.setColor(Theme.getColor(Theme.key_chat_serviceText, resourcesProvider)); int x = (getMeasuredWidth() - currentTextSize - AndroidUtilities.dp(28)) / 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java index e8e7a52d06..87478e8fe8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java @@ -1085,13 +1085,13 @@ public void onAnimationEnd(Animator animation) { Object parentObject; if (DialogObject.isUserDialog(peerId)) { TLRPC.User currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId); - noVideoStubLayout.avatarDrawable.setInfo(currentUser); + noVideoStubLayout.avatarDrawable.setInfo(currentAccount, currentUser); imageLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_SMALL); parentObject = currentUser; } else { TLRPC.Chat currentChat = AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().getChat(-peerId); - noVideoStubLayout.avatarDrawable.setInfo(currentChat); + noVideoStubLayout.avatarDrawable.setInfo(currentAccount, currentChat); imageLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_SMALL); parentObject = currentChat; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 5277056b2a..5201608059 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -205,6 +205,7 @@ public void onItemClick(int id) { doneButton = menu.addItem(done_button, LocaleController.getString("Done", R.string.Done).toUpperCase()); fragmentView = new ScrollView(context); + fragmentView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); @@ -876,7 +877,7 @@ public ArrayList getThemeDescriptions() { if (user == null) { return; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImage.invalidate(); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java index 9ded923ceb..5fa4251606 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java @@ -1100,7 +1100,7 @@ public boolean isLightStatusBar() { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - if (event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { + if (event != null && event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { return true; } return pager.getCurrentPosition() == 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 444b819770..b127d5a3d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -166,6 +166,7 @@ import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlurredRecyclerView; +import org.telegram.ui.Components.BotWebViewSheet; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatActivityEnterView; @@ -2908,6 +2909,11 @@ public void onFragmentDestroy() { SuggestClearDatabaseBottomSheet.dismissDialog(); } + @Override + public boolean dismissDialogOnPause(Dialog dialog) { + return !(dialog instanceof BotWebViewSheet) && super.dismissDialogOnPause(dialog); + } + @Override public ActionBar createActionBar(Context context) { ActionBar actionBar = new ActionBar(context) { @@ -3580,7 +3586,7 @@ public void onDeletePressed(int id) { switchItem.addView(imageView, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); TLRPC.User user = getUserConfig().getCurrentUser(); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageView.getImageReceiver().setCurrentAccount(currentAccount); Drawable thumb = user != null && user.photo != null && user.photo.strippedBitmap != null ? user.photo.strippedBitmap : avatarDrawable; imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", thumb, user); @@ -7740,22 +7746,36 @@ private void onItemClick(View view, int position, RecyclerListView.Adapter adapt slowedReloadAfterDialogClick = true; if (getMessagesController().checkCanOpenChat(args, DialogsActivity.this)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat != null && chat.forum && topicId == 0 && !NaConfig.INSTANCE.getShowForumAsNormalChat().Bool()) { + TLRPC.Dialog dialog = getMessagesController().getDialog(dialogId); + boolean needOpenChatActivity = dialog != null && dialog.view_forum_as_messages; + if (chat != null && chat.forum && topicId == 0) { if (!LiteMode.isEnabled(LiteMode.FLAG_CHAT_FORUM_TWOCOLUMN)) { - presentFragment(new TopicsFragment(args)); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); + } else { + presentFragment(new TopicsFragment(args)); + } } else { if (!canOpenInRightSlidingView) { - presentFragment(new TopicsFragment(args)); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); + } else { + presentFragment(new TopicsFragment(args)); + } } else if (!searching) { - if (rightSlidingDialogContainer.currentFragment != null && ((TopicsFragment) rightSlidingDialogContainer.currentFragment).getDialogId() == dialogId) { - rightSlidingDialogContainer.finishPreview(); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); } else { - viewPages[0].listView.prepareSelectorForAnimation(); - TopicsFragment topicsFragment = new TopicsFragment(args); - topicsFragment.parentDialogsActivity = this; - rightSlidingDialogContainer.presentFragment(getParentLayout(), topicsFragment); + if (rightSlidingDialogContainer.currentFragment != null && ((TopicsFragment) rightSlidingDialogContainer.currentFragment).getDialogId() == dialogId) { + rightSlidingDialogContainer.finishPreview(); + } else { + viewPages[0].listView.prepareSelectorForAnimation(); + TopicsFragment topicsFragment = new TopicsFragment(args); + topicsFragment.parentDialogsActivity = this; + rightSlidingDialogContainer.presentFragment(getParentLayout(), topicsFragment); + } + searchViewPager.updateTabs(); } - searchViewPager.updateTabs(); } } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java index b25f4c028b..6c0d0d0a87 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java @@ -121,8 +121,6 @@ import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlobDrawable; -import org.telegram.ui.Components.Bulletin; -import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CheckBoxSquare; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextBoldCursor; @@ -7037,7 +7035,7 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, lo imageView.setRoundRadius(AndroidUtilities.dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); String name; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index b5140c83f4..fb5f6cf251 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -285,8 +285,8 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private List overlayPasscodeViews = new ArrayList<>(); private TermsOfServiceView termsOfServiceView; private BlockingUpdateView blockingUpdateView; - private AlertDialog visibleDialog; - private AlertDialog proxyErrorDialog; + public Dialog visibleDialog; + private Dialog proxyErrorDialog; private RecyclerListView sideMenu; private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; private SideMenultItemAnimator itemAnimator; @@ -294,7 +294,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private View rippleAbove; private IUpdateLayout updateLayout; - private AlertDialog localeDialog; + private Dialog localeDialog; private boolean loadingLocaleDialog; private HashMap systemLocaleStrings; private HashMap englishLocaleStrings; @@ -1012,7 +1012,12 @@ private void showAttachMenuBot(TLRPC.TL_attachMenuBot attachMenuBot, String star BotWebViewSheet webViewSheet = new BotWebViewSheet(this, getLastFragment().getResourceProvider()); webViewSheet.setParentActivity(this); webViewSheet.requestWebView(currentAccount, attachMenuBot.bot_id, attachMenuBot.bot_id, attachMenuBot.short_name, null, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, null, null, false, startApp, null, BotWebViewSheet.FLAG_FROM_SIDE_MENU); + if (visibleDialog != null) { + visibleDialog.dismiss(); + visibleDialog = null; + } webViewSheet.show(); + visibleDialog = webViewSheet; } @Override @@ -3375,10 +3380,10 @@ public boolean shouldShowNextButton(DialogsActivity dialogsFragment, ArrayList arrayList) { + private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, int messageId, TLRPC.TL_forumTopic forumTopic, Runnable whenDone, String quote, int fromMessageId, ArrayList arrayList, int quoteOffset) { if (forumTopic == null) { forumTopic = MessagesController.getInstance(intentAccount).getTopicsController().findTopic(chat.id, topicId); } @@ -3466,7 +3471,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i MessagesController.getInstance(intentAccount).getTopicsController().processTopics(chat.id, topics.topics, messagesMap, false, TopicsController.LOAD_TYPE_LOAD_UNKNOWN, -1); TLRPC.TL_forumTopic topic = MessagesController.getInstance(intentAccount).getTopicsController().findTopic(chat.id, topicId); - openTopicRequest(intentAccount, topicId, chat, messageId, topic, whenDone, quote, fromMessageId, arrayList); + openTopicRequest(intentAccount, topicId, chat, messageId, topic, whenDone, quote, fromMessageId, arrayList, quoteOffset); }; })); return; @@ -3474,7 +3479,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i BaseFragment lastFragment = !mainFragmentsStack.isEmpty() ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; if (lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == -chat.id && ((ChatActivity) lastFragment).isTopic && ((ChatActivity) lastFragment).getTopicId() == forumTopic.id) { if (quote != null) { - ((ChatActivity) lastFragment).setHighlightQuote(messageId, quote); + ((ChatActivity) lastFragment).setHighlightQuote(messageId, quote, quoteOffset); } ((ChatActivity) lastFragment).scrollToMessageId(messageId, fromMessageId, true, 0, true, 0, null); } else { @@ -3493,7 +3498,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i chatActivity.setThreadMessages(arrayList, chat, messageId, forumTopic.read_inbox_max_id, forumTopic.read_outbox_max_id, forumTopic); if (messageId != forumTopic.id) { if (quote != null) { - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); } else { chatActivity.setHighlightMessageId(messageId); } @@ -3641,7 +3646,7 @@ private void openGroupCall(AccountInstance accountInstance, TLRPC.Chat chat, Str VoIPHelper.startCall(chat, null, hash, false, this, mainFragmentsStack.get(mainFragmentsStack.size() - 1), accountInstance); } - public void openMessage(long dialogId, int messageId, String quote, final Browser.Progress progress, int fromMessageId) { + public void openMessage(long dialogId, int messageId, String quote, final Browser.Progress progress, int fromMessageId, final int quoteOffset) { if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null && ChatObject.isForum(chat)) { @@ -3652,7 +3657,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } } @@ -3669,7 +3674,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } args.putLong("chat_id", -dialogId); @@ -3679,7 +3684,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (lastFragment == null || MessagesController.getInstance(currentAccount).checkCanOpenChat(args, lastFragment)) { AndroidUtilities.runOnUIThread(() -> { ChatActivity chatActivity = new ChatActivity(args); - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); if (!(AndroidUtilities.isTablet() ? rightActionBarLayout : getActionBarLayout()).presentFragment(chatActivity) && dialogId < 0) { TLRPC.TL_channels_getChannels req = new TLRPC.TL_channels_getChannels(); TLRPC.TL_inputChannel inputChannel = new TLRPC.TL_inputChannel(); @@ -3701,7 +3706,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse } if (lastFragment == null || MessagesController.getInstance(currentAccount).checkCanOpenChat(args, lastFragment)) { ChatActivity chatActivity2 = new ChatActivity(args); - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); getActionBarLayout().presentFragment(chatActivity2); } } @@ -4290,7 +4295,7 @@ public void didChangeOwner(TLRPC.User user) { } else { Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialog_id); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); try { dismissLoading.run(); } catch (Exception e) { @@ -4426,7 +4431,7 @@ public void onError() { if (invite.chat.forum) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", invite.chat.id); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); } else { MessagesController.getInstance(intentAccount).ensureMessagesLoaded(-invite.chat.id, 0, new MessagesController.MessagesLoadedCallback() { @Override @@ -5003,7 +5008,12 @@ private void processWebAppBot(final int intentAccount, BotWebViewSheet sheet = new BotWebViewSheet(LaunchActivity.this, lastFragment.getResourceProvider()); sheet.setParentActivity(LaunchActivity.this); sheet.requestWebView(intentAccount, user.id, user.id, null, null, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP, 0, false, lastFragment, botApp.app, allowWrite.get(), botAppStartParam, user); + if (visibleDialog != null) { + visibleDialog.dismiss(); + visibleDialog = null; + } sheet.show(); + visibleDialog = sheet; if (botApp.inactive || forceNotInternalForApps) { sheet.showJustAddedBulletin(); } @@ -5140,6 +5150,13 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM if (!attachMenuBot.inactive) { if (dialogsActivity != null) { + if (lastFragment != null) { + lastFragment.dismissCurrentDialog(); + } + if (visibleDialog != null) { + visibleDialog.dismiss(); + visibleDialog = null; + } presentFragment(dialogsActivity); } else if (lastFragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) lastFragment; @@ -5167,6 +5184,13 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM if (response2 instanceof TLRPC.TL_boolTrue) { MediaDataController.getInstance(intentAccount).loadAttachMenuBots(false, true, () -> { if (dialogsActivity != null) { + if (lastFragment != null) { + lastFragment.dismissCurrentDialog(); + } + if (visibleDialog != null) { + visibleDialog.dismiss(); + visibleDialog = null; + } presentFragment(dialogsActivity); } else if (lastFragment instanceof ChatActivity) { ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot, true); @@ -5183,14 +5207,14 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM } private void openForumFromLink(long dialogId, Integer messageId, Runnable onOpened) { - openForumFromLink(dialogId, messageId, null, onOpened, 0); + openForumFromLink(dialogId, messageId, null, onOpened, 0, -1); } - private void openForumFromLink(long dialogId, Integer messageId, String quote, Runnable onOpened, int fromMessageId) { + private void openForumFromLink(long dialogId, Integer messageId, String quote, Runnable onOpened, int fromMessageId, int quoteOffset) { if (messageId == null) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialogId); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); if (onOpened != null) { onOpened.run(); @@ -5214,13 +5238,13 @@ private void openForumFromLink(long dialogId, Integer messageId, String quote, R } if (message != null) { - runCommentRequest(currentAccount, null, message.id, null, MessageObject.getTopicId(message, MessagesController.getInstance(currentAccount).isForum(message)), MessagesController.getInstance(currentAccount).getChat(-dialogId), onOpened, quote, fromMessageId); + runCommentRequest(currentAccount, null, message.id, null, MessageObject.getTopicId(message, MessagesController.getInstance(currentAccount).isForum(message)), MessagesController.getInstance(currentAccount).getChat(-dialogId), onOpened, quote, fromMessageId, quoteOffset); return; } Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialogId); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); if (onOpened != null) { onOpened.run(); @@ -5345,7 +5369,7 @@ public void checkAppUpdate(boolean force) { })); } - public AlertDialog showAlertDialog(AlertDialog.Builder builder) { + public Dialog showAlertDialog(AlertDialog.Builder builder) { try { if (visibleDialog != null) { visibleDialog.dismiss(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 9255f8729b..c52e3ef582 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -1521,9 +1521,9 @@ private Bitmap createUserBitmap(LiveLocation liveLocation) { } else { AvatarDrawable avatarDrawable = new AvatarDrawable(); if (liveLocation.user != null) { - avatarDrawable.setInfo(liveLocation.user); + avatarDrawable.setInfo(currentAccount, liveLocation.user); } else if (liveLocation.chat != null) { - avatarDrawable.setInfo(liveLocation.chat); + avatarDrawable.setInfo(currentAccount, liveLocation.chat); } canvas.translate(AndroidUtilities.dp(6), AndroidUtilities.dp(6)); avatarDrawable.setBounds(0, 0, AndroidUtilities.dp(50), AndroidUtilities.dp(50)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java index c7adda3a63..7f172e396f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java @@ -1,19 +1,11 @@ package org.telegram.ui; import android.content.Context; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; -import android.text.style.DynamicDrawableSpan; -import android.text.style.ImageSpan; -import android.util.Log; import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; @@ -25,7 +17,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -40,13 +31,11 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; -import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.AvatarsImageView; @@ -412,7 +401,7 @@ public void setUser(TLObject object, int date) { updateStatus(false); if (object != null) { - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); ImageLocation imageLocation = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); avatarImageView.setImage(imageLocation, "50_50", avatarDrawable, object); nameView.setText(ContactsController.formatName(object)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java index 72f551ccbb..ffd77d9079 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -18,11 +18,10 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -31,6 +30,7 @@ import android.widget.Toast; import androidx.collection.ArraySet; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; @@ -55,14 +55,15 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.EmptyCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LoadingCell; @@ -72,12 +73,15 @@ import org.telegram.ui.Charts.data.ChartData; import org.telegram.ui.Charts.data.StackLinearChartData; import org.telegram.ui.Charts.view_data.ChartHeaderView; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Stories.StoriesListPlaceProvider; +import org.telegram.ui.Stories.StoriesUtilities; import java.util.ArrayList; @@ -93,19 +97,22 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati private MessageObject messageObject; private StatisticActivity.ChartViewData interactionsViewData; + private StatisticActivity.ChartViewData reactionsByEmotionData; private LruCache childDataCache = new LruCache<>(15); private StatisticActivity.ZoomCancelable lastCancelable; - private ArrayList messages = new ArrayList<>(); + private ArrayList messages = new ArrayList<>(); private boolean statsLoaded; private boolean loading; private boolean firstLoaded; + private String nextOffset = null; private int headerRow; private int startRow; private int endRow; private int loadingRow; private int interactionsChartRow; + private int reactionsByEmotionChartRow; private int overviewRow; private int overviewHeaderRow; private int emptyRow; @@ -122,6 +129,7 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati ImageReceiver thumbImage; boolean drawPlay; + boolean hasThumb; private final Runnable showProgressbar = new Runnable() { @Override @@ -132,6 +140,8 @@ public void run() { private FrameLayout listContainer; private ChatAvatarContainer avatarContainer; private BaseChartView.SharedUiComponents sharedUi; + private boolean needActionbarMenu; + private StatisticActivity.RecentPostInfo recentPostInfo; public MessageStatisticActivity(MessageObject message) { messageObject = message; @@ -146,6 +156,19 @@ public MessageStatisticActivity(MessageObject message) { this.chat = getMessagesController().getChatFull(chatId); } + public MessageStatisticActivity(StatisticActivity.RecentPostInfo recentPostInfo, long chatId, boolean needActionbarMenu) { + this(recentPostInfo.message, chatId, needActionbarMenu); + this.recentPostInfo = recentPostInfo; + } + + public MessageStatisticActivity(MessageObject message, long chatId, boolean needActionbarMenu) { + messageObject = message; + messageId = 0; + this.chatId = chatId; + this.chat = getMessagesController().getChatFull(chatId); + this.needActionbarMenu = needActionbarMenu; + } + private void updateRows() { shadowDivideCells.clear(); headerRow = -1; @@ -153,6 +176,7 @@ private void updateRows() { endRow = -1; loadingRow = -1; interactionsChartRow = -1; + reactionsByEmotionChartRow = -1; overviewHeaderRow = -1; overviewRow = -1; @@ -178,6 +202,10 @@ public void onAnimationEnd(Animator animation) { interactionsChartRow = rowCount++; shadowDivideCells.add(rowCount++); } + if (reactionsByEmotionData != null) { + reactionsByEmotionChartRow = rowCount++; + shadowDivideCells.add(rowCount++); + } if (!messages.isEmpty()) { headerRow = rowCount++; @@ -220,12 +248,8 @@ public void onFragmentDestroy() { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; - if (chat == null && chatFull.id == chatId) { - TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); - if (chatLocal != null) { - avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); - } + if (chat == null && chatFull.id == chatId) { + setAvatarAndTitle(); chat = chatFull; loadStat(); loadChats(100); @@ -234,12 +258,23 @@ public void didReceivedNotification(int id, int account, Object... args) { } } + private boolean checkIsDeletedStory(MessageObject message) { + if (message == null || !message.isStory()) { + return false; + } + if (message.storyItem instanceof TL_stories.TL_storyItemDeleted) { + BulletinFactory.of(this).createSimpleBulletin(R.raw.story_bomb1, LocaleController.getString("StoryNotFound", R.string.StoryNotFound)).show(); + return true; + } + return false; + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); fragmentView = new FrameLayout(context); - fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider())); FrameLayout frameLayout = (FrameLayout) fragmentView; emptyView = new EmptyTextProgressView(context); @@ -257,14 +292,14 @@ public View createView(Context context) { TextView loadingTitle = new TextView(context); loadingTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); loadingTitle.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); + loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider())); loadingTitle.setTag(Theme.key_player_actionBarTitle); loadingTitle.setText(LocaleController.getString("LoadingStats", R.string.LoadingStats)); loadingTitle.setGravity(Gravity.CENTER_HORIZONTAL); TextView loadingSubtitle = new TextView(context); loadingSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); loadingSubtitle.setTag(Theme.key_player_actionBarSubtitle); loadingSubtitle.setText(LocaleController.getString("LoadingStatsDescription", R.string.LoadingStatsDescription)); loadingSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); @@ -276,7 +311,7 @@ public View createView(Context context) { frameLayout.addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); - listView = new RecyclerListView(context); + listView = new RecyclerListView(context, getResourceProvider()); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); ((SimpleItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); listView.setAdapter(listViewAdapter = new ListAdapter(context)); @@ -284,21 +319,69 @@ public View createView(Context context) { listView.setOnItemClickListener((view, position) -> { if (position >= startRow && position < endRow) { - TLRPC.Message message = messages.get(position - startRow); - long did = MessageObject.getDialogId(message); + MessageObject message = messages.get(position - startRow); + if (message.isStory()) { + if (checkIsDeletedStory(message)) { + return; + } + getOrCreateStoryViewer().open(getContext(), message.storyItem, StoriesListPlaceProvider.of(listView)); + return; + } + long did = MessageObject.getDialogId(message.messageOwner); Bundle args = new Bundle(); if (DialogObject.isUserDialog(did)) { args.putLong("user_id", did); } else { args.putLong("chat_id", -did); } - args.putInt("message_id", message.id); + args.putInt("message_id", message.getId()); args.putBoolean("need_remove_previous_same_chat_activity", false); if (getMessagesController().checkCanOpenChat(args, this)) { presentFragment(new ChatActivity(args)); } } }); + listView.setOnItemLongClickListener((view, position) -> { + if (position >= startRow && position < endRow) { + try { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + MessageObject message = messages.get(position - startRow); + final long did = MessageObject.getDialogId(message.messageOwner); + final boolean isDialog = DialogObject.isUserDialog(did); + final ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + final ArrayList icons = new ArrayList<>(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), getResourceProvider()); + if (message.isStory()) { + items.add(isDialog ? LocaleController.getString("OpenProfile", R.string.OpenProfile) : LocaleController.getString("OpenChannel2", R.string.OpenChannel2)); + icons.add(isDialog ? R.drawable.msg_openprofile : R.drawable.msg_channel); + } else { + items.add(LocaleController.getString("ViewMessage", R.string.ViewMessage)); + icons.add(R.drawable.msg_msgbubble3); + } + actions.add(0); + builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { + if (message.isStory()) { + presentFragment(isDialog ? ProfileActivity.of(did) : ChatActivity.of(did)); + } else { + Bundle args = new Bundle(); + if (isDialog) { + args.putLong("user_id", did); + } else { + args.putLong("chat_id", -did); + } + args.putInt("message_id", message.getId()); + args.putBoolean("need_remove_previous_same_chat_activity", false); + if (getMessagesController().checkCanOpenChat(args, this)) { + presentFragment(new ChatActivity(args)); + } + } + }); + showDialog(builder.create()); + } + return false; + }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -335,8 +418,19 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - thumbImage.setImageCoords(avatarContainer.getSubtitleTextView().getX(), avatarContainer.getSubtitleTextView().getY(), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); - thumbImage.draw(canvas); + thumbImage.setImageCoords( + avatarContainer.getAvatarImageView().getX(), + avatarContainer.getAvatarImageView().getY(), + avatarContainer.getAvatarImageView().getWidth(), + avatarContainer.getAvatarImageView().getHeight()); + + if (hasThumb) { + canvas.save(); + canvas.scale(0.9f, 0.9f, thumbImage.getCenterX(), thumbImage.getCenterY()); + thumbImage.draw(canvas); + canvas.restore(); + } + if (drawPlay) { int x = (int) (thumbImage.getCenterX() - Theme.dialogs_playDrawable.getIntrinsicWidth() / 2); int y = (int) (thumbImage.getCenterY() - Theme.dialogs_playDrawable.getIntrinsicHeight() / 2); @@ -360,64 +454,66 @@ protected void onDetachedFromWindow() { thumbImage = new ImageReceiver(); thumbImage.setParentView(avatarContainer); - thumbImage.setRoundRadius(AndroidUtilities.dp(2)); - actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); - - TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); - if (chatLocal != null) { - avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); - } - - boolean hasThumb = false; - - if (!messageObject.needDrawBluredPreview() && (messageObject.isPhoto() || messageObject.isNewGif() || messageObject.isVideo())) { - String type = messageObject.isWebpage() ? messageObject.messageOwner.media.webpage.type : null; - if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { - TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); - TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - if (smallThumb == bigThumb) { - bigThumb = null; - } - if (smallThumb != null) { - hasThumb = true; - drawPlay = messageObject.isVideo(); - String fileName = FileLoader.getAttachFileName(bigThumb); - if (messageObject.mediaExists || DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { - int size; - if (messageObject.type == MessageObject.TYPE_PHOTO) { - size = bigThumb != null ? bigThumb.size : 0; + thumbImage.setRoundRadius(AndroidUtilities.dp(9)); + + hasThumb = false; + if (!messageObject.isStory()) { + if (!messageObject.needDrawBluredPreview() && (messageObject.isPhoto() || messageObject.isNewGif() || messageObject.isVideo())) { + String type = messageObject.isWebpage() ? messageObject.messageOwner.media.webpage.type : null; + if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { + TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); + TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + if (smallThumb == bigThumb) { + bigThumb = null; + } + if (smallThumb != null) { + hasThumb = true; + drawPlay = messageObject.isVideo(); + String fileName = FileLoader.getAttachFileName(bigThumb); + if (messageObject.mediaExists || DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + int size; + if (messageObject.type == MessageObject.TYPE_PHOTO) { + size = bigThumb != null ? bigThumb.size : 0; + } else { + size = 0; + } + thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "50_50", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "50_50", size, null, messageObject, 0); } else { - size = 0; + thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "50_50", (Drawable) null, messageObject, 0); } - thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", size, null, messageObject, 0); - } else { - thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", (Drawable) null, messageObject, 0); } } } - } - CharSequence message; - if (!TextUtils.isEmpty(messageObject.caption)) { - message = messageObject.caption; - } else if (!TextUtils.isEmpty(messageObject.messageOwner.message)) { - message = messageObject.messageText; - if (message.length() > 150) { - message = message.subSequence(0, 150); + CharSequence message; + if (!TextUtils.isEmpty(messageObject.caption)) { + message = messageObject.caption; + } else if (!TextUtils.isEmpty(messageObject.messageOwner.message)) { + message = messageObject.messageText; + if (message.length() > 150) { + message = message.subSequence(0, 150); + } + message = Emoji.replaceEmoji(message, avatarContainer.getSubtitleTextView().getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); + } else { + message = messageObject.messageText; + } + + if (messageObject.isVideo() || messageObject.isPhoto()) { + avatarContainer.hideSubtitle(); + } else { + avatarContainer.setSubtitle(message); } - } else { - message = messageObject.messageText; } - if (hasThumb) { - SpannableStringBuilder builder = new SpannableStringBuilder(message); - builder.insert(0, " "); - builder.setSpan(new DialogCell.FixedWidthSpan(AndroidUtilities.dp(18 + 6)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - avatarContainer.setSubtitle(builder); - } else { - avatarContainer.setSubtitle(messageObject.messageText); + int avatarContainerMarginLeft = 56; + if (hasThumb || messageObject.isStory()) { + avatarContainer.setRightAvatarPadding(-AndroidUtilities.dp(3)); + avatarContainerMarginLeft = 50; } + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? avatarContainerMarginLeft : 0, 0, 40, 0)); + + setAvatarAndTitle(); + actionBar.setBackButtonDrawable(new BackDrawable(false)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -426,26 +522,25 @@ public void onItemClick(final int id) { finishFragment(); } else if (id == 1) { Bundle args = new Bundle(); - if (messageObject.messageOwner.fwd_from == null) { - args.putLong("chat_id", messageObject.getChatId()); - } else { - args.putLong("chat_id", -messageObject.getFromChatId()); - } + args.putLong("chat_id", chatId); presentFragment(new StatisticActivity(args)); } } }); - avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle), Theme.getColor(Theme.key_player_actionBarSubtitle)); - avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), false); - actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); - actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider()), Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); + actionBar.setItemsColor(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider()), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector, getResourceProvider()), false); + actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); avatarContainer.setOnClickListener(view -> { + if (messageObject.isStory()) { + return; + } if (getParentLayout().getFragmentStack().size() > 1) { BaseFragment previousFragemnt = getParentLayout().getFragmentStack().get(getParentLayout().getFragmentStack().size() - 2); - if (previousFragemnt instanceof ChatActivity && ((ChatActivity) previousFragemnt).getCurrentChat().id == chatId) { + if (previousFragemnt instanceof ChatActivity && ((ChatActivity) previousFragemnt).getCurrentChat().id == chatId) { finishFragment(); return; } @@ -462,7 +557,35 @@ public void onItemClick(final int id) { return fragmentView; } + private void setAvatarAndTitle() { + if (messageObject.isStory()) { + avatarContainer.setTitle(LocaleController.getString("StoryStatistics", R.string.StoryStatistics)); + avatarContainer.hideSubtitle(); + avatarContainer.allowDrawStories = true; + avatarContainer.setStoriesForceState(StoriesUtilities.STATE_HAS_UNREAD); + if (messageObject.photoThumbs != null) { + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); + avatarContainer.getAvatarImageView().setImage( + ImageLocation.getForObject(size, messageObject.photoThumbsObject), "50_50", + ImageLocation.getForObject(thumbSize, messageObject.photoThumbsObject), "b1", 0, messageObject); + avatarContainer.setClipChildren(false); + avatarContainer.getAvatarImageView().setScaleX(0.96f); + avatarContainer.getAvatarImageView().setScaleY(0.96f); + } + } else { + avatarContainer.setTitle(LocaleController.getString("PostStatistics", R.string.PostStatistics)); + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); + if (chatLocal != null && !hasThumb) { + avatarContainer.setChatAvatar(chatLocal); + } + } + } + private void updateMenu() { + if (!needActionbarMenu) { + return; + } if (chat != null && chat.can_view_stats) { ActionBarMenu menu = actionBar.createMenu(); menu.clearItems(); @@ -479,6 +602,54 @@ private void loadChats(int count) { if (listViewAdapter != null) { listViewAdapter.notifyDataSetChanged(); } + if (messageObject.isStory()) { + TLRPC.TL_stats_getStoryPublicForwards req = new TLRPC.TL_stats_getStoryPublicForwards(); + req.limit = count; + req.id = messageObject.storyItem.id; + req.peer = getMessagesController().getInputPeer(-chatId); + req.offset = nextOffset == null ? "" : nextOffset; + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_stats_publicForwards res = (TLRPC.TL_stats_publicForwards) response; + if ((res.flags & 1) != 0) { + nextOffset = res.next_offset; + } else { + nextOffset = null; + } + if (res.count != 0) { + publicChats = res.count; + } else if (publicChats == 0) { + publicChats = res.forwards.size(); + } + endReached = nextOffset == null; + getMessagesController().putChats(res.chats, false); + getMessagesController().putUsers(res.users, false); + + for (TLRPC.PublicForward forward : res.forwards) { + if (forward instanceof TL_stories.TL_publicForwardStory) { + TL_stories.TL_publicForwardStory forwardStory = (TL_stories.TL_publicForwardStory) forward; + forwardStory.story.dialogId = DialogObject.getPeerDialogId(forwardStory.peer); + forwardStory.story.messageId = forwardStory.story.id; + MessageObject msg = new MessageObject(currentAccount, forwardStory.story); + msg.generateThumbs(false); + messages.add(msg); + } else if (forward instanceof TLRPC.TL_publicForwardMessage) { + TLRPC.TL_publicForwardMessage forwardMessage = (TLRPC.TL_publicForwardMessage) forward; + messages.add(new MessageObject(currentAccount, forwardMessage.message, false, true)); + } + } + + if (emptyView != null) { + emptyView.showTextView(); + } + } + firstLoaded = true; + loading = false; + updateRows(); + }), null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + return; + } TLRPC.TL_stats_getMessagePublicForwards req = new TLRPC.TL_stats_getMessagePublicForwards(); req.limit = count; if (messageObject.messageOwner.fwd_from != null) { @@ -489,7 +660,7 @@ private void loadChats(int count) { req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); } if (!messages.isEmpty()) { - TLRPC.Message message = messages.get(messages.size() - 1); + TLRPC.Message message = messages.get(messages.size() - 1).messageOwner; req.offset_id = message.id; req.offset_peer = getMessagesController().getInputPeer(MessageObject.getDialogId(message)); req.offset_rate = nextRate; @@ -510,7 +681,9 @@ private void loadChats(int count) { endReached = !(res instanceof TLRPC.TL_messages_messagesSlice); getMessagesController().putChats(res.chats, false); getMessagesController().putUsers(res.users, false); - messages.addAll(res.messages); + for (int i = 0; i < res.messages.size(); i++) { + messages.add(new MessageObject(currentAccount, res.messages.get(i), false, true)); + } if (emptyView != null) { emptyView.showTextView(); } @@ -523,22 +696,45 @@ private void loadChats(int count) { } private void loadStat() { - TLRPC.TL_stats_getMessageStats req = new TLRPC.TL_stats_getMessageStats(); - if (messageObject.messageOwner.fwd_from != null) { - req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; - req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + TLObject reqObject; + if (messageObject.isStory()) { + TL_stories.TL_stats_getStoryStats req = new TL_stories.TL_stats_getStoryStats(); + req.id = messageObject.storyItem.id; + req.peer = getMessagesController().getInputPeer(-chatId); + reqObject = req; } else { - req.msg_id = messageObject.getId(); - req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); + TLRPC.TL_stats_getMessageStats req = new TLRPC.TL_stats_getMessageStats(); + if (messageObject.messageOwner.fwd_from != null) { + req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; + req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + } else { + req.msg_id = messageObject.getId(); + req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); + } + reqObject = req; } - getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + + getConnectionsManager().sendRequest(reqObject, (response, error) -> AndroidUtilities.runOnUIThread(() -> { statsLoaded = true; if (error != null) { updateRows(); return; } - TLRPC.TL_stats_messageStats res = (TLRPC.TL_stats_messageStats) response; - interactionsViewData = StatisticActivity.createViewData(res.views_graph, LocaleController.getString("InteractionsChartTitle", R.string.InteractionsChartTitle), 1, false); + + TLRPC.StatsGraph views_graph; + TLRPC.StatsGraph reactions_by_emotion_graph; + if (response instanceof TL_stories.TL_stats_storyStats) { + TL_stories.TL_stats_storyStats res = (TL_stories.TL_stats_storyStats) response; + views_graph = res.views_graph; + reactions_by_emotion_graph = res.reactions_by_emotion_graph; + } else { + TLRPC.TL_stats_messageStats res = (TLRPC.TL_stats_messageStats) response; + views_graph = res.views_graph; + reactions_by_emotion_graph = res.reactions_by_emotion_graph; + } + + interactionsViewData = StatisticActivity.createViewData(views_graph, LocaleController.getString("ViewsAndSharesChartTitle", R.string.ViewsAndSharesChartTitle), 1, false); + reactionsByEmotionData = StatisticActivity.createViewData(reactions_by_emotion_graph, LocaleController.getString("ReactionsByEmotionChartTitle", R.string.ReactionsByEmotionChartTitle), 2, false); if (interactionsViewData != null && interactionsViewData.chartData.x.length <= 5) { statsLoaded = false; TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); @@ -621,20 +817,23 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType View view; switch (viewType) { case 0: - view = new ManageChatUserCell(mContext, 6, 2, false); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + ManageChatUserCell cell = new ManageChatUserCell(mContext, 6, 2, false, getResourceProvider()); + cell.setDividerColor(Theme.key_divider); + view = cell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 1: - view = new ShadowSectionCell(mContext); + view = new ShadowSectionCell(mContext, getResourceProvider()); break; case 2: - HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 16, 11, false); - headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlackText, 16, 11, false, getResourceProvider()); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); headerCell.setHeight(43); view = headerCell; break; case 4: - view = new StatisticActivity.BaseChartCell(mContext, 1, sharedUi = new BaseChartView.SharedUiComponents()) { + case 7: + view = new StatisticActivity.BaseChartCell(mContext, viewType == 4 ? 1 : 2, sharedUi = new BaseChartView.SharedUiComponents(getResourceProvider()), getResourceProvider()) { @Override public void onZoomed() { @@ -728,17 +927,17 @@ void loadData(StatisticActivity.ChartViewData viewData) { // viewData.load(currentAccount, classGuid, ); } }; - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 5: view = new OverviewCell(mContext); view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 6: view = new EmptyCell(mContext, 16); view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 16)); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 3: default: @@ -753,26 +952,38 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 0: ManageChatUserCell userCell = (ManageChatUserCell) holder.itemView; - TLRPC.Message item = getItem(position); - long did = MessageObject.getDialogId(item); + MessageObject item = getItem(position); + long did = MessageObject.getDialogId(item.messageOwner); TLObject object; String status = null; - if (DialogObject.isUserDialog(did)) { - object = getMessagesController().getUser(did); + if (item.isStory()) { + object = DialogObject.isUserDialog(did) ? getMessagesController().getUser(did) : getMessagesController().getChat(-did); + boolean isZeroViews = item.storyItem.views == null || item.storyItem.views.views_count == 0; + status = isZeroViews ? LocaleController.getString("NoViews", R.string.NoViews) : LocaleController.formatPluralString("Views", item.storyItem.views.views_count); + userCell.setData(object, null, status, position != endRow - 1); + userCell.setStoryItem(item.storyItem, v -> { + if (checkIsDeletedStory(item)) { + return; + } + getOrCreateStoryViewer().open(getContext(), item.storyItem, StoriesListPlaceProvider.of(listView)); + }); } else { - object = getMessagesController().getChat(-did); - TLRPC.Chat chat = (TLRPC.Chat) object; - if (chat.participants_count != 0) { + userCell.setStoryItem(null, null); + if (DialogObject.isUserDialog(did)) { + object = getMessagesController().getUser(did); + } else { + object = getMessagesController().getChat(-did); + TLRPC.Chat chat = (TLRPC.Chat) object; if (ChatObject.isChannel(chat) && !chat.megagroup) { - status = LocaleController.formatPluralString("Subscribers", chat.participants_count); - } else { + status = LocaleController.formatPluralString("Views", item.messageOwner.views); + } else if (chat.participants_count != 0) { status = LocaleController.formatPluralString("Members", chat.participants_count); + status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.messageOwner.views)); } - status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.views)); } - } - if (object != null) { - userCell.setData(object, null, status, position != endRow - 1); + if (object != null) { + userCell.setData(object, null, status, position != endRow - 1); + } } break; case 1: @@ -781,9 +992,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { case 2: HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == overviewHeaderRow) { + headerCell.setTopMargin(9); + headerCell.setPadding(0, 0, 0, AndroidUtilities.dp(8)); headerCell.setText(LocaleController.formatString("StatisticOverview", R.string.StatisticOverview)); } else { - headerCell.setText(LocaleController.formatPluralString("PublicSharesCount", publicChats)); + headerCell.setTopMargin(11); + headerCell.setPadding(0, 0, 0, 0); + headerCell.setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); } break; case 4: @@ -795,6 +1010,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { OverviewCell overviewCell = (OverviewCell) holder.itemView; overviewCell.setData(); break; + case 7: + StatisticActivity.BaseChartCell chartCell2 = (StatisticActivity.BaseChartCell) holder.itemView; + chartCell2.updateData(reactionsByEmotionData, false); + chartCell2.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + break; } } @@ -819,11 +1039,13 @@ public int getItemViewType(int position) { return 5; } else if (position == emptyRow) { return 6; + } else if (position == reactionsByEmotionChartRow) { + return 7; } return 0; } - public TLRPC.Message getItem(int position) { + public MessageObject getItem(int position) { if (position >= startRow && position < endRow) { return messages.get(position - startRow); } @@ -833,64 +1055,90 @@ public TLRPC.Message getItem(int position) { public class OverviewCell extends LinearLayout { - TextView[] primary = new TextView[3]; - TextView[] title = new TextView[3]; - View[] cell = new View[3]; + TextView[] primary = new TextView[4]; + TextView[] title = new TextView[4]; public OverviewCell(Context context) { super(context); setOrientation(VERTICAL); setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(16)); - LinearLayout linearLayout = new LinearLayout(context); - linearLayout.setOrientation(HORIZONTAL); + for (int i = 0; i < 2; i++) { + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(HORIZONTAL); - for (int j = 0; j < 3; j++) { - LinearLayout contentCell = new LinearLayout(context); - cell[j] = contentCell; - contentCell.setOrientation(VERTICAL); + for (int j = 0; j < 2; j++) { + LinearLayout contentCell = new LinearLayout(context); + contentCell.setOrientation(VERTICAL); - primary[j] = new TextView(context); - title[j] = new TextView(context); + LinearLayout infoLayout = new LinearLayout(context); + infoLayout.setOrientation(HORIZONTAL); + primary[i * 2 + j] = new TextView(context); + title[i * 2 + j] = new TextView(context); - primary[j].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - primary[j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); - title[j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + primary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); + title[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + title[i * 2 + j].setGravity(Gravity.LEFT); - contentCell.addView(primary[j]); - contentCell.addView(title[j]); - linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); + infoLayout.addView(primary[i * 2 + j]); + + contentCell.addView(infoLayout); + contentCell.addView(title[i * 2 + j]); + linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); + } + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, i == 0 ? 16 : 0)); } - addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } public void setData() { - primary[0].setText(AndroidUtilities.formatWholeNumber(messageObject.messageOwner.views, 0)); - title[0].setText(LocaleController.getString("StatisticViews", R.string.StatisticViews)); - - if (publicChats > 0) { - cell[1].setVisibility(View.VISIBLE); - primary[1].setText(AndroidUtilities.formatWholeNumber(publicChats, 0)); - title[1].setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); + int views; + int forwards; + int reactions; + + if (recentPostInfo != null) { + views = recentPostInfo.getViews(); + forwards = recentPostInfo.getForwards(); + reactions = recentPostInfo.getReactions(); } else { - cell[1].setVisibility(View.GONE); + views = messageObject.isStory() ? messageObject.storyItem.views.views_count : messageObject.messageOwner.views; + forwards = messageObject.isStory() ? messageObject.storyItem.views.forwards_count : messageObject.messageOwner.forwards; + reactions = 0; + if (messageObject.isStory()) { + reactions = messageObject.storyItem.views.reactions_count; + } else { + if (messageObject.messageOwner.reactions != null) { + for (int i = 0; i < messageObject.messageOwner.reactions.results.size(); i++) { + reactions += messageObject.messageOwner.reactions.results.get(i).count; + } + } + } } - int privateChats = messageObject.messageOwner.forwards - publicChats; - if (privateChats > 0) { - cell[2].setVisibility(View.VISIBLE); - primary[2].setText(AndroidUtilities.formatWholeNumber(privateChats, 0)); - title[2].setText(LocaleController.formatString("PrivateShares", R.string.PrivateShares)); - } else { - cell[2].setVisibility(View.GONE); + primary[0].setText(AndroidUtilities.formatWholeNumber(views, 0)); + title[0].setText(LocaleController.getString("StatisticViews", R.string.StatisticViews)); + + primary[1].setText(AndroidUtilities.formatWholeNumber(publicChats, 0)); + title[1].setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); + + primary[2].setText(AndroidUtilities.formatWholeNumber(reactions, 0)); + title[2].setText(LocaleController.formatString("Reactions", R.string.Reactions)); + + boolean isReactionsNotVisible = chat != null && chat.available_reactions instanceof TLRPC.TL_chatReactionsNone && reactions == 0; + if (isReactionsNotVisible) { + ((ViewGroup) title[2].getParent()).setVisibility(GONE); } + int privateChats = Math.max(0, forwards - publicChats); + primary[3].setText(AndroidUtilities.formatWholeNumber(privateChats, 0)); + title[3].setText(LocaleController.formatString("PrivateShares", R.string.PrivateShares)); + updateColors(); } private void updateColors() { - for (int i = 0; i < 3; i++) { - primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + for (int i = 0; i < 4; i++) { + primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, getResourceProvider())); + title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, getResourceProvider())); } } } @@ -923,7 +1171,7 @@ public ArrayList getThemeDescriptions() { sharedUi.invalidate(); } - avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); }; themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); @@ -959,6 +1207,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_actionBarDefaultSubmenuItemIcon)); StatisticActivity.putColorFromData(interactionsViewData, themeDescriptions, cellDelegate); + StatisticActivity.putColorFromData(reactionsByEmotionData, themeDescriptions, cellDelegate); return themeDescriptions; } @@ -967,10 +1216,10 @@ private void recolorRecyclerItem(View child) { ((ManageChatUserCell) child).update(0); } else if (child instanceof StatisticActivity.BaseChartCell) { ((StatisticActivity.BaseChartCell) child).recolor(); - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } else if (child instanceof ShadowSectionCell) { Drawable shadowDrawable = Theme.getThemedDrawableByKey(ApplicationLoader.applicationContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); - Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider())); CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); combinedDrawable.setFullsize(true); child.setBackground(combinedDrawable); @@ -978,10 +1227,16 @@ private void recolorRecyclerItem(View child) { ((ChartHeaderView) child).recolor(); } else if (child instanceof OverviewCell) { ((OverviewCell) child).updateColors(); - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } if (child instanceof EmptyCell) { - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider()); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java index fc9795c1ef..445e1b22dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java @@ -1,65 +1,80 @@ package org.telegram.ui; -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; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.Drawable; -import android.icu.util.Measure; import android.os.Build; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.util.Log; +import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.ThemePreviewMessagesCell; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; @@ -68,13 +83,20 @@ import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; +import org.telegram.ui.Components.FilledTabsView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SimpleThemeDescription; import org.telegram.ui.Components.Text; +import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.Stories.StoriesUtilities; import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -86,361 +108,973 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private final long dialogId; private FrameLayout contentView; - private RecyclerListView listView; - private RecyclerView.Adapter listAdapter; - private FrameLayout buttonContainer; - private ButtonWithCounterView button; - private PeerColorGrid peerColorPicker; - - private int selectedColor; - private long selectedEmoji; - private ThemePreviewMessagesCell messagesCellPreview; - private SetReplyIconCell setReplyIconCell; - - private CharSequence buttonLocked, buttonUnlocked; - - int previewRow; - int colorPickerRow; - int infoRow; - int iconRow; - int info2Row; - int buttonRow; - - int rowCount; - - private static final int VIEW_TYPE_MESSAGE = 0; - 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; + private ColoredActionBar colorBar; - public PeerColorActivity(long dialogId) { - super(); + public static final int PAGE_NAME = 0; + public static final int PAGE_PROFILE = 1; - this.dialogId = dialogId; - this.isChannel = dialogId != 0; - } + public Page namePage; + public Page profilePage; - private BaseFragment bulletinFragment; - public PeerColorActivity setOnApplied(BaseFragment bulletinFragment) { - this.bulletinFragment = bulletinFragment; - return this; + public Page getCurrentPage() { + return viewPager.getCurrentPosition() == 0 ? namePage : profilePage; } - @Override - public boolean onFragmentCreate() { - getNotificationCenter().addObserver(this, NotificationCenter.currentUserPremiumStatusChanged); - Bulletin.addDelegate(this, new Bulletin.Delegate() { - @Override - public int getBottomOffset(int tag) { - return dp(62); - } + public boolean loading; - @Override - public boolean clipWithGradient(int tag) { - return true; + private class Page extends FrameLayout { + + private ProfilePreview profilePreview; + + private RecyclerListView listView; + private RecyclerView.Adapter listAdapter; + private FrameLayout buttonContainer; + private ButtonWithCounterView button; + private PeerColorGrid peerColorPicker; + + private int selectedColor = -1; + private long selectedEmoji = 0; + private ThemePreviewMessagesCell messagesCellPreview; + private SetReplyIconCell setReplyIconCell; + + private CharSequence buttonLocked, buttonUnlocked; + + int previewRow = -1; + int colorPickerRow = -1; + int infoRow = -1; + int iconRow = -1; + int info2Row = -1; + int buttonRow = -1; + int clearRow = -1; + int shadowRow = -1; + int rowCount; + + private static final int VIEW_TYPE_MESSAGE = 0; + 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; + private static final int VIEW_TYPE_TEXT = 6; + + private final int type; + public Page(Context context, int type) { + super(context); + this.type = type; + + if (type == PAGE_PROFILE) { + if (dialogId < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + selectedColor = ChatObject.getProfileColorId(chat); + selectedEmoji = ChatObject.getProfileEmojiId(chat); + } else { + TLRPC.User user = getUserConfig().getCurrentUser(); + selectedColor = UserObject.getProfileColorId(user); + selectedEmoji = UserObject.getProfileEmojiId(user); + } + } else { + if (dialogId < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + selectedColor = ChatObject.getColorId(chat); + selectedEmoji = ChatObject.getEmojiId(chat); + } else { + TLRPC.User user = getUserConfig().getCurrentUser(); + selectedColor = UserObject.getColorId(user); + selectedEmoji = UserObject.getEmojiId(user); + } } - }); - getMediaDataController().loadReplyIcons(); - if (MessagesController.getInstance(currentAccount).peerColors == null && BuildVars.DEBUG_PRIVATE_VERSION) { - MessagesController.getInstance(currentAccount).loadAppConfig(true); - } - return super.onFragmentCreate(); - } - @Override - public View createView(Context context) { - actionBar.setTitle(LocaleController.getString(isChannel ? R.string.ChannelColorTitle : R.string.UserColorTitle)); - actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setAllowOverlayTitle(true); + listView = new RecyclerListView(getContext(), getResourceProvider()) { + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, heightSpec); + updateButtonY(); + } - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { - @Override - public void onItemClick(int id) { - if (id == -1) { - if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { - showUnsavedAlert(); - return; + @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(getContext())); + listView.setAdapter(listAdapter = new RecyclerListView.SelectionAdapter() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_ICON || holder.getItemViewType() == VIEW_TYPE_TEXT; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_MESSAGE: + ThemePreviewMessagesCell messagesCell = messagesCellPreview = new ThemePreviewMessagesCell(getContext(), parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId, resourceProvider); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + messagesCell.fragment = PeerColorActivity.this; + view = messagesCell; + break; + default: + case VIEW_TYPE_INFO: + TextInfoPrivacyCell cell = new TextInfoPrivacyCell(getContext(), getResourceProvider()); + view = cell; + break; + case VIEW_TYPE_COLOR_PICKER: + PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(getContext(), type, currentAccount); + colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + colorPicker.setSelected(selectedColor); + colorPicker.setOnColorClick(colorId -> { + selectedColor = colorId; + colorPicker.setSelected(colorId); + updateMessages(); + if (setReplyIconCell != null) { + setReplyIconCell.invalidate(); + } + if (type == PAGE_PROFILE && colorBar != null) { + colorBar.setColor(selectedColor, true); + } + if (profilePreview != null) { + profilePreview.setColor(selectedColor, true); + } + checkResetColorButton(); + }); + view = colorPicker; + break; + case VIEW_TYPE_BUTTONPAD: + view = new View(getContext()) { + @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(getContext()); + setcell.update(false); + view = setcell; + break; + case VIEW_TYPE_TEXT: + TextCell textCell = new TextCell(getContext(), getResourceProvider()); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + break; + case 4: + view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(16), MeasureSpec.EXACTLY) + ); + } + }; + view.setBackground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + break; } - finishFragment(); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + switch (getItemViewType(position)) { + case VIEW_TYPE_INFO: + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + if (position == infoRow) { + if (type == PAGE_NAME) { + cell.setText(LocaleController.getString(isChannel ? R.string.ChannelColorHint : R.string.UserColorHint)); + } else { + cell.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileHint : R.string.UserProfileHint)); + } + cell.setBackground(Theme.getThemedDrawableByKey(getContext(), clearRow >= 0 ? R.drawable.greydivider : R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (position == shadowRow) { + cell.setText(""); + cell.setBackground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } + break; + case VIEW_TYPE_TEXT: + TextCell textCell = (TextCell) holder.itemView; + textCell.updateColors(); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + if (position == clearRow) { + textCell.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileColorReset : R.string.UserProfileColorReset), false); + } + break; + } + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public int getItemViewType(int position) { + if (position == previewRow) { + return VIEW_TYPE_MESSAGE; + } + if (position == infoRow || position == info2Row || position == shadowRow) { + return VIEW_TYPE_INFO; + } + if (position == colorPickerRow) { + return VIEW_TYPE_COLOR_PICKER; + } + if (position == iconRow) { + return VIEW_TYPE_ICON; + } + if (position == buttonRow) { + return VIEW_TYPE_BUTTONPAD; + } + if (position == clearRow) { + return VIEW_TYPE_TEXT; + } + if (position == getItemCount() - 1) { + return 4; + } + return VIEW_TYPE_INFO; + } + }); + listView.setOnItemClickListener((view, position) -> { + if (view instanceof SetReplyIconCell) { + showSelectStatusDialog((SetReplyIconCell) view); + } else if (position == clearRow) { + selectedColor = -1; + selectedEmoji = 0; + if (peerColorPicker != null) { + peerColorPicker.setSelected(selectedColor); + } + updateMessages(); + if (type == PAGE_PROFILE) { + namePage.updateMessages(); + } + if (setReplyIconCell != null) { + setReplyIconCell.update(true); + } + if (type == PAGE_PROFILE && colorBar != null) { + colorBar.setColor(selectedColor, true); + } + if (profilePreview != null) { + profilePreview.setColor(selectedColor, true); + profilePreview.setEmoji(selectedEmoji, true); + } + checkResetColorButton(); + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + buttonContainer = new FrameLayout(getContext()); + buttonContainer.setPadding(dp(14), dp(14), dp(14), dp(14)); + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + + SpannableStringBuilder buttonLock = new SpannableStringBuilder("l"); + buttonLock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + buttonUnlocked = LocaleController.getString(isChannel ? R.string.ChannelColorApply : R.string.UserColorApplyIcon); + buttonLocked = new SpannableStringBuilder(buttonLock).append(" ").append(buttonUnlocked); + + button = new ButtonWithCounterView(getContext(), getResourceProvider()); + button.text.setHacks(true, true, true); + button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), false); + button.setOnClickListener(v -> buttonClick()); + buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + + 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(); } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); + + if (type == PAGE_PROFILE) { + profilePreview = new ProfilePreview(getContext()); + profilePreview.setColor(selectedColor, false); + profilePreview.setEmoji(selectedEmoji, false); + addView(profilePreview, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); } - }); - if (dialogId < 0) { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if ((chat.flags2 & 32) != 0) { - selectedEmoji = chat.background_emoji_id; + updateColors(); + updateRows(); + + setWillNotDraw(false); + } + + private int actionBarHeight; + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getParentLayout() != null) { + getParentLayout().drawHeaderShadow(canvas, actionBarHeight); } - if ((chat.flags2 & 64) != 0) { - selectedColor = chat.color; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (type == PAGE_NAME) { + actionBarHeight = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; } else { - selectedColor = (int) (chat.id % 7); - } - } else { - TLRPC.User user = getUserConfig().getCurrentUser(); - if ((user.flags2 & 64) != 0) { - selectedEmoji = user.background_emoji_id; + actionBarHeight = dp(144) + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; + ((MarginLayoutParams) profilePreview.getLayoutParams()).height = actionBarHeight; } - if ((user.flags2 & 128) != 0) { - selectedColor = user.color; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public boolean hasUnsavedChanged() { + if (isChannel) { + final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat == null) return false; + if (type == PAGE_NAME) { + return !(selectedColor == ChatObject.getColorId(chat) && selectedEmoji == ChatObject.getEmojiId(chat)); + } else { + return !(selectedColor == ChatObject.getProfileColorId(chat) && selectedEmoji == ChatObject.getProfileEmojiId(chat)); + } } else { - selectedColor = (int) (user.id % 7); + final TLRPC.User me = getUserConfig().getCurrentUser(); + if (me == null) return false; + if (type == PAGE_NAME) { + return !(selectedColor == UserObject.getColorId(me) && selectedEmoji == UserObject.getEmojiId(me)); + } else { + return !(selectedColor == UserObject.getProfileColorId(me) && selectedEmoji == UserObject.getProfileEmojiId(me)); + } + } + } + + 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 (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool()) { - selectedColor = NaConfig.INSTANCE.getUseLocalQuoteColorColor().Int(); - selectedEmoji = NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().Long(); + if (!foundLastPosition) { + maxTop = listView.getMeasuredHeight(); } + buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14)))); } - FrameLayout frameLayout = new FrameLayout(context); - listView = new RecyclerListView(context) { - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - super.onMeasure(widthSpec, heightSpec); - updateButtonY(); + private class SetReplyIconCell extends FrameLayout { + + private TextView textView; + private Text offText; + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; + + public SetReplyIconCell(Context context) { + super(context); + + setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + if (type == PAGE_NAME) { + textView.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIcon : R.string.UserReplyIcon)); + } else { + textView.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileIcon : R.string.UserProfileIcon)); + } + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 48, 0)); + + imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - updateButtonY(); + public void updateColors() { + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); } - }; - ((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_ICON; + + public void update(boolean animated) { + if (selectedEmoji != 0) { + imageDrawable.set(selectedEmoji, animated); + offText = null; + } else { + imageDrawable.set((Drawable) null, animated); + if (offText == null) { + offText = new Text(LocaleController.getString(isChannel ? R.string.ChannelReplyIconOff : R.string.UserReplyIconOff), 16); + } + } + } + + public void updateImageBounds() { + imageDrawable.setBounds( + getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), + (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, + getWidth() - dp(21), + (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 + ); } - @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case VIEW_TYPE_MESSAGE: - ThemePreviewMessagesCell messagesCell = messagesCellPreview = new ThemePreviewMessagesCell(context, parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - } - messagesCell.fragment = PeerColorActivity.this; - view = messagesCell; - break; - default: - case VIEW_TYPE_INFO: - TextInfoPrivacyCell cell = new TextInfoPrivacyCell(context); - view = cell; - break; - case VIEW_TYPE_COLOR_PICKER: - PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(context, currentAccount); - colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); - colorPicker.setSelected(selectedColor); - colorPicker.setOnColorClick(colorId -> { - selectedColor = colorId; - colorPicker.setSelected(colorId); - updateMessages(); - if (setReplyIconCell != null) { - setReplyIconCell.invalidate(); - } - }); - 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); - view = setcell; - break; - case 4: - view = new View(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(16), MeasureSpec.EXACTLY) - ); - } - }; - view.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - break; + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + updateImageBounds(); + imageDrawable.setColor(getColor()); + if (offText != null) { + offText.draw(canvas, getMeasuredWidth() - offText.getWidth() - dp(19), getMeasuredHeight() / 2f, getThemedColor(Theme.key_windowBackgroundWhiteBlueText4), 1f); + } else { + imageDrawable.draw(canvas); } - return new RecyclerListView.Holder(view); } - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - switch (getItemViewType(position)) { - case VIEW_TYPE_INFO: - TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; - if (position == infoRow) { - cell.setText(LocaleController.getString(isChannel ? R.string.ChannelColorHint : R.string.UserColorHint)); - cell.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); - } else if (position == info2Row) { - cell.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIconHint : R.string.UserReplyIconHint)); - cell.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + public int getColor() { + if (selectedColor < 0) { + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + return Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + return Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f); + } else { + return Theme.blendOver(Theme.getColor(Theme.key_windowBackgroundWhite, resourceProvider), Theme.multAlpha(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider)), .7f)); + } + } else if (selectedColor < 7) { + return getThemedColor(Theme.keys_avatar_nameInMessage[selectedColor]); + } else { + MessagesController.PeerColors peerColors = type == PAGE_NAME ? MessagesController.getInstance(currentAccount).peerColors : MessagesController.getInstance(currentAccount).profilePeerColors; + if (peerColors != null) { + MessagesController.PeerColor color = peerColors.getColor(selectedColor); + if (color != null) { + return color.getColor1(); } + } } + return getThemedColor(Theme.keys_avatar_nameInMessage[0]); } @Override - public int getItemCount() { - return rowCount; + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY) + ); } @Override - public int getItemViewType(int position) { - if (position == previewRow) { - return VIEW_TYPE_MESSAGE; - } - if (position == infoRow || position == info2Row) { - return VIEW_TYPE_INFO; - } - if (position == colorPickerRow) { - return VIEW_TYPE_COLOR_PICKER; + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + imageDrawable.detach(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + imageDrawable.attach(); + } + } + + private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; + public void showSelectStatusDialog(SetReplyIconCell cell) { + if (selectAnimatedEmojiDialog != null || cell == null) { + return; + } + final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; + int xoff = 0, yoff = 0; + + AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; + View scrimDrawableParent = null; + final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); + final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); + if (cell != null) { + scrimDrawable = cell.imageDrawable; + scrimDrawableParent = cell; + if (cell.imageDrawable != null) { + cell.imageDrawable.play(); + cell.updateImageBounds(); + AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); + if (type == PAGE_NAME) { + yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; + } else { + yoff = -(cell.getHeight() - AndroidUtilities.rectTmp2.centerY()) - AndroidUtilities.dp(16); + } + xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); } - if (position == iconRow) { - return VIEW_TYPE_ICON; + } + SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(PeerColorActivity.this, getContext(), true, xoff, type == PAGE_NAME ? SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON : SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM, true, getResourceProvider(), type == PAGE_NAME ? 24 : 16, cell.getColor()) { + @Override + protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { + selectedEmoji = documentId == null ? 0 : documentId; + if (cell != null) { + cell.update(true); + } + if (profilePreview != null) { + profilePreview.setEmoji(selectedEmoji, true); + } + updateMessages(); + if (popup[0] != null) { + selectAnimatedEmojiDialog = null; + popup[0].dismiss(); + } } - if (position == buttonRow) { - return VIEW_TYPE_BUTTONPAD; + + @Override + protected float getScrimDrawableTranslationY() { + return 0; } - if (position == getItemCount() - 1) { - return 4; + }; + popupLayout.useAccentForPlus = true; + popupLayout.setSelected(selectedEmoji == 0 ? null : selectedEmoji); + popupLayout.setSaveState(3); + popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); + popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + selectAnimatedEmojiDialog = null; } - return VIEW_TYPE_INFO; + }; + popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); + popup[0].dimBehind(); + } + + public void checkResetColorButton() { + if (type != PAGE_PROFILE) { + return; } - }); - listView.setOnItemClickListener((view, position) -> { - if (view instanceof SetReplyIconCell) { - showSelectStatusDialog((SetReplyIconCell) view); + final int wasIndex = clearRow; + updateRows(); + if (wasIndex >= 0 && clearRow < 0) { + listAdapter.notifyItemRangeRemoved(wasIndex, 2); + } else if (wasIndex < 0 && clearRow >= 0) { + listAdapter.notifyItemRangeInserted(clearRow, 2); } - }); - frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } - buttonContainer = new FrameLayout(context); - buttonContainer.setPadding(dp(14), dp(14), dp(14), dp(14)); - buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + private void updateRows() { + rowCount = 0; + if (type == PAGE_NAME) { + previewRow = rowCount++; + } + colorPickerRow = rowCount++; + iconRow = rowCount++; + infoRow = rowCount++; + if (type == PAGE_PROFILE && selectedColor >= 0) { + clearRow = rowCount++; + shadowRow = rowCount++; + } else { + clearRow = -1; + shadowRow = -1; + } + buttonRow = rowCount++; + } - SpannableStringBuilder buttonLock = new SpannableStringBuilder("l"); - buttonLock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - buttonUnlocked = LocaleController.getString(isChannel ? R.string.ChannelColorApply : R.string.UserColorApplyIcon); - buttonLocked = new SpannableStringBuilder(buttonLock).append(" ").append(buttonUnlocked); + private void updateMessages() { + if (messagesCellPreview != null) { + ChatMessageCell[] cells = messagesCellPreview.getCells(); + for (int i = 0; i < cells.length; ++i) { + if (cells[i] != null) { + MessageObject msg = cells[i].getMessageObject(); + if (msg != null) { + if (peerColorPicker != null) { + msg.overrideLinkColor = peerColorPicker.getColorId(); + } + if (profilePage != null && profilePage.selectedColor >= 0 && getMessagesController().profilePeerColors != null) { + msg.overrideProfilePeerColor = getMessagesController().profilePeerColors.getColor(profilePage.selectedColor); + } else { + msg.overrideProfilePeerColor = null; + } + msg.overrideLinkEmoji = selectedEmoji; + cells[i].setAvatar(msg); + cells[i].invalidate(); + } + } + } + } + } - button = new ButtonWithCounterView(context, getResourceProvider()); - button.text.setHacks(true, true, true); - button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), false); - button.setOnClickListener(v -> buttonClick()); - buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + public void updateColors() { + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + if (type == PAGE_PROFILE && colorBar != null) { + colorBar.setColor(selectedColor, true); + } + if (button != null) { + button.updateColors(); + } + if (messagesCellPreview != null) { + messagesCellPreview.invalidate(); + } + if (profilePreview != null) { + profilePreview.setColor(selectedColor, false); + } + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof PeerColorGrid) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((PeerColorGrid) view).updateColors(); + } else if (view instanceof TextCell) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((TextCell) view).updateColors(); + } else if (view instanceof SetReplyIconCell) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((SetReplyIconCell) view).updateColors(); + } + }); + } - 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(); + public void premiumChanged() { + if (button != null && !isChannel) { + button.setText(!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked, true); } - }); + } + } - fragmentView = contentView = frameLayout; + private Theme.ResourcesProvider parentResourcesProvider; + private final SparseIntArray currentColors = new SparseIntArray(); + private final Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; - updateColors(); - updateRows(); + public void updateThemeColors() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("themeconfig", Activity.MODE_PRIVATE); + String dayThemeName = preferences.getString("lastDayTheme", "Blue"); + if (Theme.getTheme(dayThemeName) == null || Theme.getTheme(dayThemeName).isDark()) { + dayThemeName = "Blue"; + } + String nightThemeName = preferences.getString("lastDarkTheme", "Dark Blue"); + if (Theme.getTheme(nightThemeName) == null || !Theme.getTheme(nightThemeName).isDark()) { + nightThemeName = "Dark Blue"; + } + Theme.ThemeInfo themeInfo = Theme.getActiveTheme(); + if (dayThemeName.equals(nightThemeName)) { + if (themeInfo.isDark() || dayThemeName.equals("Dark Blue") || dayThemeName.equals("Night")) { + dayThemeName = "Blue"; + } else { + nightThemeName = "Dark Blue"; + } + } - return contentView; - } + if (isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } - private void updateButtonY() { - if (buttonContainer == null) { - return; + currentColors.clear(); + final String[] wallpaperLink = new String[1]; + final SparseIntArray themeColors; + if (themeInfo.assetName != null) { + themeColors = Theme.getThemeFileValues(null, themeInfo.assetName, wallpaperLink); + } else { + themeColors = Theme.getThemeFileValues(new File(themeInfo.pathToFile), null, wallpaperLink); } - 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; - } + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); } } - if (!foundLastPosition) { - maxTop = listView.getMeasuredHeight(); + if (themeColors != null) { + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } } - 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) { - getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { - if (getContext() == null) { - return; - } - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_COLOR, currentAccount, getResourceProvider()); - limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); - limitReachedBottomSheet.setBoostsStats(boostsStatus, true); - limitReachedBottomSheet.setDialogId(dialogId); - limitReachedBottomSheet.showStatisticButtonInLink(() -> { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); - }); - showDialog(limitReachedBottomSheet); - AndroidUtilities.runOnUIThread(() -> button.setLoading(false), 300); - }); + if (namePage != null && namePage.messagesCellPreview != null) { + if (Theme.isCurrentThemeDark() == isDark) { + namePage.messagesCellPreview.setOverrideBackground(null); } else { - apply(); + Theme.BackgroundDrawableSettings bg = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink[0], 0, true); + namePage.messagesCellPreview.setOverrideBackground(bg.themedWallpaper != null ? bg.themedWallpaper : bg.wallpaper); } - }); + } + } + + public PeerColorActivity(long dialogId) { + super(); + + this.dialogId = dialogId; + this.isChannel = dialogId != 0; + + resourceProvider = new Theme.ResourcesProvider() { + @Override + public int getColor(int key) { + int index = currentColors.indexOfKey(key); + if (index >= 0) { + return currentColors.valueAt(index); + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getColor(key); + } + return Theme.getColor(key); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (drawableKey.equals(Theme.key_drawable_msgIn)) { + return msgInDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgInSelected)) { + return msgInDrawableSelected; + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getDrawable(drawableKey); + } + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public Paint getPaint(String paintKey) { + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public boolean isDark() { + return isDark; + } + }; + msgInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, false, resourceProvider); + msgInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, true, resourceProvider); } @Override - public boolean onBackPressed() { - if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { - showUnsavedAlert(); - return false; + public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + parentResourcesProvider = resourceProvider; + } + + private boolean startAtProfile; + public PeerColorActivity startOnProfile() { + this.startAtProfile = true; + return this; + } + + private BaseFragment bulletinFragment; + public PeerColorActivity setOnApplied(BaseFragment bulletinFragment) { + this.bulletinFragment = bulletinFragment; + return this; + } + + @Override + public boolean onFragmentCreate() { + getNotificationCenter().addObserver(this, NotificationCenter.currentUserPremiumStatusChanged); + Bulletin.addDelegate(this, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return dp(62); + } + + @Override + public boolean clipWithGradient(int tag) { + return true; + } + }); + getMediaDataController().loadReplyIcons(); + if (MessagesController.getInstance(currentAccount).peerColors == null && BuildVars.DEBUG_PRIVATE_VERSION) { + MessagesController.getInstance(currentAccount).loadAppConfig(true); } - return super.onBackPressed(); + return super.onFragmentCreate(); } - public boolean hasUnsavedChanged() { - if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat == null) { - return false; + private ViewPagerFixed viewPager; + + private ImageView backButton; + private ImageView dayNightItem; + + private FrameLayout actionBarContainer; + private FilledTabsView tabsView; + private SimpleTextView titleView; + + @Override + public View createView(Context context) { + + namePage = new Page(context, PAGE_NAME); + profilePage = new Page(context, PAGE_PROFILE); + + actionBar.setCastShadows(false); + actionBar.setVisibility(View.GONE); + actionBar.setAllowOverlayTitle(false); + + FrameLayout frameLayout = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (actionBarContainer != null) { + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).height = ActionBar.getCurrentActionBarHeight(); + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).topMargin = AndroidUtilities.statusBarHeight; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - if (selectedColor == chat.color && selectedEmoji == ((chat.flags2 & 64) == 0 ? 0 : chat.background_emoji_id)) { - return false; + }; + frameLayout.setFitsSystemWindows(true); + + colorBar = new ColoredActionBar(context); + if (profilePage != null) { + colorBar.setColor(profilePage.selectedColor, false); + } + frameLayout.addView(colorBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + + viewPager = new ViewPagerFixed(context) { + @Override + protected void onTabAnimationUpdate(boolean manual) { + tabsView.setSelected(viewPager.getPositionAnimated()); + colorBar.setProgressToGradient(viewPager.getPositionAnimated()); } - return true; + }; + viewPager.setAdapter(new ViewPagerFixed.Adapter() { + @Override + public int getItemCount() { + return isChannel ? 1 : 2; + } + + @Override + public View createView(int viewType) { + if (viewType == PAGE_NAME) return namePage; + if (viewType == PAGE_PROFILE) return profilePage; + return null; + } + + @Override + public int getItemViewType(int position) { + return position; + } + + @Override + public void bindView(View view, int position, int viewType) { + + } + }); + frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + + actionBarContainer = new FrameLayout(context); + frameLayout.addView(actionBarContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + + if (!isChannel) { + tabsView = new FilledTabsView(context); + tabsView.setTabs( + LocaleController.getString(isChannel ? R.string.ChannelColorTabName : R.string.UserColorTabName), + LocaleController.getString(isChannel ? R.string.ChannelColorTabProfile : R.string.UserColorTabProfile) + ); + tabsView.onTabSelected(tab -> { + if (viewPager != null) { + viewPager.scrollToPosition(tab); + } + }); + actionBarContainer.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.CENTER)); } else { - final TLRPC.User me = getUserConfig().getCurrentUser(); - if (selectedColor == me.color && selectedEmoji == ((me.flags2 & 64) == 0 ? 0 : me.background_emoji_id)) { - return false; + titleView = new SimpleTextView(context); + titleView.setText(LocaleController.getString(R.string.ChannelColorTitle)); + titleView.setEllipsizeByGradient(true); + titleView.setTextSize(20); + titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + actionBarContainer.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT, 72, 0, 72, 0)); + } + if (startAtProfile && !isChannel) { + viewPager.setPosition(1); + if (tabsView != null) { + tabsView.setSelected(1); } - return true; + if (colorBar != null) { + colorBar.setProgressToGradient(1f); + } + } + + backButton = new ImageView(context); + backButton.setScaleType(ImageView.ScaleType.CENTER); + backButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarWhiteSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + backButton.setImageResource(R.drawable.ic_ab_back); + backButton.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + backButton.setOnClickListener(v -> { + if (onBackPressed()) { + finishFragment(); + } + }); + actionBarContainer.addView(backButton, LayoutHelper.createFrame(54, 54, Gravity.LEFT | Gravity.CENTER_VERTICAL)); + + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (!isDark) { + sunDrawable.setCustomEndFrame(0); + sunDrawable.setCurrentFrame(0); + } else { + sunDrawable.setCurrentFrame(35); + sunDrawable.setCustomEndFrame(36); } + sunDrawable.beginApplyLayerColors(); + int color = Theme.getColor(Theme.key_chats_menuName); + sunDrawable.setLayerColor("Sunny.**", color); + sunDrawable.setLayerColor("Path 6.**", color); + sunDrawable.setLayerColor("Path.**", color); + sunDrawable.setLayerColor("Path 5.**", color); + sunDrawable.commitApplyLayerColors(); + + dayNightItem = new ImageView(context); + dayNightItem.setScaleType(ImageView.ScaleType.CENTER); + dayNightItem.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarWhiteSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + dayNightItem.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + dayNightItem.setOnClickListener(v -> { + toggleTheme(); + }); + actionBarContainer.addView(dayNightItem, LayoutHelper.createFrame(54, 54, Gravity.RIGHT | Gravity.CENTER_VERTICAL)); + dayNightItem.setImageDrawable(sunDrawable); + + colorBar.updateColors(); + + fragmentView = contentView = frameLayout; + + return contentView; + } + + private boolean isDark = Theme.isCurrentThemeDark(); + private RLottieDrawable sunDrawable; + + public boolean hasUnsavedChanged() { + return namePage.hasUnsavedChanged() || profilePage.hasUnsavedChanged(); + } + + private void showBoostLimit(boolean error) { + getMessagesController().getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + if (error || boostsStatus.level < getMessagesController().channelColorLevelMin) { + getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + if (getContext() == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_COLOR, currentAccount, getResourceProvider()); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + }; + StatisticActivity fragment = new StatisticActivity(args); + presentFragment(fragment); + }); + showDialog(limitReachedBottomSheet); + loading = false; + AndroidUtilities.runOnUIThread(() -> getCurrentPage().button.setLoading(false), 300); + }); + } else { + apply(); + } + }); + } + + @Override + public boolean onBackPressed() { + if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { + showUnsavedAlert(); + return false; + } + return super.onBackPressed(); } @Override @@ -470,22 +1104,22 @@ private void showUnsavedAlert() { } private void buttonClick() { - if (button.isLoading()) { + if (loading) { return; } if (isChannel) { - button.setLoading(true); + final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (namePage != null && chat != null && namePage.selectedColor == ChatObject.getColorId(chat) && namePage.selectedEmoji == ChatObject.getEmojiId(chat)) { + finishFragment(); + return; + } + loading = true; + getCurrentPage().button.setLoading(true); showBoostLimit(false); return; } else { if (!getUserConfig().isPremium()) { - Bulletin bulletin = BulletinFactory.of(this).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.premiumText(LocaleController.getString(R.string.UserColorApplyPremium), () -> { - presentFragment(new PremiumPreviewFragment("name_color")); - })); - bulletin.getLayout().setPadding(dp(8 + 6), dp(8), dp(8 + 6), dp(8)); - bulletin.show(); - - BotWebViewVibrationEffect.APP_ERROR.vibrate(); + showDialog(new PremiumFeatureBottomSheet(PeerColorActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_NAME_COLOR, true)); return; } } @@ -495,9 +1129,10 @@ private void buttonClick() { showBulletin(); } + private boolean applyingName, applyingProfile; private boolean applying; private void apply() { - if (applying || peerColorPicker == null || !isChannel && !getUserConfig().isPremium()) { + if (applying || !isChannel && !getUserConfig().isPremium()) { return; } @@ -506,7 +1141,9 @@ private void apply() { if (chat == null) { return; } - if (selectedColor == chat.color && selectedEmoji == ((chat.flags2 & 64) == 0 ? 0 : chat.background_emoji_id)) { + if (namePage.selectedColor == ChatObject.getColorId(chat) && namePage.selectedEmoji == ChatObject.getEmojiId(chat)) { + getCurrentPage().button.setLoading(loading = false); + finishFragment(); return; } TLRPC.TL_channels_updateColor req = new TLRPC.TL_channels_updateColor(); @@ -515,18 +1152,20 @@ private void apply() { return; } chat.flags2 |= 64; - req.color = chat.color = selectedColor; - if (selectedEmoji != 0) { - chat.flags2 |= 32; - chat.background_emoji_id = selectedEmoji; + if (chat.color == null) { + chat.color = new TLRPC.TL_peerColor(); + } + chat.flags2 |= 128; + req.color = chat.color.color = namePage.selectedColor; + if (namePage.selectedEmoji != 0) { + chat.color.background_emoji_id = namePage.selectedEmoji; req.flags |= 1; - req.background_emoji_id = selectedEmoji; + req.background_emoji_id = namePage.selectedEmoji; } else { - chat.flags2 &= ~32; - chat.background_emoji_id = 0; + chat.color.background_emoji_id = 0; } - button.setLoading(true); + getCurrentPage().button.setLoading(loading = true); getMessagesController().putChat(chat, false); getUserConfig().saveConfig(true); getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { @@ -539,30 +1178,55 @@ private void apply() { } })); } else { - if (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool()) { - NaConfig.INSTANCE.getUseLocalQuoteColorColor().setConfigInt(selectedColor); - NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().setConfigLong(selectedEmoji); - } final TLRPC.User me = getUserConfig().getCurrentUser(); - if (selectedColor == me.color && selectedEmoji == ((me.flags2 & 64) == 0 ? 0 : me.background_emoji_id)) { - return; + if (me.color == null) { + me.color = new TLRPC.TL_peerColor(); + me.color.color = (int) (me.id % 7); + } + if (namePage.selectedColor != UserObject.getColorId(me) || namePage.selectedEmoji != UserObject.getEmojiId(me)) { + applyingName = true; + TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); + me.flags2 |= 256; + me.color.flags |= 1; + req.flags |= 4; + req.color = me.color.color = namePage.selectedColor; + if (namePage.selectedEmoji != 0) { + req.flags |= 1; + me.color.flags |= 2; + req.background_emoji_id = me.color.background_emoji_id = namePage.selectedEmoji; + } else { + me.color.flags &=~ 2; + me.color.background_emoji_id = 0; + } + getConnectionsManager().sendRequest(req, null); } - TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); - me.flags2 |= 128; - req.color = me.color = selectedColor; - if (selectedEmoji != 0) { - me.flags2 |= 64; - me.background_emoji_id = selectedEmoji; - - req.flags |= 1; - req.background_emoji_id = selectedEmoji; - } else { - me.flags2 &= ~64; - me.background_emoji_id = 0; + if (profilePage.selectedColor != UserObject.getProfileColorId(me) || profilePage.selectedEmoji != UserObject.getProfileEmojiId(me)) { + applyingProfile = true; + if (me.profile_color == null) { + me.profile_color = new TLRPC.TL_peerColor(); + } + TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); + req.for_profile = true; + me.flags2 |= 512; + if (profilePage.selectedColor < 0) { + me.profile_color.flags &=~ 1; + } else { + me.profile_color.flags |= 1; + req.flags |= 4; + req.color = me.profile_color.color = profilePage.selectedColor; + } + if (profilePage.selectedEmoji != 0) { + req.flags |= 1; + me.profile_color.flags |= 2; + req.background_emoji_id = me.profile_color.background_emoji_id = profilePage.selectedEmoji; + } else { + me.profile_color.flags &=~ 2; + me.profile_color.background_emoji_id = 0; + } + getConnectionsManager().sendRequest(req, null); } getMessagesController().putUser(me, false); getUserConfig().saveConfig(true); - getConnectionsManager().sendRequest(req, null); } applying = true; getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_EMOJI_STATUS); @@ -570,493 +1234,96 @@ private void apply() { private void showBulletin() { if (bulletinFragment != null) { - BulletinFactory.of(bulletinFragment).createSimpleBulletin(PeerColorDrawable.from(currentAccount, selectedColor), LocaleController.getString(isChannel ? R.string.ChannelColorApplied : R.string.UserColorApplied)).show(); - bulletinFragment = null; - } - } - - private void updateMessages() { - if (messagesCellPreview != null) { - ChatMessageCell[] cells = messagesCellPreview.getCells(); - for (int i = 0; i < cells.length; ++i) { - if (cells[i] != null) { - MessageObject msg = cells[i].getMessageObject(); - if (msg != null) { - if (peerColorPicker != null) { - msg.overrideLinkColor = peerColorPicker.getColorId(); - } - msg.overrideLinkEmoji = selectedEmoji; - cells[i].setAvatar(msg); - cells[i].invalidate(); - } - } - } - } - } - - @Override - public void onFragmentClosed() { - super.onFragmentClosed(); - Bulletin.removeDelegate(this); - } - - private class SetReplyIconCell extends FrameLayout { - - private TextView textView; - private Text offText; - private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; - - public SetReplyIconCell(Context context) { - super(context); - - setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); - - textView = new TextView(context); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); - textView.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIcon : R.string.UserReplyIcon)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 48, 0)); - - imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); - } - - public void update(boolean animated) { - if (selectedEmoji != 0) { - imageDrawable.set(selectedEmoji, animated); - offText = null; - } else { - imageDrawable.set((Drawable) null, animated); - if (offText == null) { - offText = new Text(LocaleController.getString(isChannel ? R.string.ChannelReplyIconOff : R.string.UserReplyIconOff), 16); - } - } - } - - public void updateImageBounds() { - imageDrawable.setBounds( - getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), - (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, - getWidth() - dp(21), - (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 - ); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - updateImageBounds(); - imageDrawable.setColor(getColor()); - if (offText != null) { - offText.draw(canvas, getMeasuredWidth() - offText.getWidth() - dp(19), getMeasuredHeight() / 2f, getThemedColor(Theme.key_windowBackgroundWhiteBlueText4), 1f); - } else { - imageDrawable.draw(canvas); - } - } - - public int getColor() { - if (selectedColor < 7) { - return getThemedColor(Theme.keys_avatar_nameInMessage[selectedColor]); - } else { - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors != null) { - MessagesController.PeerColor color = peerColors.getColor(selectedColor); - if (color != null) { - return color.getColor1(); - } - } - } - return getThemedColor(Theme.keys_avatar_nameInMessage[0]); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY) - ); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - imageDrawable.detach(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - imageDrawable.attach(); - } - } - - private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; - public void showSelectStatusDialog(SetReplyIconCell cell) { - if (selectAnimatedEmojiDialog != null || cell == null) { - return; - } - final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; - int xoff = 0, yoff = 0; - - AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; - View scrimDrawableParent = null; - final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); - final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); - if (cell != null) { - scrimDrawable = cell.imageDrawable; - scrimDrawableParent = cell; - if (cell.imageDrawable != null) { - cell.imageDrawable.play(); - cell.updateImageBounds(); - AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); - yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; - xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); - } - } - SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, xoff, SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON, true, getResourceProvider(), 24, cell.getColor()) { - @Override - protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - selectedEmoji = documentId == null ? 0 : documentId; - if (cell != null) { - cell.update(true); - } - updateMessages(); - if (popup[0] != null) { - selectAnimatedEmojiDialog = null; - popup[0].dismiss(); - } - } - - @Override - protected float getScrimDrawableTranslationY() { - return 0; - } - }; - popupLayout.useAccentForPlus = true; - popupLayout.setSelected(selectedEmoji == 0 ? null : selectedEmoji); - popupLayout.setSaveState(3); - popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); - popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { - @Override - public void dismiss() { - super.dismiss(); - selectAnimatedEmojiDialog = null; - } - }; - popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); - popup[0].dimBehind(); - } - - private void updateRows() { - rowCount = 0; - previewRow = rowCount++; - colorPickerRow = rowCount++; - iconRow = rowCount++; - infoRow = rowCount++; - buttonRow = rowCount++; - } - - @Override - public void onFragmentDestroy() { - super.onFragmentDestroy(); - getNotificationCenter().removeObserver(this, NotificationCenter.currentUserPremiumStatusChanged); - } - - private List getAvailableReactions() { - return getMediaDataController().getReactionsList(); - } - - @Override - public ArrayList getThemeDescriptions() { - return SimpleThemeDescription.createThemeDescriptions(this::updateColors, - Theme.key_windowBackgroundWhite, - Theme.key_windowBackgroundWhiteBlackText, - Theme.key_windowBackgroundWhiteGrayText2, - Theme.key_listSelector, - Theme.key_windowBackgroundGray, - Theme.key_windowBackgroundWhiteGrayText4, - Theme.key_text_RedRegular, - Theme.key_windowBackgroundChecked, - Theme.key_windowBackgroundCheckText, - Theme.key_switchTrackBlue, - Theme.key_switchTrackBlueChecked, - Theme.key_switchTrackBlueThumb, - Theme.key_switchTrackBlueThumbChecked - ); - } - - @SuppressLint("NotifyDataSetChanged") - private void updateColors() { - contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); - listAdapter.notifyDataSetChanged(); - } - - @SuppressLint("NotifyDataSetChanged") - @Override - public void didReceivedNotification(int id, int account, Object... args) { - if (account != currentAccount) return; - if (id == NotificationCenter.currentUserPremiumStatusChanged) { -// updateRows(); -// listAdapter.notifyDataSetChanged(); - - if (button != null) { - button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), true); - } - } - } - - private static class PeerColorPicker extends RecyclerListView { - private final Theme.ResourcesProvider resourcesProvider; - public final LinearLayoutManager layoutManager; - public final Adapter adapter; - private final int currentAccount; - - private static final int[] order = { // key_avatar_nameInMessageRed, key_avatar_nameInMessageOrange, key_avatar_nameInMessageViolet, key_avatar_nameInMessageGreen, key_avatar_nameInMessageCyan, key_avatar_nameInMessageBlue, key_avatar_nameInMessagePink - 5, // blue - 3, // green - 1, // orange - 0, // red - 2, // violet - 4, // cyan - 6 // pink - }; - - @Override - public boolean onInterceptTouchEvent(MotionEvent e) { - if (getParent() != null && getParent().getParent() != null) { - getParent().getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1) || canScrollHorizontally(1)); - getParent().requestDisallowInterceptTouchEvent(true); - } - return super.onInterceptTouchEvent(e); - } - - @Override - public Integer getSelectorColor(int position) { - return 0; - } - - public PeerColorPicker(Context context, final int currentAccount, Theme.ResourcesProvider resourcesProvider) { - super(context); - this.currentAccount = currentAccount; - this.resourcesProvider = resourcesProvider; - - setPadding(dp(8), dp(8), dp(8), dp(8)); - setClipToPadding(false); - - setAdapter(adapter = new SelectionAdapter() { - @Override - public boolean isEnabled(ViewHolder holder) { - return true; - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new Holder(new ColorCell(context)); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - ColorCell cell = (ColorCell) holder.itemView; - cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); - cell.setSelected(position == selectedPosition, false); - if (position >= 0 && position < Theme.keys_avatar_nameInMessage.length) { - cell.set( - Theme.getColor(Theme.keys_avatar_nameInMessage[order[position]], resourcesProvider) - ); + if (applyingName && (!applyingProfile || getCurrentPage() == namePage)) { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + PeerColorDrawable.from(currentAccount, namePage.selectedColor), + LocaleController.getString(isChannel ? R.string.ChannelColorApplied : R.string.UserColorApplied) + ).show(); + } else if (applyingProfile && (!applyingName || getCurrentPage() == profilePage)) { + if (profilePage.selectedColor < 0) { + if (profilePage.selectedEmoji != 0) { + BulletinFactory.of(bulletinFragment).createStaticEmojiBulletin( + AnimatedEmojiDrawable.findDocument(currentAccount, profilePage.selectedEmoji), + LocaleController.getString(isChannel ? R.string.ChannelProfileColorEmojiApplied : R.string.UserProfileColorEmojiApplied) + ).show(); } else { - position -= Theme.keys_avatar_nameInMessage.length; - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors != null && position >= 0 && position < peerColors.colors.size()) { - cell.set(peerColors.colors.get(position)); - } - } - } - - @Override - public int getItemCount() { - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - return 7 + (peerColors == null ? 0 : peerColors.colors.size()); - } - }); - layoutManager = new LinearLayoutManager(context); - layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); - setLayoutManager(layoutManager); - } - - private int selectedPosition; - public void setSelected(int color) { - setSelectedPosition(toPosition(color)); - } - - public void setSelectedPosition(int position) { - if (position != selectedPosition) { - selectedPosition = position; - AndroidUtilities.forEachViews(this, child -> ((ColorCell) child).setSelected(getChildAdapterPosition(child) == selectedPosition, true)); - } - } - - public int getColorId() { - return toColorId(selectedPosition); - } - - public int toPosition(final int colorId) { - if (colorId >= 0 && colorId < Theme.keys_avatar_nameInMessage.length) { - for (int i = 0; i < order.length; ++i) { - if (order[i] == colorId) { - return i; + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + R.raw.contact_check, + LocaleController.getString(isChannel ? R.string.ChannelProfileColorResetApplied : R.string.UserProfileColorResetApplied) + ).show(); } - } - } - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors == null) { - return 0; - } - for (int i = 0; i < peerColors.colors.size(); ++i) { - if (peerColors.colors.get(i).id == colorId) { - return 7 + i; - } - } - return 0; - } - - public int toColorId(int position) { - if (position >= 0 && position < 7) { - return order[position]; - } - position -= 7; - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors == null || position < 0 || position >= peerColors.colors.size()) { - return 0; - } - return peerColors.colors.get(position).id; - } - - private static class ColorCell extends View { - 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(this); - - public ColorCell(Context context) { - super(context); - 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 (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(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; - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(dp(VIEW_SIZE_DP), dp(VIEW_SIZE_DP)); - - circlePath.rewind(); - circlePath.addCircle(getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, dp(CIRCLE_RADIUS_DP), Path.Direction.CW); - - color2Path.rewind(); - color2Path.moveTo(getMeasuredWidth(), 0); - color2Path.lineTo(getMeasuredWidth(), getMeasuredHeight()); - color2Path.lineTo(0, getMeasuredHeight()); - color2Path.close(); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - canvas.save(); - final float s = bounce.getScale(.05f); - canvas.scale(s, s, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); - - canvas.save(); - canvas.clipPath(circlePath); - canvas.drawPaint(paint1); - if (hasColor2) { - canvas.drawPath(color2Path, paint2); - } - canvas.restore(); - - if (hasColor3) { - canvas.save(); - AndroidUtilities.rectTmp.set( - (getMeasuredWidth() - dp(12.4f)) / 2f, - (getMeasuredHeight() - dp(12.4f)) / 2f, - (getMeasuredWidth() + dp(12.4f)) / 2f, - (getMeasuredHeight() + dp(12.4f)) / 2f - ); - canvas.rotate(45f, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); - canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2.33f), dp(2.33f), paint3); - canvas.restore(); + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + PeerColorDrawable.fromProfile(currentAccount, profilePage.selectedColor), + LocaleController.getString(isChannel ? R.string.ChannelProfileColorApplied : R.string.UserProfileColorApplied) + ).show(); } + } + bulletinFragment = null; + } + } - final float selectT = selectedT.set(selected); + @Override + public void onFragmentClosed() { + super.onFragmentClosed(); + Bulletin.removeDelegate(this); + } - if (selectT > 0) { - backgroundPaint.setStrokeWidth(dpf2(2)); - canvas.drawCircle( - getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, - AndroidUtilities.lerp( - dp(CIRCLE_RADIUS_DP) + backgroundPaint.getStrokeWidth() * .5f, - dp(CIRCLE_RADIUS_DP) - backgroundPaint.getStrokeWidth() * 2f, - selectT - ), - backgroundPaint - ); - } + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + getNotificationCenter().removeObserver(this, NotificationCenter.currentUserPremiumStatusChanged); + } - canvas.restore(); - } + private List getAvailableReactions() { + return getMediaDataController().getReactionsList(); + } - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - bounce.setPressed(pressed); - } + @Override + public ArrayList getThemeDescriptions() { + return SimpleThemeDescription.createThemeDescriptions(this::updateColors, + Theme.key_windowBackgroundWhite, + Theme.key_windowBackgroundWhiteBlackText, + Theme.key_windowBackgroundWhiteGrayText2, + Theme.key_listSelector, + Theme.key_windowBackgroundGray, + Theme.key_windowBackgroundWhiteGrayText4, + Theme.key_text_RedRegular, + Theme.key_windowBackgroundChecked, + Theme.key_windowBackgroundCheckText, + Theme.key_switchTrackBlue, + Theme.key_switchTrackBlueChecked, + Theme.key_switchTrackBlueThumb, + Theme.key_switchTrackBlueThumbChecked + ); + } + + @SuppressLint("NotifyDataSetChanged") + private void updateColors() { + contentView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + if (titleView != null) { + titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + } + namePage.updateColors(); + profilePage.updateColors(); + if (colorBar != null) { + colorBar.updateColors(); + } + setNavigationBarColor(getNavigationBarColor()); + } + + @SuppressLint("NotifyDataSetChanged") + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (account != currentAccount) return; + if (id == NotificationCenter.currentUserPremiumStatusChanged) { + namePage.premiumChanged(); + profilePage.premiumChanged(); } } public static class ChangeNameColorCell extends View { + private final int currentAccount; private final boolean isChannel; private final Theme.ResourcesProvider resourcesProvider; @@ -1068,8 +1335,13 @@ public static class ChangeNameColorCell extends View { private int userTextColorKey = -1; private boolean needDivider; - public ChangeNameColorCell(boolean isChannel, Context context, Theme.ResourcesProvider resourcesProvider) { + private PeerColorDrawable color1Drawable; + private PeerColorDrawable color2Drawable; + + public ChangeNameColorCell(int currentAccount, boolean isChannel, Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + + this.currentAccount = currentAccount; this.isChannel = isChannel; this.resourcesProvider = resourcesProvider; @@ -1099,7 +1371,7 @@ public void set(TLRPC.Chat chat, boolean divider) { text = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), false); userText = new Text(text, 13, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); final int color; - int colorId = chat != null && (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + int colorId = ChatObject.getColorId(chat); if (colorId < 7) { color = Theme.getColor(userTextColorKey = Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { @@ -1114,6 +1386,8 @@ public void set(TLRPC.Chat chat, boolean divider) { } userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); + + color1Drawable = color2Drawable = null; } public void set(TLRPC.User user) { @@ -1129,7 +1403,7 @@ public void set(TLRPC.User user) { text = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), false); userText = new Text(text, 13, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); final int color; - int colorId = user != null && (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + int colorId = UserObject.getColorId(user); if (colorId < 7) { color = Theme.getColor(userTextColorKey = Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { @@ -1144,6 +1418,9 @@ public void set(TLRPC.User user) { } userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); + + color1Drawable = PeerColorDrawable.from(currentAccount, colorId).setRadius(dp(11)); + color2Drawable = UserObject.getProfileColorId(user) >= 0 ? PeerColorDrawable.fromProfile(currentAccount, UserObject.getProfileColorId(user)).setRadius(dp(11)) : null; } @Override @@ -1171,7 +1448,19 @@ protected void dispatchDraw(Canvas canvas) { .ellipsize(getMeasuredWidth() - dp(64 + 7 + 100)) .draw(canvas, LocaleController.isRTL ? getMeasuredWidth() - buttonText.getWidth() - dp(64 + 7) : dp(64 + 7), getMeasuredHeight() / 2f); - if (userText != null) { + if (color1Drawable != null && color2Drawable != null) { + + int x = getMeasuredWidth() - dp(16); + color2Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); + color2Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + color2Drawable.draw(canvas); + + x -= dp(18); + color1Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); + color1Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + color1Drawable.draw(canvas); + + } else if (userText != null) { final int maxWidth = (int) (getMeasuredWidth() - dp(64 + 7 + 15 + 9 + 9 + 12) - Math.min(buttonText.getWidth(), getMeasuredWidth() - dp(64 + 100))); final int w = (int) Math.min(userText.getWidth(), maxWidth); @@ -1184,8 +1473,8 @@ protected void dispatchDraw(Canvas canvas) { canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(12), dp(12), userTextBackgroundPaint); userText - .ellipsize(maxWidth) - .draw(canvas, LocaleController.isRTL ? dp(15 + 9) : getMeasuredWidth() - dp(15 + 9) - w, getMeasuredHeight() / 2f); + .ellipsize(maxWidth) + .draw(canvas, LocaleController.isRTL ? dp(15 + 9) : getMeasuredWidth() - dp(15 + 9) - w, getMeasuredHeight() / 2f); } if (needDivider) { @@ -1198,10 +1487,11 @@ protected void dispatchDraw(Canvas canvas) { } } - public static class PeerColorGrid extends View { + public class PeerColorGrid extends View { + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { backgroundPaint.setStyle(Paint.Style.STROKE); } 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); @@ -1211,13 +1501,7 @@ public class ColorButton { private final ButtonBounce bounce = new ButtonBounce(PeerColorGrid.this); - public ColorButton() { - backgroundPaint.setStyle(Paint.Style.STROKE); - } - - public void setBackgroundColor(int backgroundColor) { - backgroundPaint.setColor(backgroundColor); - } + public ColorButton() {} public void set(int color) { hasColor2 = hasColor3 = false; @@ -1235,16 +1519,24 @@ 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()); + final boolean dark = isDark; + if (type == PAGE_NAME) { + if (dark && color.hasColor2() && !color.hasColor3()) { + paint1.setColor(color.getColor2(dark)); + paint2.setColor(color.getColor1(dark)); + } else { + paint1.setColor(color.getColor1(dark)); + paint2.setColor(color.getColor2(dark)); + } + paint3.setColor(color.getColor3(dark)); + hasColor2 = color.hasColor2(dark); + hasColor3 = color.hasColor3(dark); } else { - paint1.setColor(color.getColor1()); - paint2.setColor(color.getColor2()); + paint1.setColor(color.getColor1(dark)); + paint2.setColor(color.hasColor6(dark) ? color.getColor2(dark) : color.getColor1(dark)); + hasColor2 = color.hasColor6(dark); + hasColor3 = false; } - paint3.setColor(color.getColor3()); - hasColor2 = color.hasColor2(); - hasColor3 = color.hasColor3(); } private boolean selected; @@ -1257,14 +1549,10 @@ public void setSelected(boolean selected, boolean animated) { 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; + public void layout(RectF bounds) { this.bounds.set(bounds); } public void layoutClickBounds(RectF bounds) { @@ -1309,6 +1597,7 @@ protected void draw(Canvas canvas) { if (selectT > 0) { backgroundPaint.setStrokeWidth(dpf2(2)); + backgroundPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhite)); canvas.drawCircle( bounds.centerX(), bounds.centerY(), Math.min(bounds.height() / 2f, bounds.width() / 2f) + backgroundPaint.getStrokeWidth() * AndroidUtilities.lerp(.5f, -2f, selectT), @@ -1329,26 +1618,49 @@ public void setPressed(boolean pressed) { } } - private int currentAccount; + private final int type; + private final int currentAccount; private ColorButton[] buttons; - public PeerColorGrid(Context context, int currentAccount) { + public PeerColorGrid(Context context, int type, int currentAccount) { super(context); + this.type = type; this.currentAccount = currentAccount; } + public void updateColors() { + if (buttons == null) return; + final MessagesController mc = MessagesController.getInstance(currentAccount); + final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; + for (int i = 0; i < buttons.length; ++i) { + if (i < 7 && type == PAGE_NAME) { + buttons[i].id = order[i]; + buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]], resourceProvider)); + } else { + final int id = i - (type == PAGE_NAME ? 7 : 0); + if (peerColors != null && id >= 0 && id < peerColors.colors.size()) { + buttons[i].id = peerColors.colors.get(id).id; + buttons[i].set(peerColors.colors.get(id)); + } + } + } + invalidate(); + } + final int[] order = new int[] { 5, 3, 1, 0, 2, 4, 6 }; + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); - final MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + final MessagesController mc = MessagesController.getInstance(currentAccount); + final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; final int colorsCount = 7 + (peerColors == null ? 0 : peerColors.colors.size()); - final int columns = 7; + final int columns = type == PAGE_NAME ? 7 : 8; final float iconSize = Math.min(dp(38 + 16), width / (columns + (columns + 1) * .28947f)); - final float horizontalSeparator = iconSize * .28947f; - final float verticalSeparator = iconSize * .315789474f; + final float horizontalSeparator = Math.min(iconSize * .28947f, dp(8)); + final float verticalSeparator = Math.min(iconSize * .315789474f, dp(11.33f)); final int rows = colorsCount / columns; final int height = (int) (iconSize * rows + verticalSeparator * (rows + 1)); @@ -1359,11 +1671,15 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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)); + if (i < 7 && type == PAGE_NAME) { + buttons[i].id = order[i]; + buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]])); + } else { + final int id = i - (type == PAGE_NAME ? 7 : 0); + if (peerColors != null && id >= 0 && id < peerColors.colors.size()) { + buttons[i].id = peerColors.colors.get(id).id; + buttons[i].set(peerColors.colors.get(id)); + } } } } @@ -1373,10 +1689,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); + buttons[i].layout(AndroidUtilities.rectTmp); AndroidUtilities.rectTmp.inset(-horizontalSeparator / 2, -verticalSeparator / 2); buttons[i].layoutClickBounds(AndroidUtilities.rectTmp); - buttons[i].setSelected(i == selectedColorId, false); + buttons[i].setSelected(buttons[i].id == selectedColorId, false); if (i % columns == (columns - 1)) { x = startX; @@ -1388,6 +1704,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + @Override protected void dispatchDraw(Canvas canvas) { if (buttons != null) { @@ -1395,7 +1713,8 @@ protected void dispatchDraw(Canvas canvas) { buttons[i].draw(canvas); } } - canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), Theme.dividerPaint); + dividerPaint.setColor(getThemedColor(Theme.key_divider)); + canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), dividerPaint); } private int selectedColorId = 0; @@ -1403,7 +1722,7 @@ public void setSelected(int colorId) { selectedColorId = colorId; if (buttons != null) { for (int i = 0; i < buttons.length; ++i) { - buttons[i].setSelected(i == colorId, true); + buttons[i].setSelected(buttons[i].id == colorId, true); } } } @@ -1476,20 +1795,42 @@ public static PeerColorDrawable from(int currentAccount, int colorId) { } MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); - return from(peerColor); + return from(peerColor, false); + } + + public static PeerColorDrawable fromProfile(int currentAccount, int colorId) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + return from(peerColor, true); } - public static PeerColorDrawable from(MessagesController.PeerColor peerColor) { + public static PeerColorDrawable from(MessagesController.PeerColor peerColor, boolean fromProfile) { if (peerColor == null) { return new PeerColorDrawable(0, 0, 0); } - return new PeerColorDrawable(peerColor.getColor1(), peerColor.getColor2(), peerColor.getColor3()); + return new PeerColorDrawable(peerColor.getColor1(), !fromProfile || peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor2() : peerColor.getColor1(), fromProfile ? peerColor.getColor1() : peerColor.getColor3()); } - private final int diameter = AndroidUtilities.dp(21.333f); - private final int radius = diameter / 2; + private float radius = dpf2(21.333f / 2f); + + public PeerColorDrawable setRadius(float r) { + this.radius = r; + initPath(); + return this; + } + + public PeerColorDrawable stroke(float width, int color) { + if (strokePaint == null) { + strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + strokePaint.setStyle(Paint.Style.STROKE); + } + strokePaint.setStrokeWidth(width); + strokePaint.setColor(color); + return this; + } private final boolean hasColor3; + private Paint strokePaint; private final Paint color1Paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint color2Paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint color3Paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -1502,10 +1843,16 @@ public PeerColorDrawable(int color1, int color2, int color3) { color2Paint.setColor(color2); color3Paint.setColor(color3); + initPath(); + } + + private void initPath() { + clipCirclePath.rewind(); clipCirclePath.addCircle(radius, radius, radius, Path.Direction.CW); - color2Path.moveTo(diameter, 0); - color2Path.lineTo(diameter, diameter); - color2Path.lineTo(0, diameter); + color2Path.rewind(); + color2Path.moveTo(radius * 2, 0); + color2Path.lineTo(radius * 2, radius * 2); + color2Path.lineTo(0, radius * 2); color2Path.close(); } @@ -1513,6 +1860,9 @@ public PeerColorDrawable(int color1, int color2, int color3) { public void draw(@NonNull Canvas canvas) { canvas.save(); canvas.translate(getBounds().centerX() - radius, getBounds().centerY() - radius); + if (strokePaint != null) { + canvas.drawCircle(radius, radius, radius, strokePaint); + } canvas.clipPath(clipCirclePath); canvas.drawPaint(color1Paint); canvas.drawPath(color2Path, color2Paint); @@ -1537,12 +1887,480 @@ public int getOpacity() { @Override public int getIntrinsicHeight() { - return diameter; + return (int) (radius * 2); } @Override public int getIntrinsicWidth() { - return diameter; + return (int) (radius * 2); + } + } + + private class ColoredActionBar extends View { + + private int defaultColor; + public ColoredActionBar(Context context) { + super(context); + defaultColor = getThemedColor(Theme.key_actionBarDefault); + setColor(-1, false); + } + + public void setColor(int colorId, boolean animated) { + isDefault = false; + if (colorId < 0) { + isDefault = true; + color1 = color2 = getThemedColor(Theme.key_actionBarDefault); + } else { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (peerColor != null) { + color1 = peerColor.getBgColor1(isDark); + color2 = peerColor.getBgColor2(isDark); + } else { + isDefault = true; + color1 = color2 = getThemedColor(Theme.key_actionBarDefault); + } + } + if (!animated) { + color1Animated.set(color1, true); + color2Animated.set(color2, true); + } + updateLightStatusBar(); + updateActionBarButtonsColor(); + invalidate(); + } + + private float progressToGradient = 0; + public void setProgressToGradient(float progress) { + if (Math.abs(progressToGradient - progress) > 0.001f) { + progressToGradient = progress; + updateTabsViewBackground(); + updateActionBarButtonsColor(); + updateLightStatusBar(); + invalidate(); + } + } + + public boolean isDefault; + public int color1, color2; + private final AnimatedColor color1Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedColor color2Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private int backgroundGradientColor1, backgroundGradientColor2, backgroundGradientHeight; + private LinearGradient backgroundGradient; + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + final int color1 = color1Animated.set(this.color1); + final int color2 = color2Animated.set(this.color2); + if (backgroundGradient == null || backgroundGradientColor1 != color1 || backgroundGradientColor2 != color2 || backgroundGradientHeight != getHeight()) { + backgroundGradient = new LinearGradient(0, 0, 0, backgroundGradientHeight = getHeight(), new int[] { backgroundGradientColor2 = color2, backgroundGradientColor1 = color1 }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + backgroundPaint.setShader(backgroundGradient); + updateTabsViewBackground(); + updateLightStatusBar(); + } + if (progressToGradient < 1) { + canvas.drawColor(defaultColor); + } + if (progressToGradient > 0) { + backgroundPaint.setAlpha((int) (0xFF * progressToGradient)); + canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.statusBarHeight + dp(144), MeasureSpec.EXACTLY)); + } + + public void updateColors() { + defaultColor = getThemedColor(Theme.key_actionBarDefault); + updateTabsViewBackground(); + updateActionBarButtonsColor(); + updateLightStatusBar(); + invalidate(); + } + + private int lastBtnColor = 0; + public void updateActionBarButtonsColor() { + final int btnColor = ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), isDefault ? getThemedColor(Theme.key_actionBarDefaultIcon) : Color.WHITE, progressToGradient); + if (lastBtnColor != btnColor) { + if (backButton != null) { + lastBtnColor = btnColor; + backButton.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); + } + if (dayNightItem != null) { + lastBtnColor = btnColor; + dayNightItem.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); + } + } + } + + public int getColor() { + return ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefault), ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), progressToGradient); + } + + private void updateTabsViewBackground() { + if (tabsView == null) return; + tabsView.setBackgroundColor( + ColorUtils.blendARGB( + AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .721f ? + getThemedColor(Theme.key_actionBarDefaultIcon) : + Theme.adaptHSV(getThemedColor(Theme.key_actionBarDefault), +.08f, -.08f), + AndroidUtilities.computePerceivedBrightness(ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f)) > .721f ? + getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon) : + Theme.adaptHSV(ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), +.08f, -.08f), + progressToGradient + ) + ); + } + } + + private class ProfilePreview extends FrameLayout { + + private final ImageReceiver imageReceiver = new ImageReceiver(this); + private final AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final SimpleTextView titleView, subtitleView; + + private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(20), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + + private final StoriesUtilities.StoryGradientTools storyGradient = new StoriesUtilities.StoryGradientTools(this, false); + + public ProfilePreview(Context context) { + super(context); + + titleView = new SimpleTextView(context); + titleView.setTextColor(0xFFFFFFFF); + titleView.setTextSize(20); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setScrollNonFitText(true); + addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 97, 0, 16, 50.33f)); + + subtitleView = new SimpleTextView(context); + subtitleView.setTextSize(14); + subtitleView.setTextColor(0x80FFFFFF); + subtitleView.setScrollNonFitText(true); + addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 97, 0, 16, 30.66f)); + + imageReceiver.setRoundRadius(dp(54)); + CharSequence title; + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + title = chat == null ? "" : chat.title; + + avatarDrawable.setInfo(currentAccount, chat); + imageReceiver.setForUserOrChat(chat, avatarDrawable); + } else { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + title = UserObject.getUserName(user); + + avatarDrawable.setInfo(currentAccount, user); + imageReceiver.setForUserOrChat(user, avatarDrawable); + } + try { + title = Emoji.replaceEmoji(title, null, false); + } catch (Exception ignore) {} + + titleView.setText(title); + + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null && chatFull.participants_count > 0) { + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.formatPluralStringComma("Subscribers", chatFull.participants_count)); + } else { + subtitleView.setText(LocaleController.formatPluralStringComma("Members", chatFull.participants_count)); + } + } else if (chat != null && chat.participants_count > 0) { + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.formatPluralStringComma("Subscribers", chat.participants_count)); + } else { + subtitleView.setText(LocaleController.formatPluralStringComma("Members", chat.participants_count)); + } + } else { + final boolean isPublic = ChatObject.isPublic(chat); + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.getString(isPublic ? R.string.ChannelPublic : R.string.ChannelPrivate).toLowerCase()); + } else { + subtitleView.setText(LocaleController.getString(isPublic ? R.string.MegaPublic : R.string.MegaPrivate).toLowerCase()); + } + } + } else { + subtitleView.setText(LocaleController.getString(R.string.Online)); + } + + setWillNotDraw(false); + } + + public void updateAvatarDrawable(MessagesController.PeerColor profilePeerColor) { + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat != null) { + avatarDrawable.setInfo(chat.id, chat.title, null, null, ChatObject.getColorId(chat), profilePeerColor); + } + } else { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + if (user != null) { + avatarDrawable.setInfo(user.id, user.first_name, user.last_name, null, UserObject.getColorId(user), profilePeerColor); + } + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + emoji.attach(); + imageReceiver.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + emoji.detach(); + imageReceiver.onDetachedFromWindow(); + } + + private int lastColorId = -1; + public void setColor(int colorId, boolean animated) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId = colorId); + if (peerColor != null) { + emoji.setColor(adaptProfileEmojiColor(peerColor.getBgColor1(isDark))); + final int accentColor = ColorUtils.blendARGB(peerColor.getStoryColor1(isDark), peerColor.getStoryColor2(isDark), .5f); + if (!Theme.hasHue(getThemedColor(Theme.key_actionBarDefault))) { + subtitleView.setTextColor(accentColor); + } else { + subtitleView.setTextColor(Theme.changeColorAccent(getThemedColor(Theme.key_actionBarDefault), accentColor, getThemedColor(Theme.key_avatar_subtitleInProfileBlue), isDark, accentColor)); + } + titleView.setTextColor(Color.WHITE); + } else { + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + emoji.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider)); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f)); + } else { + emoji.setColor(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider))); + } + subtitleView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubtitle, resourceProvider)); + titleView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider)); + } + updateAvatarDrawable(peerColor); + + storyGradient.setColorId(colorId, animated); + invalidate(); + } + + public void setEmoji(long docId, boolean animated) { + if (docId == 0) { + emoji.set((Drawable) null, animated); + } else { + emoji.set(docId, animated); + } + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId); + if (peerColor != null) { + emoji.setColor(adaptProfileEmojiColor(peerColor.getBgColor1(isDark))); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + emoji.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider)); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f)); + } else { + emoji.setColor(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider))); + } + } + + private final RectF rectF = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rectF.set(dp(20.33f), getHeight() - dp(25.33f + 53.33f), dp(20.33f) + dp(53.33f), getHeight() - dp(25.33f)); + imageReceiver.setImageCoords(rectF); + imageReceiver.draw(canvas); + + canvas.drawCircle(rectF.centerX(), rectF.centerY(), rectF.width() / 2f + dp(4), storyGradient.getPaint(rectF)); + + drawProfileIconPattern(getWidth() - dp(46), getHeight(), 1f, (x, y, sz, alpha) -> { + emoji.setAlpha((int) (0xFF * alpha)); + emoji.setBounds((int) (x - sz * .45f), (int) (y - sz * .45f), (int) (x + sz * .45f), (int) (y + sz * .45f)); + emoji.draw(canvas); + }); + + super.dispatchDraw(canvas); + } + } + + public static int adaptProfileEmojiColor(int color) { + final boolean isDark = AndroidUtilities.computePerceivedBrightness(color) < .2f; + return Theme.adaptHSV(color, +.5f, isDark ? +.28f : -.28f); + } + + public static final float PARTICLE_SIZE_DP = 24; + public static final int PARTICLES_COUNT = 15; + public static final float GOLDEN_RATIO_ANGLE = 139f; + public static final float FILL_SCALE = 1; + + public static void drawSunflowerPattern(float cx, float cy, Utilities.Callback3 draw) { + drawSunflowerPattern(PARTICLES_COUNT, cx, cy, 30, dp(PARTICLE_SIZE_DP) * .7f, 1.4f, GOLDEN_RATIO_ANGLE, draw); + } + + public static void drawSunflowerPattern(int count, float cx, float cy, float anglestart, float scale, float scale2, float angle, Utilities.Callback3 draw) { + for (int i = 1; i <= count; ++i) { + final float a = anglestart + i * angle; + final float r = (float) (Math.sqrt(i * scale2) * scale); + final float x = (float) (cx + Math.cos(a / 180f * Math.PI) * r) + (i == 3 ? .3f * scale : 0); + final float y = (float) (cy + Math.sin(a / 180f * Math.PI) * r) + (i == 3 ? -.5f * scale : 0); + draw.run(x, y, (float) Math.sqrt(1f - (float) i / count)); + } + } + + private final static float[] particles = { + -18, -24.66f, 24, .4f, + 5.33f, -53, 28, .38f, + -4, -86, 19, .18f, + 31, -30, 21, .35f, + 12, -3, 24, .18f, + 30, -73, 19, .3f, + 43, -101, 16, .1f, + -50, 1.33f, 20, .22f, + -58, -33, 24, .22f, + -35, -62, 25, .22f, + -59, -88, 19, .18f, + -86, -61, 19, .1f, + -90, -14.33f, 19.66f, .18f + }; + public static void drawProfileIconPattern(float cx, float cy, float scale, Utilities.Callback4 draw) { + for (int i = 0; i < particles.length; i += 4) { + draw.run( + cx + dp(particles[i]) * scale, + cy + dp(particles[i + 1]) * scale, + dpf2(particles[i + 2]), + particles[i + 3] + ); + } + } + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + @SuppressLint("NotifyDataSetChanged") + public void toggleTheme() { + FrameLayout decorView1 = (FrameLayout) getParentActivity().getWindow().getDecorView(); + Bitmap bitmap = Bitmap.createBitmap(decorView1.getWidth(), decorView1.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + dayNightItem.setAlpha(0f); + decorView1.draw(bitmapCanvas); + dayNightItem.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + dayNightItem.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + dayNightItem.getMeasuredWidth() / 2f; + float cy = y + dayNightItem.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isDark) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + dayNightItem.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setDuration(400); + changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad); + changeDayNightViewAnimator.start(); + + decorView1.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + isDark = !isDark; + updateThemeColors(); + setForceDark(isDark, true); + updateColors(); + }); + } + + @Override + public boolean isLightStatusBar() { + if (colorBar == null) { + return super.isLightStatusBar(); + } + return ColorUtils.calculateLuminance(colorBar.getColor()) > 0.7f; + } + + public void updateLightStatusBar() { + if (getParentActivity() == null) return; + AndroidUtilities.setLightStatusBar(getParentActivity().getWindow(), isLightStatusBar()); + } + + private boolean forceDark = isDark; + public void setForceDark(boolean isDark, boolean playAnimation) { + if (forceDark == isDark) { + return; + } + forceDark = isDark; + if (playAnimation) { + sunDrawable.setCustomEndFrame(isDark ? sunDrawable.getFramesCount() : 0); + if (sunDrawable != null) { + sunDrawable.start(); + } + } else { + int frame = isDark ? sunDrawable.getFramesCount() - 1 : 0; + sunDrawable.setCurrentFrame(frame, false, true); + sunDrawable.setCustomEndFrame(frame); + if (dayNightItem != null) { + dayNightItem.invalidate(); + } } } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index b4c0b0fee4..5d1b642e6e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -7212,7 +7212,7 @@ private void showShareAlert(ArrayList messages) { parentChatActivity.getFragmentView().requestLayout(); } final boolean finalOpenKeyboardOnShareAlertClose = openKeyboardOnShareAlertClose; - ShareAlert alert = new ShareAlert(parentActivity, parentChatActivity, messages, null, null, false, null, null, false, true, null) { + ShareAlert alert = new ShareAlert(parentActivity, parentChatActivity, messages, null, null, false, null, null, false, true, false, null) { @Override protected void onSend(LongSparseArray dids, int count, TLRPC.TL_forumTopic topic) { AndroidUtilities.runOnUIThread(() -> { @@ -13795,8 +13795,10 @@ private void checkProgress(int a, boolean scroll, boolean animated) { return; } ImageLocation location = imagesArrLocationsVideo.get(index); - f1 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), false); - f2 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), true); + if (location != null) { + f1 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), false); + f2 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), true); + } } else if (currentSecureDocument != null) { if (index < 0 || index >= secureDocuments.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index cf4ad88ec5..10c36c1366 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -154,6 +154,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING = 19; public static final int PREMIUM_FEATURE_STORIES_PRIORITY_ORDER = 20; public static final int PREMIUM_FEATURE_STORIES_CAPTION = 21; + public final static int PREMIUM_FEATURE_WALLPAPER = 22; + public final static int PREMIUM_FEATURE_NAME_COLOR = 23; private int statusBarHeight; private int firstViewHeight; @@ -223,6 +225,10 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_STORIES_PRIORITY_ORDER; case "stories__caption": return PREMIUM_FEATURE_STORIES_CAPTION; + case "wallpapers": + return PREMIUM_FEATURE_WALLPAPER; + case "peer_colors": + return PREMIUM_FEATURE_NAME_COLOR; } return -1; } @@ -273,6 +279,10 @@ public static String featureTypeToServerString(int type) { return "stories__priority_order"; case PREMIUM_FEATURE_STORIES_CAPTION: return "stories__caption"; + case PREMIUM_FEATURE_WALLPAPER: + return "wallpapers"; + case PREMIUM_FEATURE_NAME_COLOR: + return "peer_colors"; } return null; } @@ -347,7 +357,7 @@ public View createView(Context context) { public boolean dispatchTouchEvent(MotionEvent ev) { float iconX = backgroundView.getX() + backgroundView.imageFrameLayout.getX(); float iconY = backgroundView.getY() + backgroundView.imageFrameLayout.getY(); - AndroidUtilities.rectTmp.set(iconX, iconY, iconX + backgroundView.imageView.getMeasuredWidth(), iconY + backgroundView.imageView.getMeasuredHeight()); + AndroidUtilities.rectTmp.set(iconX, iconY, iconX + (backgroundView.imageView == null ? 0 : backgroundView.imageView.getMeasuredWidth()), iconY + (backgroundView.imageView == null ? 0 : backgroundView.imageView.getMeasuredHeight())); if ((AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY()) || iconInterceptedTouch) && !listView.scrollingByUser) { ev.offsetLocation(-iconX, -iconY); if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) { @@ -632,24 +642,26 @@ public static void fillPremiumFeaturesList(ArrayList premium MessagesController messagesController = MessagesController.getInstance(currentAccount); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_LIMITS, R.drawable.msg_premium_limits, LocaleController.getString("PremiumPreviewLimits", R.string.PremiumPreviewLimits), LocaleController.formatString("PremiumPreviewLimitsDescription", R.string.PremiumPreviewLimitsDescription, messagesController.channelsLimitPremium, messagesController.dialogFiltersLimitPremium, messagesController.dialogFiltersPinnedLimitPremium, messagesController.publicLinksLimitPremium, 4))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, applyNewSpan(LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories)), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_UPLOAD_LIMIT, R.drawable.msg_premium_uploads, LocaleController.getString("PremiumPreviewUploads", R.string.PremiumPreviewUploads), LocaleController.getString("PremiumPreviewUploadsDescription", R.string.PremiumPreviewUploadsDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_DOWNLOAD_SPEED, R.drawable.msg_premium_speed, LocaleController.getString("PremiumPreviewDownloadSpeed", R.string.PremiumPreviewDownloadSpeed), LocaleController.getString("PremiumPreviewDownloadSpeedDescription", R.string.PremiumPreviewDownloadSpeedDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_VOICE_TO_TEXT, R.drawable.msg_premium_voice, LocaleController.getString("PremiumPreviewVoiceToText", R.string.PremiumPreviewVoiceToText), LocaleController.getString("PremiumPreviewVoiceToTextDescription", R.string.PremiumPreviewVoiceToTextDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADS, R.drawable.msg_premium_ads, LocaleController.getString("PremiumPreviewNoAds", R.string.PremiumPreviewNoAds), LocaleController.getString("PremiumPreviewNoAdsDescription", R.string.PremiumPreviewNoAdsDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_REACTIONS, R.drawable.msg_premium_reactions, LocaleController.getString("PremiumPreviewReactions2", R.string.PremiumPreviewReactions2), LocaleController.getString("PremiumPreviewReactions2Description", R.string.PremiumPreviewReactions2Description))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STICKERS, R.drawable.msg_premium_stickers, LocaleController.getString("PremiumPreviewStickers", R.string.PremiumPreviewStickers), LocaleController.getString("PremiumPreviewStickersDescription", R.string.PremiumPreviewStickersDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_EMOJI, R.drawable.msg_premium_emoji, LocaleController.getString("PremiumPreviewEmoji", R.string.PremiumPreviewEmoji), LocaleController.getString("PremiumPreviewEmojiDescription", R.string.PremiumPreviewEmojiDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT, R.drawable.msg_premium_tools, LocaleController.getString("PremiumPreviewAdvancedChatManagement", R.string.PremiumPreviewAdvancedChatManagement), LocaleController.getString("PremiumPreviewAdvancedChatManagementDescription", R.string.PremiumPreviewAdvancedChatManagementDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_PROFILE_BADGE, R.drawable.msg_premium_badge, LocaleController.getString("PremiumPreviewProfileBadge", R.string.PremiumPreviewProfileBadge), LocaleController.getString("PremiumPreviewProfileBadgeDescription", R.string.PremiumPreviewProfileBadgeDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString("PremiumPreviewAnimatedProfiles", R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString("PremiumPreviewAnimatedProfilesDescription", R.string.PremiumPreviewAnimatedProfilesDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString("PremiumPreviewAppIcon", R.string.PremiumPreviewAppIcon), LocaleController.getString("PremiumPreviewAppIconDescription", R.string.PremiumPreviewAppIconDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.msg_premium_status, LocaleController.getString("PremiumPreviewEmojiStatus", R.string.PremiumPreviewEmojiStatus), LocaleController.getString("PremiumPreviewEmojiStatusDescription", R.string.PremiumPreviewEmojiStatusDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString("PremiumPreviewTranslations", R.string.PremiumPreviewTranslations), LocaleController.getString("PremiumPreviewTranslationsDescription", R.string.PremiumPreviewTranslationsDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_REACTIONS, R.drawable.msg_premium_reactions, LocaleController.getString(R.string.PremiumPreviewReactions2), LocaleController.getString(R.string.PremiumPreviewReactions2Description))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STICKERS, R.drawable.msg_premium_stickers, LocaleController.getString(R.string.PremiumPreviewStickers), LocaleController.getString(R.string.PremiumPreviewStickersDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_EMOJI, R.drawable.msg_premium_emoji, LocaleController.getString(R.string.PremiumPreviewEmoji), LocaleController.getString(R.string.PremiumPreviewEmojiDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT, R.drawable.msg_premium_tools, LocaleController.getString(R.string.PremiumPreviewAdvancedChatManagement), LocaleController.getString(R.string.PremiumPreviewAdvancedChatManagementDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_PROFILE_BADGE, R.drawable.msg_premium_badge, LocaleController.getString(R.string.PremiumPreviewProfileBadge), LocaleController.getString(R.string.PremiumPreviewProfileBadgeDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString(R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString(R.string.PremiumPreviewAnimatedProfilesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString(R.string.PremiumPreviewAppIcon), LocaleController.getString(R.string.PremiumPreviewAppIconDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.premium_status, LocaleController.getString(R.string.PremiumPreviewEmojiStatus), LocaleController.getString(R.string.PremiumPreviewEmojiStatusDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString(R.string.PremiumPreviewTranslations), LocaleController.getString(R.string.PremiumPreviewTranslationsDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_WALLPAPER, R.drawable.premium_wallpaper, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewWallpaper)), LocaleController.getString(R.string.PremiumPreviewWallpaperDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_NAME_COLOR, R.drawable.premium_colors, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewProfileColor)), LocaleController.getString(R.string.PremiumPreviewProfileColorDescription))); if (messagesController.premiumFeaturesTypesToPosition.size() > 0) { for (int i = 0; i < premiumFeatures.size(); i++) { - if (messagesController.premiumFeaturesTypesToPosition.get(premiumFeatures.get(i).type, -1) == -1) { + if (messagesController.premiumFeaturesTypesToPosition.get(premiumFeatures.get(i).type, -1) == -1 && !BuildVars.DEBUG_PRIVATE_VERSION) { premiumFeatures.remove(i); i--; } @@ -673,7 +685,7 @@ public static CharSequence applyNewSpan(String str) { } private void updateBackgroundImage() { - if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0) { + if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0 || backgroundView == null || backgroundView.imageView == null) { return; } gradientTools.gradientMatrix(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight(), 0, 0); @@ -1346,21 +1358,27 @@ public boolean isLightStatusBar() { @Override public void onResume() { super.onResume(); - backgroundView.imageView.setPaused(false); - backgroundView.imageView.setDialogVisible(false); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setPaused(false); + backgroundView.imageView.setDialogVisible(false); + } particlesView.setPaused(false); } @Override public void onPause() { super.onPause(); - backgroundView.imageView.setDialogVisible(true); - particlesView.setPaused(true); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setDialogVisible(true); + } + if (particlesView != null) { + particlesView.setPaused(true); + } } @Override public boolean canBeginSlide() { - return !backgroundView.imageView.touched; + return backgroundView == null || backgroundView.imageView == null || !backgroundView.imageView.touched; } @Override @@ -1378,11 +1396,13 @@ private void updateColors() { } actionBar.setItemsColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), false); actionBar.setItemsBackgroundColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), 60), false); - backgroundView.titleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); - backgroundView.subtitleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); particlesView.drawable.updateColors(); - if (backgroundView.imageView.mRenderer != null) { - backgroundView.imageView.mRenderer.updateColors(); + if (backgroundView != null) { + backgroundView.titleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + backgroundView.subtitleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + if (backgroundView.imageView != null && backgroundView.imageView.mRenderer != null) { + backgroundView.imageView.mRenderer.updateColors(); + } } updateBackgroundImage(); } @@ -1423,7 +1443,9 @@ protected void onDialogDismiss(Dialog dialog) { private void updateDialogVisibility(boolean isVisible) { if (isVisible != isDialogVisible) { isDialogVisible = isVisible; - backgroundView.imageView.setDialogVisible(isVisible); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setDialogVisible(isVisible); + } particlesView.setPaused(isVisible); contentView.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index b692c67efa..4717333788 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -9,6 +9,7 @@ package org.telegram.ui; import static androidx.core.view.ViewCompat.TYPE_TOUCH; +import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.ContactsController.PRIVACY_RULES_TYPE_ADDED_BY_PHONE; import android.Manifest; @@ -35,6 +36,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -43,7 +45,9 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -178,8 +182,10 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioPlayerAlert; import org.telegram.ui.Components.AutoDeletePopupWrapper; @@ -308,12 +314,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private AnimatorSet writeButtonAnimation; // private AnimatorSet qrItemAnimation; private Drawable lockIconDrawable; - private Drawable verifiedDrawable; - private Drawable premiumStarDrawable; + private final Drawable[] verifiedDrawable = new Drawable[2]; + private final Drawable[] premiumStarDrawable = new Drawable[2]; private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable[] emojiStatusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable[2]; - private Drawable verifiedCheckDrawable; - private CrossfadeDrawable verifiedCrossfadeDrawable; - private CrossfadeDrawable premiumCrossfadeDrawable; + private final Drawable[] verifiedCheckDrawable = new Drawable[2]; + private final CrossfadeDrawable[] verifiedCrossfadeDrawable = new CrossfadeDrawable[2]; + private final CrossfadeDrawable[] premiumCrossfadeDrawable = new CrossfadeDrawable[2]; private ScamDrawable scamDrawable; private UndoView undoView; private OverlaysView overlaysView; @@ -322,6 +328,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private boolean sharedMediaLayoutAttached; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; + private View blurredView; + private RLottieDrawable cameraDrawable; private RLottieDrawable cellCameraDrawable; @@ -398,6 +406,7 @@ public void setAlpha(int a) { private boolean needSendMessage; private boolean hasVoiceChatItem; private boolean isTopic; + private boolean openSimilar; private boolean scrolling; @@ -503,6 +512,7 @@ public void setAlpha(int a) { private final static int qr_button = 37; // private final static int gift_premium = 38; private final static int channel_stories = 39; + private final static int edit_color = 40; private Rect rect = new Rect(); @@ -578,6 +588,7 @@ public void setAlpha(int a) { private int subscribersRow; private int subscribersRequestsRow; private int administratorsRow; + private int settingsRow; private int blockedUsersRow; private int membersSectionRow; @@ -895,6 +906,78 @@ public void setBackgroundColor(int color) { } } + private boolean hasColorById; + private final AnimatedFloat hasColorAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + public int color1, color2; + private final AnimatedColor color1Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedColor color2Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private int backgroundGradientColor1, backgroundGradientColor2, backgroundGradientHeight; + private LinearGradient backgroundGradient; + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public void setBackgroundColorId(MessagesController.PeerColor peerColor, boolean animated) { + if (peerColor != null) { + hasColorById = true; + color1 = peerColor.getBgColor1(Theme.isCurrentThemeDark()); + color2 = peerColor.getBgColor2(Theme.isCurrentThemeDark()); + emojiColor = PeerColorActivity.adaptProfileEmojiColor(color1); + } else { + hasColorById = false; + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + emojiColor = getThemedColor(Theme.key_windowBackgroundWhiteBlueText); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emojiColor = Theme.multAlpha(getThemedColor(Theme.key_actionBarDefaultTitle), .5f); + } else { + emojiColor = PeerColorActivity.adaptProfileEmojiColor(getThemedColor(Theme.key_actionBarDefault)); + } + } + if (!animated) { + color1Animated.set(color1, true); + color2Animated.set(color2, true); + } + invalidate(); + } + + private int emojiColor; + private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(20), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + emoji.attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + emoji.detach(); + } + + public final AnimatedFloat emojiLoadedT = new AnimatedFloat(this, 0, 440, CubicBezierInterpolator.EASE_OUT_QUINT); + + private boolean hasEmoji; + public void setBackgroundEmojiId(long emojiId, boolean animated) { + emoji.set(emojiId, animated); + emoji.setColor(emojiColor); + hasEmoji = hasEmoji || emojiId != 0 && emojiId != -1; + invalidate(); + } + + private boolean emojiLoaded; + private boolean isEmojiLoaded() { + if (emojiLoaded) { + return true; + } + if (emoji != null && emoji.getDrawable() instanceof AnimatedEmojiDrawable) { + AnimatedEmojiDrawable drawable = (AnimatedEmojiDrawable) emoji.getDrawable(); + if (drawable.getImageReceiver() != null && drawable.getImageReceiver().hasImageLoaded()) { + return emojiLoaded = true; + } + } + return false; + } + @Override protected void onDraw(Canvas canvas) { final int height = ActionBar.getCurrentActionBarHeight() + (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0); @@ -913,7 +996,36 @@ protected void onDraw(Canvas canvas) { } } paint.setColor(currentColor); - canvas.drawRect(0, 0, getMeasuredWidth(), y1, paint); + final int color1 = color1Animated.set(this.color1); + final int color2 = color2Animated.set(this.color2); + final int gradientHeight = AndroidUtilities.statusBarHeight + AndroidUtilities.dp(144); + if (backgroundGradient == null || backgroundGradientColor1 != color1 || backgroundGradientColor2 != color2 || backgroundGradientHeight != gradientHeight) { + backgroundGradient = new LinearGradient(0, 0, 0, backgroundGradientHeight = gradientHeight, new int[] { backgroundGradientColor2 = color2, backgroundGradientColor1 = color1 }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + backgroundPaint.setShader(backgroundGradient); + } + final float progressToGradient = (playProfileAnimation == 0 ? 1f : avatarAnimationProgress) * hasColorAnimated.set(hasColorById); + if (progressToGradient < 1) { + canvas.drawRect(0, 0, getMeasuredWidth(), y1, paint); + } + if (progressToGradient > 0) { + backgroundPaint.setAlpha((int) (0xFF * progressToGradient)); + canvas.drawRect(0, 0, getMeasuredWidth(), y1, backgroundPaint); + } + if (hasEmoji) { + final float loadedScale = emojiLoadedT.set(isEmojiLoaded()); + if (loadedScale > 0) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), y1); + final float cx = getMeasuredWidth() - dp(46); + final float cy = ((actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + dp(144)) - (1f - extraHeight / dp(88)) * dp(33); + PeerColorActivity.drawProfileIconPattern(cx, cy, 1f + (extraHeight / dp(88) - 1f) * .2f, (x, y, sz, alpha) -> { + emoji.setAlpha((int) (0xFF * alpha * Math.min(1f, extraHeight / dp(88)))); + emoji.setBounds((int) (x - sz * .45f), (int) (y - sz * .45f), (int) (x + sz * .45f), (int) (y + sz * .45f)); + emoji.draw(canvas); + }); + canvas.restore(); + } + } if (previousTransitionFragment != null) { ActionBar actionBar = previousTransitionFragment.getActionBar(); ActionBarMenu menu = actionBar.menu; @@ -1647,6 +1759,7 @@ public boolean onFragmentCreate() { userId = arguments.getLong("user_id", 0); chatId = arguments.getLong("chat_id", 0); topicId = arguments.getInt("topic_id", 0); + openSimilar = arguments.getBoolean("similar", false); isTopic = topicId != 0; banFromGroup = arguments.getLong("ban_chat_id", 0); reportReactionMessageId = arguments.getInt("report_reaction_message_id", 0); @@ -1925,7 +2038,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto actionBar.setColorFilterMode(PorterDuff.Mode.SRC_IN); actionBar.setForceSkipTouches(true); actionBar.setBackgroundColor(Color.TRANSPARENT); - actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); actionBar.setBackButtonDrawable(new BackDrawable(false)); actionBar.setCastShadows(false); @@ -2352,6 +2465,8 @@ public void didChangeOwner(TLRPC.User user) { } } else if (id == edit_name) { presentFragment(new ChangeNameActivity(resourcesProvider)); + } else if (id == edit_color) { + presentFragment(new PeerColorActivity(0).startOnProfile().setOnApplied(ProfileActivity.this)); } else if (id == logout) { presentFragment(new LogoutActivity()); } else if (id == set_as_main) { @@ -2624,14 +2739,20 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (lockIconDrawable != null) { lockIconDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(1f); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(1f); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(1f); + } + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(1f); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(1f); + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(1f); } updateEmojiStatusDrawableColor(1f); - onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); + onlineTextView[1].setTextColor(0xB3FFFFFF); idTextView.setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); actionBar.setItemsColor(Color.WHITE, false); @@ -2733,7 +2854,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { top = view.getTop(); } boolean layout = false; - if (actionBar.isSearchFieldVisible() && sharedMediaRow >= 0) { + if ((actionBar.isSearchFieldVisible() || openSimilar) && sharedMediaRow >= 0) { layoutManager.scrollToPositionWithOffset(sharedMediaRow, -paddingTop); layout = true; } else if (invalidateScroll || currentPaddingTop != paddingTop) { @@ -2916,6 +3037,18 @@ protected void dispatchDraw(Canvas canvas) { scrimView.draw(canvas); canvas.restoreToCount(c); } + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (blurredView.getAlpha() != 1f) { + if (blurredView.getAlpha() != 0) { + canvas.saveLayerAlpha(blurredView.getLeft(), blurredView.getTop(), blurredView.getRight(), blurredView.getBottom(), (int) (255 * blurredView.getAlpha()), Canvas.ALL_SAVE_FLAG); + canvas.translate(blurredView.getLeft(), blurredView.getTop()); + blurredView.draw(canvas); + canvas.restore(); + } + } else { + blurredView.draw(canvas); + } + } } @Override @@ -2923,6 +3056,9 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (pinchToZoomHelper.isInOverlayMode() && (child == avatarContainer2 || child == actionBar || child == writeButton)) { return true; } + if (child == blurredView) { + return true; + } return super.drawChild(canvas, child, drawingTime); } @@ -2950,7 +3086,12 @@ protected void onDetachedFromWindow() { }; ArrayList users = chatInfo != null && chatInfo.participants != null && chatInfo.participants.participants.size() > 5 ? sortedUsers : null; - sharedMediaLayout = new SharedMediaLayout(context, did, sharedMediaPreloader, userInfo != null ? userInfo.common_chats_count : 0, sortedUsers, chatInfo, userInfo, users != null, this, this, SharedMediaLayout.VIEW_TYPE_PROFILE_ACTIVITY, resourcesProvider) { + sharedMediaLayout = new SharedMediaLayout(context, did, sharedMediaPreloader, userInfo != null ? userInfo.common_chats_count : 0, sortedUsers, chatInfo, userInfo, openSimilar ? SharedMediaLayout.TAB_RECOMMENDED_CHANNELS : users != null ? SharedMediaLayout.TAB_GROUPUSERS : -1, this, this, SharedMediaLayout.VIEW_TYPE_PROFILE_ACTIVITY, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + @Override protected void onSelectedTabChanged() { updateSelectedMediaTabText(); @@ -3528,6 +3669,8 @@ public void openExceptions() { ChatUsersActivity fragment = new ChatUsersActivity(args); fragment.setInfo(chatInfo); presentFragment(fragment); + } else if (position == settingsRow) { + editItem.performClick(); } else if (position == blockedUsersRow) { Bundle args = new Bundle(); args.putLong("chat_id", chatId); @@ -3898,6 +4041,7 @@ public boolean onItemClick(View view, int position) { SharedConfig.updateStealthModeSendMessageConfirm(2); SharedConfig.setStoriesReactionsLongPressHintUsed(false); SharedConfig.setStoriesIntroShown(false); + SharedConfig.setMultipleReactionsPromoShowed(false); ChatThemeController.getInstance(currentAccount).clearCache(); getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); RestrictedLanguagesSelectActivity.cleanup(); @@ -4164,6 +4308,14 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } }); + if (openSimilar) { + updateRowsIds(); + scrollToSharedMedia(); + savedScrollToSharedMedia = true; + savedScrollPosition = sharedMediaRow; + savedScrollOffset = 0; + } + if (searchItem != null) { searchListView = new RecyclerListView(context); searchListView.setVerticalScrollBarEnabled(false); @@ -4306,6 +4458,7 @@ public void didChangeOwner(TLRPC.User user) { } topView = new TopView(context); + topView.setBackgroundColorId(peerColor, false); topView.setBackgroundColor(getThemedColor(Theme.key_avatar_backgroundActionBarBlue)); frameLayout.addView(topView); contentView.blurBehindViews.add(topView); @@ -4631,7 +4784,7 @@ public void setTextColor(int color) { } onlineTextView[a].setEllipsizeByGradient(true); - onlineTextView[a].setTextColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue)); + onlineTextView[a].setTextColor(applyPeerColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), true)); onlineTextView[a].setTextSize(14); onlineTextView[a].setGravity(Gravity.LEFT); onlineTextView[a].setAlpha(a == 0 ? 0.0f : 1.0f); @@ -4703,14 +4856,7 @@ protected void onLongPress() { updateProfileData(true); writeButton = new RLottieImageView(context); - - Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN)); - CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, - Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_profile_actionBackground), getThemedColor(Theme.key_profile_actionPressedBackground)), - 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - writeButton.setBackground(combinedDrawable); + writeButtonSetBackground(); if (userId != 0) { if (imageUpdater != null) { cameraDrawable = new RLottieDrawable(R.raw.camera_outline, String.valueOf(R.raw.camera_outline), AndroidUtilities.dp(56), AndroidUtilities.dp(56), false, null); @@ -4818,12 +4964,18 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, value), PorterDuff.Mode.SRC_IN); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(value); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(value); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(value); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(value); + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(value); + } + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(value); } updateEmojiStatusDrawableColor(value); @@ -4897,7 +5049,7 @@ public void onAnimationStart(Animator animation) { @Override public void onAnimationEnd(Animator animation) { - actionBar.setItemsBackgroundColor(isPulledDown ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsBackgroundColor(isPulledDown ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); avatarImage.clearForeground(); doNotSetForeground = false; updateStoriesViewBounds(false); @@ -4996,6 +5148,27 @@ public void onZoomStarted(MessageObject messageObject) { BackButtonMenuRecent.addToRecentDialogs(currentAccount, userId != 0 ? userId : -chatId); + blurredView = new View(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (fragmentView != null) { + fragmentView.invalidate(); + } + } + }; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + blurredView.setForeground(new ColorDrawable(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_windowBackgroundWhite), 100))); + } + blurredView.setFocusable(false); + blurredView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + blurredView.setOnClickListener(e -> { + finishPreviewFragment(); + }); + blurredView.setVisibility(View.GONE); + blurredView.setFitsSystemWindows(true); + contentView.addView(blurredView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + createFloatingActionButton(getContext()); return fragmentView; } @@ -5130,7 +5303,7 @@ private void updateFloatingButtonColor() { } Drawable drawable; if (floatingButtonContainer != null) { - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); + drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), applyPeerColor(Theme.getColor(Theme.key_chats_actionBackground), false), applyPeerColor(Theme.getColor(Theme.key_chats_actionPressedBackground), false)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -5229,12 +5402,18 @@ private void setAvatarExpandProgress(float animatedFracture) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, value), PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(value); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(value); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(value); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(value); + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(value); + } + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(value); } updateEmojiStatusDrawableColor(value); @@ -5263,12 +5442,14 @@ private void setAvatarExpandProgress(float animatedFracture) { mediaCounterTextView.setTranslationY(onlineTextViewY); final Object onlineTextViewTag = onlineTextView[1].getTag(); int statusColor; + boolean online = false; if (onlineTextViewTag instanceof Integer) { statusColor = getThemedColor((Integer) onlineTextViewTag); + online = (Integer) onlineTextViewTag == Theme.key_profile_status; } else { statusColor = getThemedColor(Theme.key_avatar_subtitleInProfileBlue); } - onlineTextView[1].setTextColor(ColorUtils.blendARGB(statusColor, Color.argb(179, 255, 255, 255), value)); + onlineTextView[1].setTextColor(ColorUtils.blendARGB(applyPeerColor(statusColor, true, online), 0xB3FFFFFF, value)); if (extraHeight > AndroidUtilities.dp(88f)) { nameTextView[1].setPivotY(AndroidUtilities.lerp(0, nameTextView[1].getMeasuredHeight(), value)); nameTextView[1].setScaleX(AndroidUtilities.lerp(1.12f, 1.67f, value)); @@ -5277,8 +5458,8 @@ private void setAvatarExpandProgress(float animatedFracture) { needLayoutText(Math.min(1f, extraHeight / AndroidUtilities.dp(88f))); - nameTextView[1].setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_profile_title), Color.WHITE, value)); - actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); + nameTextView[1].setTextColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_profile_title), Color.WHITE, currentExpandAnimatorValue)); + actionBar.setItemsColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); actionBar.setMenuOffsetSuppressed(true); avatarImage.setForegroundAlpha(value); @@ -5372,7 +5553,7 @@ public void goToForum() { Bundle args = new Bundle(); args.putLong("chat_id", chatId); - presentFragment(new TopicsFragment(args)); + presentFragment(TopicsFragment.getTopicsOrChat(this, args)); } private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; @@ -5413,7 +5594,7 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d for (int a = 0; a < 2; ++a) { if (emojiStatusDrawable[a] != null) { if (documentId == null) { - emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(), true); + emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(a), true); } else { emojiStatusDrawable[a].set(documentId, true); } @@ -6162,37 +6343,53 @@ public void setValue(ActionBar object, float value) { scamDrawable.setColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f)); } - color1 = getThemedColor(Theme.key_actionBarDefaultIcon); + color1 = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); color2 = getThemedColor(Theme.key_actionBarActionModeDefaultIcon); actionBar.setItemsColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), false); - color1 = getThemedColor(Theme.key_avatar_actionBarSelectorBlue); + color1 = peerColor != null ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue); color2 = getThemedColor(Theme.key_actionBarActionModeDefaultSelector); actionBar.setItemsBackgroundColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), false); topView.invalidate(); - otherItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - callItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - videoCallItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - editItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - eventLogItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); + otherItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + callItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + videoCallItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + editItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + eventLogItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); - if (verifiedDrawable != null) { + if (verifiedDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedBackground); color2 = getThemedColor(Theme.key_player_actionBarTitle); - verifiedDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.SRC_IN); + verifiedDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (verifiedDrawable[1] != null) { + color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedBackground)); + color2 = getThemedColor(Theme.key_player_actionBarTitle); + verifiedDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } - if (verifiedCheckDrawable != null) { + if (verifiedCheckDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedCheck); color2 = getThemedColor(Theme.key_windowBackgroundWhite); - verifiedCheckDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.SRC_IN); + verifiedCheckDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (verifiedCheckDrawable[1] != null) { + color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedCheck)); + color2 = getThemedColor(Theme.key_windowBackgroundWhite); + verifiedCheckDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } - if (premiumStarDrawable != null) { + + if (premiumStarDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedBackground); color2 = getThemedColor(Theme.key_player_actionBarTitle); - premiumStarDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + premiumStarDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (premiumStarDrawable[1] != null) { + color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedBackground)); + color2 = applyPeerColor(getThemedColor(Theme.key_player_actionBarTitle)); + premiumStarDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } updateEmojiStatusDrawableColor(); @@ -6501,6 +6698,9 @@ public void updateSelectedMediaTabText() { mediaCounterTextView.setText(onlineTextView[1].getText()); } else if (id == SharedMediaLayout.TAB_STORIES) { mediaCounterTextView.setText(LocaleController.formatPluralString("ProfileStoriesCount", sharedMediaLayout.getStoriesCount(id))); + } else if (id == SharedMediaLayout.TAB_RECOMMENDED_CHANNELS) { + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(chatId); + mediaCounterTextView.setText(LocaleController.formatPluralString("Channels", rec == null ? 0 : rec.chats.size() + rec.more)); } } @@ -6772,7 +6972,7 @@ public void onAnimationEnd(Animator animation) { avatarContainer.setScaleY(avatarScale); overlaysView.setAlphaValue(avatarAnimationProgress, false); - actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, avatarAnimationProgress), false); + actionBar.setItemsColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, avatarAnimationProgress), false); if (scamDrawable != null) { scamDrawable.setColor(ColorUtils.blendARGB(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), Color.argb(179, 255, 255, 255), avatarAnimationProgress)); @@ -6780,12 +6980,12 @@ public void onAnimationEnd(Animator animation) { if (lockIconDrawable != null) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, avatarAnimationProgress), PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(avatarAnimationProgress); + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(avatarAnimationProgress); nameTextView[1].invalidate(); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(avatarAnimationProgress); + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(avatarAnimationProgress); nameTextView[1].invalidate(); } updateEmojiStatusDrawableColor(avatarAnimationProgress); @@ -7336,6 +7536,10 @@ public void onResume() { firstLayout = true; listAdapter.notifyDataSetChanged(); } + if (!parentLayout.isInPreviewMode() && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } if (imageUpdater != null) { imageUpdater.onResume(); @@ -7385,7 +7589,7 @@ public void onPause() { public boolean isSwipeBackEnabled(MotionEvent event) { if (avatarsViewPager != null && avatarsViewPager.getVisibility() == View.VISIBLE && avatarsViewPager.getRealCount() > 1) { avatarsViewPager.getHitRect(rect); - if (rect.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { + if (event != null && rect.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { return false; } } @@ -7496,6 +7700,11 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { } } getNotificationCenter().onAnimationFinish(transitionIndex); + + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } } transitionAnimationInProress = false; checkPhotoDescriptionAlpha(); @@ -7536,8 +7745,8 @@ public void setAvatarAnimationProgress(float progress) { timerDrawable.setBackgroundColor(ColorUtils.blendARGB(actionBarColor2, color, progress)); color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); - int iconColor = getThemedColor(Theme.key_actionBarDefaultIcon); - actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, progress), false); + int iconColor = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); + actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, avatarAnimationProgress), false); color = getThemedColor(Theme.key_profile_title); int titleColor = getThemedColor(Theme.key_actionBarDefaultTitle); @@ -7550,12 +7759,11 @@ public void setAvatarAnimationProgress(float progress) { color = isOnline[0] ? getThemedColor(Theme.key_profile_status) : AvatarDrawable.getProfileTextColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); int subtitleColor = getThemedColor(isOnline[0] ? Theme.key_chat_status : Theme.key_actionBarDefaultSubtitle); - for (int i = 0; i < 3; i++) { if (onlineTextView[i] == null || i == 1 || i == 2 && playProfileAnimation == 2) { continue; } - onlineTextView[i].setTextColor(ColorUtils.blendARGB(subtitleColor, color, progress)); + onlineTextView[i].setTextColor(ColorUtils.blendARGB(i == 0 ? subtitleColor : applyPeerColor(subtitleColor, true, isOnline[0]), i == 0 ? color : applyPeerColor(color, true, isOnline[0]), progress)); } extraHeight = initialAnimationExtraHeight * progress; color = AvatarDrawable.getProfileColorForId(userId != 0 ? userId : chatId, resourcesProvider); @@ -7663,7 +7871,7 @@ public AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runna if (playProfileAnimation == 2) { avatarColor = getAverageColor(avatarImage.getImageReceiver()); nameTextView[1].setTextColor(Color.WHITE); - onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); + onlineTextView[1].setTextColor(0xB3FFFFFF); idTextView.setAlpha(0); idTextView.setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); @@ -8063,6 +8271,7 @@ private void updateRowsIds() { membersSectionRow = -1; sharedMediaRow = -1; notificationsSimpleRow = -1; + settingsRow = -1; unblockRow = -1; joinRow = -1; @@ -8086,6 +8295,11 @@ private void updateRowsIds() { if (!hasMedia && chatInfo != null) { hasMedia = chatInfo.stories_pinned_available; } + if (!hasMedia) { + if (MessagesController.ChannelRecommendations.hasRecommendations(currentAccount, chatId)) { + hasMedia = true; + } + } if (userId != 0) { if (LocaleController.isRTL) { @@ -8268,6 +8482,7 @@ private void updateRowsIds() { if (chatInfo.banned_count != 0 || chatInfo.kicked_count != 0) { blockedUsersRow = rowCount++; } + settingsRow = rowCount++; membersSectionRow = rowCount++; } } @@ -8387,22 +8602,29 @@ private Drawable getLockIconDrawable() { return lockIconDrawable; } - private Drawable getVerifiedCrossfadeDrawable() { - if (verifiedCrossfadeDrawable == null) { - verifiedDrawable = Theme.profile_verifiedDrawable.getConstantState().newDrawable().mutate(); - verifiedCheckDrawable = Theme.profile_verifiedCheckDrawable.getConstantState().newDrawable().mutate(); - verifiedCrossfadeDrawable = new CrossfadeDrawable(new CombinedDrawable(verifiedDrawable, verifiedCheckDrawable), ContextCompat.getDrawable(getParentActivity(), R.drawable.verified_profile)); + private Drawable getVerifiedCrossfadeDrawable(int a) { + if (verifiedCrossfadeDrawable[a] == null) { + verifiedDrawable[a] = Theme.profile_verifiedDrawable.getConstantState().newDrawable().mutate(); + verifiedCheckDrawable[a] = Theme.profile_verifiedCheckDrawable.getConstantState().newDrawable().mutate(); + verifiedCrossfadeDrawable[a] = new CrossfadeDrawable( + new CombinedDrawable(verifiedDrawable[a], verifiedCheckDrawable[a]), + ContextCompat.getDrawable(getParentActivity(), R.drawable.verified_profile) + ); } - return verifiedCrossfadeDrawable; + return verifiedCrossfadeDrawable[a]; } - private Drawable getPremiumCrossfadeDrawable() { - if (premiumCrossfadeDrawable == null) { - premiumStarDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate(); - premiumStarDrawable.setColorFilter(getThemedColor(Theme.key_profile_verifiedBackground), PorterDuff.Mode.MULTIPLY); - premiumCrossfadeDrawable = new CrossfadeDrawable(premiumStarDrawable, ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_prolfilestar).mutate()); + private Drawable getPremiumCrossfadeDrawable(int a) { + if (premiumCrossfadeDrawable[a] == null) { + premiumStarDrawable[a] = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate(); + int color = getThemedColor(Theme.key_profile_verifiedBackground); + if (a == 1) { + color = applyPeerColor(color); + } + premiumStarDrawable[a].setColorFilter(color, PorterDuff.Mode.MULTIPLY); + premiumCrossfadeDrawable[a] = new CrossfadeDrawable(premiumStarDrawable[a], ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_prolfilestar).mutate()); } - return premiumCrossfadeDrawable; + return premiumCrossfadeDrawable[a]; } private Drawable getEmojiStatusDrawable(TLRPC.EmojiStatus emojiStatus, boolean switchable, boolean animated, int a) { @@ -8417,7 +8639,7 @@ private Drawable getEmojiStatusDrawable(TLRPC.EmojiStatus emojiStatus, boolean s } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000) && !reportSpam) { emojiStatusDrawable[a].set(((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id, animated); } else { - emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(), animated); + emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(a), animated); } updateEmojiStatusDrawableColor(); return emojiStatusDrawable[a]; @@ -8428,18 +8650,25 @@ private void updateEmojiStatusDrawableColor() { updateEmojiStatusDrawableColor(lastEmojiStatusProgress); } private void updateEmojiStatusDrawableColor(float progress) { - final int color = - ColorUtils.blendARGB( - AndroidUtilities.getOffsetColor(getThemedColor(Theme.key_profile_verifiedBackground), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f), - 0xffffffff, - progress - ); for (int a = 0; a < 2; ++a) { + final int fromColor; + if (peerColor != null && a == 1) { + fromColor = ColorUtils.blendARGB( + peerColor.getColor2(), + peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor5() : peerColor.getColor3(), + .5f + ); + } else { + fromColor = AndroidUtilities.getOffsetColor(getThemedColor(Theme.key_profile_verifiedBackground), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f); + } + final int color = ColorUtils.blendARGB(fromColor, 0xffffffff, progress); if (emojiStatusDrawable[a] != null) { emojiStatusDrawable[a].setColor(color); } + if (a == 1) { + animatedStatusView.setColor(color); + } } - animatedStatusView.setColor(color); lastEmojiStatusProgress = progress; } @@ -8452,6 +8681,8 @@ private void updateEmojiStatusEffectPosition() { ); } + private MessagesController.PeerColor peerColor; + private void updateProfileData(boolean reload) { if (avatarContainer == null || nameTextView == null || getParentActivity() == null) { return; @@ -8487,7 +8718,18 @@ private void updateProfileData(boolean reload) { if (user.photo != null) { photoBig = user.photo.photo_big; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); + + final int colorId = UserObject.getProfileColorId(user); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + final MessagesController.PeerColor wasPeerColor = peerColor; + peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (wasPeerColor != peerColor) { + updatedPeerColor(); + } + if (topView != null) { + topView.setBackgroundEmojiId(UserObject.getProfileEmojiId(user), true); + } final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); @@ -8547,10 +8789,10 @@ private void updateProfileData(boolean reload) { isOnline[0] = false; newString2 = LocaleController.formatUserStatus(currentAccount, user, isOnline, shortStatus ? new boolean[1] : null); if (onlineTextView[1] != null && !mediaHeaderVisible) { - int key = isOnline[0] ? Theme.key_profile_status : Theme.key_avatar_subtitleInProfileBlue; + int key = isOnline[0] && peerColor == null ? Theme.key_profile_status : Theme.key_avatar_subtitleInProfileBlue; onlineTextView[1].setTag(key); if (!isPulledDown) { - onlineTextView[1].setTextColor(getThemedColor(key)); + onlineTextView[1].setTextColor(applyPeerColor(getThemedColor(key), true, isOnline[0])); } } } @@ -8584,7 +8826,7 @@ private void updateProfileData(boolean reload) { rightIcon = getScamDrawable(user.scam ? 0 : 1); nameTextViewRightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); } else if (user.verified) { - rightIcon = getVerifiedCrossfadeDrawable(); + rightIcon = getVerifiedCrossfadeDrawable(a); nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { rightIconIsStatus = true; @@ -8607,7 +8849,7 @@ private void updateProfileData(boolean reload) { if (user.scam || user.fake) { rightIcon = getScamDrawable(user.scam ? 0 : 1); } else if (user.verifiedExtended()) { - rightIcon = getVerifiedCrossfadeDrawable(); + rightIcon = getVerifiedCrossfadeDrawable(a); } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { rightIconIsStatus = true; rightIconIsPremium = false; @@ -8731,6 +8973,17 @@ private void updateProfileData(boolean reload) { flagSecure.invalidate(); } + final int colorId = ChatObject.getProfileColorId(chat); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + final MessagesController.PeerColor wasPeerColor = peerColor; + peerColor = null; + if (wasPeerColor != peerColor) { + updatedPeerColor(); + } + if (topView != null) { + topView.setBackgroundEmojiId(ChatObject.getProfileEmojiId(chat), true); + } + if (isTopic) { topic = getMessagesController().getTopicsController().findTopic(chatId, topicId); } @@ -8843,7 +9096,7 @@ private void updateProfileData(boolean reload) { nameTextView[a].setRightDrawable(getScamDrawable(chat.scam ? 0 : 1)); nameTextViewRightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); } else if (chat.verifiedExtended()) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable()); + nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable(a)); nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); } else { nameTextView[a].setRightDrawable(null); @@ -8853,7 +9106,7 @@ private void updateProfileData(boolean reload) { if (chat.scam || chat.fake) { nameTextView[a].setRightDrawable(getScamDrawable(chat.scam ? 0 : 1)); } else if (chat.verified) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable()); + nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable(a)); } else if (getMessagesController().isDialogMuted(-chatId, topicId)) { nameTextView[a].setRightDrawable(getThemedDrawable(Theme.key_drawable_muteIconDrawable)); } else { @@ -8916,7 +9169,7 @@ private void updateProfileData(boolean reload) { videoLocation = null; ForumUtilities.setTopicIcon(avatarImage, topic, true, true, resourcesProvider); } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); @@ -9001,6 +9254,80 @@ private void updateProfileData(boolean reload) { AndroidUtilities.runOnUIThread(this::updateEmojiStatusEffectPosition); } + private void updatedPeerColor() { + if (topView != null) { + topView.setBackgroundColorId(peerColor, true); + } + if (onlineTextView[1] != null) { + int statusColor; + if (onlineTextView[1].getTag() instanceof Integer) { + statusColor = getThemedColor((Integer) onlineTextView[1].getTag()); + } else { + statusColor = getThemedColor(Theme.key_avatar_subtitleInProfileBlue); + } + onlineTextView[1].setTextColor(ColorUtils.blendARGB(applyPeerColor(statusColor, true, isOnline[0]), 0xB3FFFFFF, currentExpandAnimatorValue)); + } + if (actionBar != null) { + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + + final int color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); + final int iconColor = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); + actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, avatarAnimationProgress), false); + } + if (nameTextView[1] != null) { + nameTextView[1].setTextColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_profile_title), Color.WHITE, currentExpandAnimatorValue)); + } + if (autoDeletePopupWrapper != null && autoDeletePopupWrapper.textView != null) { + autoDeletePopupWrapper.textView.invalidate(); + } + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof HeaderCell) { + ((HeaderCell) view).setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueHeader), false)); + } else if (view instanceof TextDetailCell) { + ((TextDetailCell) view).valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2), false)); + } else if (view instanceof TextCell) { + ((TextCell) view).updateColors(); + } else if (view instanceof NotificationsCheckCell) { + ((NotificationsCheckCell) view).getCheckBox().invalidate(); + } + }); + if (sharedMediaLayout != null && sharedMediaLayout.scrollSlidingTextTabStrip != null) { + sharedMediaLayout.scrollSlidingTextTabStrip.updateColors(); + } + writeButtonSetBackground(); + updateEmojiStatusDrawableColor(); + } + + private int applyPeerColor(int color) { + return applyPeerColor(color, true, null); + } + + private int applyPeerColor(int color, boolean actionBar) { + return applyPeerColor(color, actionBar, null); + } + + private int applyPeerColor(int color, boolean actionBar, Boolean online) { + if (!actionBar) return color; + if (peerColor != null) { + final int baseColor = getThemedColor(actionBar ? Theme.key_actionBarDefault : Theme.key_windowBackgroundWhiteBlueIcon); + final int storyColor = ColorUtils.blendARGB(peerColor.getStoryColor1(Theme.isCurrentThemeDark()), peerColor.getStoryColor2(Theme.isCurrentThemeDark()), .5f); + int accentColor = actionBar ? storyColor : peerColor.getBgColor1(Theme.isCurrentThemeDark()); + if (!Theme.hasHue(baseColor)) { + return online != null && !online ? Theme.adaptHSV(Theme.multAlpha(storyColor, .7f), -.2f, +.2f) : storyColor; + } + return Theme.changeColorAccent(baseColor, accentColor, color, Theme.isCurrentThemeDark(), online != null && !online ? Theme.multAlpha(storyColor, .7f) : storyColor); + } + return color; + } + + private int applyPeerColor2(int color) { + if (peerColor != null) { + int accentColor = peerColor.getBgColor2(Theme.isCurrentThemeDark()); + return Theme.changeColorAccent(getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon), accentColor, color, Theme.isCurrentThemeDark(), accentColor); + } + return color; + } + private void createActionBarMenu(boolean animated) { if (actionBar == null || otherItem == null) { return; @@ -9021,7 +9348,8 @@ private void createActionBarMenu(boolean animated) { return; } if (UserObject.isUserSelf(user)) { - otherItem.addSubItem(edit_name, R.drawable.msg_edit, LocaleController.getString("EditName", R.string.EditName)); + otherItem.addSubItem(edit_name, R.drawable.msg_edit, LocaleController.getString(R.string.EditName)); + otherItem.addSubItem(edit_color, R.drawable.msg_colors, LocaleController.getString(R.string.EditProfileColor)); selfUser = true; } else { if (user.bot && user.bot_can_edit) { @@ -9311,7 +9639,8 @@ public void showGlobalAutoDeleteScreen() { } }, false, 0, resourcesProvider); if (dialogId > 0 || userId > 0) { - autoDeletePopupWrapper.allowExtenededHint(); + int linkColor = applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText), false); + autoDeletePopupWrapper.allowExtendedHint(linkColor); } int ttl = 0; if (userInfo != null || chatInfo != null) { @@ -9953,7 +10282,12 @@ protected void didResizeStart() { break; } case VIEW_TYPE_TEXT: { - view = new TextCell(mContext, resourcesProvider); + view = new TextCell(mContext, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + }; break; } case VIEW_TYPE_DIVIDER: { @@ -9962,7 +10296,12 @@ protected void didResizeStart() { break; } case VIEW_TYPE_NOTIFICATIONS_CHECK: { - view = new NotificationsCheckCell(mContext, 23, 70, false, resourcesProvider); + view = new NotificationsCheckCell(mContext, 23, 70, false, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + }; break; } case VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE: { @@ -10121,6 +10460,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == debugHeaderRow) { headerCell.setText(LocaleController.getString("SettingsDebug", R.string.SettingsDebug)); } + headerCell.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueHeader), false)); break; case VIEW_TYPE_TEXT_DETAIL_MULTILINE: case VIEW_TYPE_TEXT_DETAIL: @@ -10260,7 +10600,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } if (containsQr) { Drawable drawable = ContextCompat.getDrawable(detailCell.getContext(), R.drawable.msg_qr_mini); - drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.MULTIPLY)); + drawable.setColorFilter(new PorterDuffColorFilter(applyPeerColor(getThemedColor(Theme.key_switch2TrackChecked), false), PorterDuff.Mode.MULTIPLY)); detailCell.setImage(drawable, LocaleController.getString("GetQRCode", R.string.GetQRCode)); detailCell.setImageClickListener(ProfileActivity.this::onTextDetailCellImageClicked); } else { @@ -10268,6 +10608,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { detailCell.setImageClickListener(null); } detailCell.setTag(position); + detailCell.valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2), false)); break; case VIEW_TYPE_ABOUT_LINK: AboutLinkCell aboutLinkCell = (AboutLinkCell) holder.itemView; @@ -10346,6 +10687,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { textCell.setTextAndIcon(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), R.drawable.msg_admins, position != membersSectionRow - 1); } + } else if (position == settingsRow) { + textCell.setTextAndIcon(LocaleController.getString("ChannelAdminSettings", R.string.ChannelAdminSettings), R.drawable.msg_customize, position != membersSectionRow - 1); } else if (position == blockedUsersRow) { if (chatInfo != null) { textCell.setTextAndValueAndIcon(LocaleController.getString("ChannelBlacklist", R.string.ChannelBlacklist), String.format("%d", Math.max(chatInfo.banned_count, chatInfo.kicked_count)), R.drawable.msg_user_remove, position != membersSectionRow - 1); @@ -10423,6 +10766,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCell.setTextAndIcon(LocaleController.getString("TelegramPremium", R.string.TelegramPremium), new AnimatedEmojiDrawable.WrapSizeDrawable(PremiumGradient.getInstance().premiumStarMenuDrawable, AndroidUtilities.dp(24), AndroidUtilities.dp(24)), false); textCell.setImageLeft(23); } + textCell.valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteValueText), false)); break; case VIEW_TYPE_NOTIFICATIONS_CHECK: NotificationsCheckCell checkCell = (NotificationsCheckCell) holder.itemView; @@ -10590,7 +10934,7 @@ public void updateDrawState(@NonNull TextPaint ds) { ds.setUnderlineText(false); } }, 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - username.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_chat_messageLinkIn)), 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + username.setSpan(new ForegroundColorSpan(applyPeerColor(getThemedColor(Theme.key_chat_messageLinkIn), false)), 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); usernames.append(username); if (i < alsoUsernames.size() - 1) { usernames.append(", "); @@ -10661,7 +11005,7 @@ public int getItemViewType(int position) { } else if (position == userInfoRow || position == channelInfoRow || position == bioRow) { return VIEW_TYPE_ABOUT_LINK; } else if (position == settingsTimerRow || position == settingsKeyRow || position == reportRow || position == reportReactionRow || - position == subscribersRow || position == subscribersRequestsRow || position == administratorsRow || position == blockedUsersRow || + position == subscribersRow || position == subscribersRequestsRow || position == administratorsRow || position == settingsRow || position == blockedUsersRow || position == addMemberRow || position == joinRow || position == unblockRow || position == sendMessageRow || position == notificationRow || position == privacyRow || position == languageRow || position == dataRow || position == chatRow || @@ -11543,9 +11887,9 @@ public ArrayList getThemeDescriptions() { final Object onlineTextViewTag = onlineTextView[1].getTag(); for (int i = 0; i < 2; i++) { if (onlineTextViewTag instanceof Integer) { - onlineTextView[i + 1].setTextColor(getThemedColor((Integer) onlineTextViewTag)); + onlineTextView[i + 1].setTextColor(applyPeerColor(getThemedColor((Integer) onlineTextViewTag), true, isOnline[0])); } else { - onlineTextView[i + 1].setTextColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue)); + onlineTextView[i + 1].setTextColor(applyPeerColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), true, true)); } } } @@ -11560,8 +11904,8 @@ public ArrayList getThemeDescriptions() { idTextView.setTextColor(Theme.getColor(Theme.key_avatar_subtitleInProfileBlue)); } if (actionBar != null) { - actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); - actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), false); + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); } } updateEmojiStatusDrawableColor(); @@ -11672,11 +12016,11 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(searchListView, 0, new Class[]{SettingsSearchCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); if (mediaHeaderVisible) { - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedCheckDrawable}, null, Theme.key_player_actionBarTitle)); - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedDrawable}, null, Theme.key_windowBackgroundWhite)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedCheckDrawable, null, Theme.key_player_actionBarTitle)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedDrawable, null, Theme.key_windowBackgroundWhite)); } else { - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedCheckDrawable}, null, Theme.key_profile_verifiedCheck)); - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedDrawable}, null, Theme.key_profile_verifiedBackground)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedCheckDrawable, null, Theme.key_profile_verifiedCheck)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedDrawable, null, Theme.key_profile_verifiedBackground)); } return arrayList; @@ -11719,9 +12063,10 @@ public void updateListAnimated(boolean updateOnlineCount) { int savedScrollPosition = -1; int savedScrollOffset; + boolean savedScrollToSharedMedia; private void saveScrollPosition() { - if (listView != null && layoutManager != null && listView.getChildCount() > 0) { + if (listView != null && layoutManager != null && listView.getChildCount() > 0 && !savedScrollToSharedMedia) { View view = null; int position = -1; int top = Integer.MAX_VALUE; @@ -11763,15 +12108,28 @@ private void onTextDetailCellImageClicked(View view) { @Override public void onBecomeFullyVisible() { super.onBecomeFullyVisible(); + writeButtonSetBackground(); + } + private void writeButtonSetBackground() { + if (writeButton == null) return; try { Drawable shadowDrawable = fragmentView.getContext().getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + int color1 = getThemedColor(Theme.key_profile_actionBackground); + int color2 = getThemedColor(Theme.key_profile_actionPressedBackground); + int iconColor = getThemedColor(Theme.key_profile_actionIcon); + if (peerColor != null && Theme.hasHue(color1)) { + color1 = Theme.adaptHSV(peerColor.getBgColor1(false), +.05f, -.04f); + color2 = applyPeerColor2(color2); + iconColor = Color.WHITE; + } CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, - Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_profile_actionBackground), getThemedColor(Theme.key_profile_actionPressedBackground)), + Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), color1, color2), 0, 0); combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); writeButton.setBackground(combinedDrawable); + writeButton.setColorFilter(new PorterDuffColorFilter(iconColor, PorterDuff.Mode.MULTIPLY)); } catch (Exception e) {} } @@ -11935,6 +12293,7 @@ public void fillPositions(SparseIntArray sparseIntArray) { put(++pointer, subscribersRow, sparseIntArray); put(++pointer, subscribersRequestsRow, sparseIntArray); put(++pointer, administratorsRow, sparseIntArray); + put(++pointer, settingsRow, sparseIntArray); put(++pointer, blockedUsersRow, sparseIntArray); put(++pointer, membersSectionRow, sparseIntArray); put(++pointer, sharedMediaRow, sparseIntArray); @@ -11963,6 +12322,8 @@ public boolean isLightStatusBar() { color = getThemedColor(Theme.key_actionBarActionModeDefault); } else if (mediaHeaderVisible) { color = getThemedColor(Theme.key_windowBackgroundWhite); + } else if (peerColor != null) { + color = peerColor.getBgColor2(Theme.isCurrentThemeDark()); } else { color = getThemedColor(Theme.key_actionBarDefault); } @@ -12139,4 +12500,33 @@ private void listCodecs(String type, StringBuilder info) { info.append("\n"); } catch (Exception ignore) {} } + + @Override + public void onTransitionAnimationProgress(boolean isOpen, float progress) { + super.onTransitionAnimationProgress(isOpen, progress); + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (isOpen) { + blurredView.setAlpha(1.0f - progress); + } else { + blurredView.setAlpha(progress); + } + } + } + + public void prepareBlurBitmap() { + if (blurredView == null) { + return; + } + int w = (int) (fragmentView.getMeasuredWidth() / 6.0f); + int h = (int) (fragmentView.getMeasuredHeight() / 6.0f); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.scale(1.0f / 6.0f, 1.0f / 6.0f); + fragmentView.draw(canvas); + Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(w, h) / 180)); + blurredView.setBackground(new BitmapDrawable(bitmap)); + blurredView.setAlpha(0.0f); + blurredView.setVisibility(View.VISIBLE); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index e1c0a4bdff..841910670b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -33,7 +33,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -49,6 +48,7 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.view.animation.OvershootInterpolator; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; @@ -144,6 +144,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public static final int TYPE_TOPIC_ICON = 3; public static final int TYPE_AVATAR_CONSTRUCTOR = 4; public final static int TYPE_SET_REPLY_ICON = 5; + public static final int TYPE_CHAT_REACTIONS = 6; + public final static int TYPE_SET_REPLY_ICON_BOTTOM = 7; + public final static int TYPE_EXPANDABLE_REACTIONS = 8; public boolean isBottom() { return type == TYPE_SET_REPLY_ICON; @@ -444,7 +447,7 @@ public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boo setFocusableInTouchMode(true); - if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { topMarginDp = topPaddingDp; setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4)); setOnTouchListener((v, e) -> { @@ -562,7 +565,7 @@ public void getOutline(View view, Outline outline) { } contentView.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); + addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON_BOTTOM ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); if (bubbleX != null) { bubble2View = new View(context) { @@ -579,7 +582,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { addView(bubble2View, LayoutHelper.createFrame(17, 9, (isBottom() ? Gravity.BOTTOM : Gravity.TOP) | Gravity.LEFT, bubbleX / AndroidUtilities.density + (bubbleRight ? -25 : 10), isBottom() ? 0 : 5 + topMarginDp, 0, isBottom() ? 5 + topMarginDp + 9 : 0)); } - boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_SET_REPLY_ICON && type != TYPE_AVATAR_CONSTRUCTOR && shouldDrawBackground; + boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_AVATAR_CONSTRUCTOR && shouldDrawBackground; for (int i = 0; i < 2; i++) { EmojiTabsStrip emojiTabs = new EmojiTabsStrip(context, resourcesProvider, true, false, true, type, showSettings ? () -> { search(null, false, false); @@ -651,8 +654,10 @@ protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); } emojiTabs.animateAppear = bubbleX == null; - emojiTabs.setPaddingLeft(5); - contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + emojiTabs.setPaddingLeft(type == TYPE_CHAT_REACTIONS ? 10 : 5); + if (type != TYPE_EXPANDABLE_REACTIONS) { + contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + } cachedEmojiTabs[i] = emojiTabs; } @@ -669,7 +674,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } }; emojiTabsShadow.setBackgroundColor(Theme.getColor(Theme.key_divider, resourcesProvider)); - contentView.addView(emojiTabsShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.TOP, 0, 36, 0, 0)); + if (type != TYPE_EXPANDABLE_REACTIONS) { + contentView.addView(emojiTabsShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.TOP, 0, 36, 0, 0)); + } AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, true, 1f, false); emojiGridView = new EmojiListView(context) { @Override @@ -680,7 +687,7 @@ public void onScrolled(int dx, int dy) { updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS || type == TYPE_CHAT_REACTIONS, 1f, true); invalidateParent(); } @@ -708,7 +715,7 @@ protected float animateByScale(View view) { emojiItemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); emojiItemAnimator.setDelayAnimations(false); emojiGridView.setItemAnimator(emojiItemAnimator); - emojiGridView.setPadding(dp(5), dp(2), dp(5), dp(2 + 36)); + emojiGridView.setPadding(dp(5), dp(type == TYPE_CHAT_REACTIONS ? 8 : 2), dp(5), dp(2 + 36)); adapter = new Adapter(); emojiGridView.setAdapter(adapter); @@ -866,8 +873,8 @@ public int getSpanSize(int position) { }); emojiSearchGridView.setVisibility(View.GONE); gridViewContainer.addView(emojiSearchGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 0)); - contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 36 + (1 / AndroidUtilities.density), 0, 0)); - + contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, type == TYPE_EXPANDABLE_REACTIONS ? 0 : 36 + (1 / AndroidUtilities.density), 0, 0)); + scrollHelper = new RecyclerAnimationScrollHelper(emojiGridView, layoutManager); scrollHelper.setAnimationCallback(new RecyclerAnimationScrollHelper.AnimationCallback() { @Override @@ -887,7 +894,7 @@ public void onEndAnimation() { RecyclerListView.OnItemLongClickListenerExtended onItemLongClick = new RecyclerListView.OnItemLongClickListenerExtended() { @Override public boolean onItemClick(View view, int position, float x, float y) { - if (view instanceof ImageViewEmoji && type == TYPE_REACTIONS) { + if (view instanceof ImageViewEmoji && (type == TYPE_REACTIONS || type == TYPE_EXPANDABLE_REACTIONS)) { incrementHintUse(); if (!NekoConfig.disableVibration.Bool()) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -1086,7 +1093,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } private void onStickerClick(ImageViewEmoji viewEmoji, TLRPC.Document document) { - onEmojiSelected(viewEmoji, null, document, null); + if (type == TYPE_CHAT_REACTIONS) { + onEmojiSelected(viewEmoji, document.id, document, null); + } else { + onEmojiSelected(viewEmoji, null, document, null); + } } protected void onSettings() { @@ -1224,7 +1235,7 @@ private void updateSearchBox() { private Drawable getPremiumStar() { if (premiumStar == null) { - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { premiumStar = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_filled_blocked).mutate(); } else { premiumStar = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_settings_premium).mutate(); @@ -1917,7 +1928,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; if (viewType == VIEW_TYPE_HEADER) { - view = new HeaderView(getContext()); + view = new HeaderView(getContext(), type == TYPE_CHAT_REACTIONS); } else if (viewType == VIEW_TYPE_SEARCH) { view = new View(getContext()) { @Override @@ -2192,7 +2203,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; if (viewType == VIEW_TYPE_HEADER) { - view = new HeaderView(getContext()); + view = new HeaderView(getContext(), type == TYPE_CHAT_REACTIONS); } else if (viewType == VIEW_TYPE_IMAGE) { view = new ImageView(getContext()); } else if (viewType == VIEW_TYPE_EMOJI || viewType == VIEW_TYPE_REACTION || viewType == VIEW_TYPE_TOPIC_ICON) { @@ -2312,7 +2323,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi int index = positionToSection.get(position); if (index >= 0) { EmojiView.EmojiPack pack = packs.get(index); - header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON); + header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS); } else { header.setText(null, false); } @@ -2436,7 +2447,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; int recentSize; - if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers || type == TYPE_CHAT_REACTIONS) { recentSize = recentStickers.size(); } else if (type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_TOPIC_ICON) { recentSize = recent.size(); @@ -2460,6 +2471,10 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { TLRPC.Document document = recentStickers.get(resentPosition); imageView.setSticker(document, emojiGridView); + } else if (type == TYPE_CHAT_REACTIONS) { + TLRPC.Document document = recentStickers.get(resentPosition); + imageView.setSticker(document, emojiGridView); + selected = document != null && selectedDocumentIds.contains(document.id); } else { imageView.span = recent.get(resentPosition); imageView.document = imageView.span == null ? null : imageView.span.document; @@ -2547,12 +2562,12 @@ private class HeaderView extends FrameLayout { private RLottieImageView lockView; ImageView closeIcon; - public HeaderView(Context context) { + public HeaderView(Context context, boolean leftGravity) { super(context); layoutView = new LinearLayout(context); layoutView.setOrientation(LinearLayout.HORIZONTAL); - addView(layoutView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + addView(layoutView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, leftGravity ? Gravity.LEFT : Gravity.CENTER)); lockView = new RLottieImageView(context); lockView.setAnimation(R.raw.unlock_icon, 20, 20); @@ -2826,6 +2841,7 @@ public class ImageViewEmoji extends View { ValueAnimator backAnimator; PremiumLockIconView premiumLockIconView; public boolean selected; + private boolean shouldSelected; private float pressedProgress; public float skewAlpha; public int skewIndex; @@ -2912,6 +2928,66 @@ public void update(long time) { } } + private void cancelBackAnimator() { + if (backAnimator != null) { + backAnimator.removeAllListeners(); + backAnimator.cancel(); + } + } + + public void unselectWithScale() { + if (selected) { + cancelBackAnimator(); + pressedProgress = 1f; + backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + emojiGridView.invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + backAnimator = null; + } + }); + backAnimator.setInterpolator(new OvershootInterpolator(5.0f)); + backAnimator.setDuration(350); + backAnimator.start(); + setViewSelected(false, true); + } + } + + public void setViewSelectedWithScale(boolean selected, boolean animated) { + boolean wasSelected = this.selected; + if (!wasSelected && selected && animated) { + shouldSelected = true; + selectedProgress = 1f; + cancelBackAnimator(); + backAnimator = ValueAnimator.ofFloat(pressedProgress, 1.6f, 0.7f); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + emojiGridView.invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + pressedProgress = 0; + backAnimator = null; + shouldSelected = false; + setViewSelected(true, false); + } + }); + backAnimator.setInterpolator(new LinearInterpolator()); + backAnimator.setDuration(200); + backAnimator.start(); + } else { + shouldSelected = false; + setViewSelected(selected, animated); + } + } + public void setViewSelected(boolean selected, boolean animated) { if (this.selected != selected) { this.selected = selected; @@ -2922,23 +2998,24 @@ public void setViewSelected(boolean selected, boolean animated) { } public void drawSelected(Canvas canvas, View view) { - if ((selected || selectedProgress > 0) && !notDraw) { - if (selected && selectedProgress < 1f) { + if ((selected || shouldSelected || selectedProgress > 0) && !notDraw) { + if (((selected || shouldSelected) && selectedProgress < 1f)) { selectedProgress += 16 / 300f; view.invalidate(); } - if (!selected && selectedProgress > 0) { + if ((!selected && !shouldSelected && selectedProgress > 0)) { selectedProgress -= 16 / 300f; view.invalidate(); } selectedProgress = Utilities.clamp(selectedProgress, 1f, 0f); - + int inset = AndroidUtilities.dp(type == TYPE_CHAT_REACTIONS ? 1.5f : 1f); + int round = AndroidUtilities.dp(type == TYPE_CHAT_REACTIONS ? 6f : 4f); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - AndroidUtilities.rectTmp.inset(AndroidUtilities.dp(1), AndroidUtilities.dp(1)); + AndroidUtilities.rectTmp.inset(inset, inset); Paint paint = empty || drawable instanceof AnimatedEmojiDrawable && ((AnimatedEmojiDrawable) drawable).canOverrideColor() ? selectorAccentPaint : selectorPaint; int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * getAlpha() * selectedProgress)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, round, round, paint); paint.setAlpha(wasAlpha); } } @@ -2992,7 +3069,13 @@ public void setSticker(TLRPC.Document document, View parent) { this.document = document; createImageReceiver(parent); SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + if (type == TYPE_CHAT_REACTIONS) { + TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); + ImageLocation thumbLocation = ImageLocation.getForDocument(thumb, document); + imageReceiver.setImage(ImageLocation.getForDocument(document), !LiteMode.isEnabled(LiteMode.FLAG_ANIMATED_EMOJI_KEYBOARD) ? "34_34_firstframe" : "34_34", thumbLocation, null, svgThumb, document.size, null, document, 0); + } else { + imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + } isStaticIcon = true; span = null; } @@ -3086,7 +3169,7 @@ public void preload(int type, int account) { return; } MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_EMOJIPACKS); - if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { + if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_CHAT_REACTIONS) { MediaDataController.getInstance(account).checkReactions(); } else if (type == TYPE_EMOJI_STATUS) { MediaDataController.getInstance(account).fetchEmojiStatuses(0, true); @@ -3158,14 +3241,14 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff stickerSets.clear(); recentStickers.clear(); - if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON) { + if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS) { searchRow = totalCount++; rowHashCodes.add(9L); } else { searchRow = -1; } - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { if (includeEmpty) { totalCount++; rowHashCodes.add(2L); @@ -3199,6 +3282,20 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } + } else if (type == TYPE_CHAT_REACTIONS) { + if (includeEmpty) { + totalCount++; + rowHashCodes.add(2L); + } + List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); + for (int i = 0; i < enabledReactions.size(); ++i) { + TLRPC.TL_availableReaction reaction = enabledReactions.get(i); + recentStickers.add(reaction.activate_animation); + } + for (int i = 0; i < recentStickers.size(); ++i) { + rowHashCodes.add(62425L + 13L * recentStickers.get(i).id); + totalCount++; + } } else if (type == TYPE_TOPIC_ICON) { topicEmojiHeaderRow = totalCount++; rowHashCodes.add(12L); @@ -3235,7 +3332,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } - if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON) { + if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM) { longtapHintRow = totalCount++; rowHashCodes.add(6L); } @@ -3243,9 +3340,13 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff if (recentReactionsToSet != null) { topReactionsStartRow = totalCount; ArrayList tmp = new ArrayList<>(recentReactionsToSet); - for (int i = 0; i < 16; i++) { - if (!tmp.isEmpty()) { - topReactions.add(tmp.remove(0)); + if (type == TYPE_EXPANDABLE_REACTIONS) { + topReactions.addAll(tmp); + } else { + for (int i = 0; i < 16; i++) { + if (!tmp.isEmpty()) { + topReactions.add(tmp.remove(0)); + } } } for (int i = 0; i < topReactions.size(); ++i) { @@ -3254,7 +3355,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff totalCount += topReactions.size(); topReactionsEndRow = totalCount; - if (!tmp.isEmpty()) { + if (!tmp.isEmpty() && type != TYPE_EXPANDABLE_REACTIONS) { boolean allRecentReactionsIsDefault = true; for (int i = 0; i < tmp.size(); i++) { if (tmp.get(i).documentId != 0) { @@ -3364,13 +3465,13 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - if (installedEmojipacks != null) { + if (installedEmojipacks != null && type != TYPE_EXPANDABLE_REACTIONS) { for (int i = 0, j = 0; i < installedEmojipacks.size(); ++i) { TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); if (set == null || set.set == null) { continue; } - if (type == TYPE_SET_REPLY_ICON && !MessageObject.isTextColorSet(set)) { + if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && !MessageObject.isTextColorSet(set)) { continue; } if ((set.set.emojis || showStickers) && !installedEmojiSets.contains(set.set.id)) { @@ -3396,7 +3497,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - if (featuredEmojiPacks != null && !showStickers) { + if (featuredEmojiPacks != null && !showStickers && type != TYPE_EXPANDABLE_REACTIONS) { final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < featuredEmojiPacks.size(); ++i) { TLRPC.StickerSetCovered set1 = featuredEmojiPacks.get(i); @@ -3429,7 +3530,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff continue; } - if (type == TYPE_SET_REPLY_ICON && (documents.isEmpty() || !MessageObject.isTextColorEmoji(documents.get(0)))) { + if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && (documents.isEmpty() || !MessageObject.isTextColorEmoji(documents.get(0)))) { continue; } @@ -3461,7 +3562,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } - if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON) { + if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS) { positionToButton.put(totalCount, packs.size()); totalCount++; rowHashCodes.add(3321 + 13L * set.id); @@ -3471,7 +3572,9 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } - emojiTabs.updateEmojiPacks(packs); + if (type != TYPE_EXPANDABLE_REACTIONS) { + emojiTabs.updateEmojiPacks(packs); + } if (animated) { emojiGridView.setItemAnimator(emojiItemAnimator); @@ -3509,6 +3612,12 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { } } + public void notifyDataSetChanged() { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + public void expand(int position, View expandButton) { int index = positionToExpand.get(position); Integer from = null, count = null; @@ -3583,15 +3692,32 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(340 - 16), AndroidUtilities.displaySize.x * .95f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f), MeasureSpec.AT_MOST) ); + } else if (type == TYPE_CHAT_REACTIONS) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec((int) (AndroidUtilities.displaySize.y * .35f), MeasureSpec.AT_MOST)); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed && type == TYPE_CHAT_REACTIONS) { + int items = getMeasuredWidth() / AndroidUtilities.dp(42); + int spanCount = items * 5; + layoutManager.setSpanCount(spanCount); + } + } + private int getCacheType() { - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } + + if (type == TYPE_CHAT_REACTIONS) { + return AnimatedEmojiDrawable.getCacheTypeForEnterView(); + } + if (type == TYPE_TOPIC_ICON || type == TYPE_AVATAR_CONSTRUCTOR) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } @@ -3652,14 +3778,16 @@ public void dispatchDraw(Canvas canvas) { invalidated = false; int restoreTo = canvas.getSaveCount(); - if (!selectorRect.isEmpty()) { - selectorDrawable.setBounds(selectorRect); - canvas.save(); - if (selectorTransformer != null) { - selectorTransformer.accept(canvas); + if (type != TYPE_CHAT_REACTIONS) { + if (!selectorRect.isEmpty()) { + selectorDrawable.setBounds(selectorRect); + canvas.save(); + if (selectorTransformer != null) { + selectorTransformer.accept(canvas); + } + selectorDrawable.draw(canvas); + canvas.restore(); } - selectorDrawable.draw(canvas); - canvas.restore(); } for (int i = 0; i < viewsGroupedByLines.size(); i++) { @@ -3824,7 +3952,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { skewAlpha = .25f + .75f * skewAlpha; } } - boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || !lite || enterAnimationInProgress() || type == TYPE_AVATAR_CONSTRUCTOR; + boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || !lite || enterAnimationInProgress() || type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_CHAT_REACTIONS; if (!drawInUi) { boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); for (int i = 0; i < imageViewEmojis.size(); i++) { @@ -3898,7 +4026,7 @@ public void prepareDraw(long time) { ImageReceiver imageReceiver; if (imageView.empty) { Drawable drawable = getPremiumStar(); - float scale = type == TYPE_SET_REPLY_ICON ? 1.3f : 1f; + float scale = type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM ? 1.3f : 1f; if (imageView.pressedProgress != 0 || imageView.selected) { scale *= 0.8f + 0.2f * (1f - (imageView.selected ? .7f : imageView.pressedProgress)); } @@ -4061,7 +4189,7 @@ protected void drawInUiThread(Canvas canvas, float alpha) { Drawable drawable = null; if (imageView.empty) { drawable = getPremiumStar(); - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { AndroidUtilities.rectTmp2.inset((int) (-AndroidUtilities.rectTmp2.width() * .15f), (int) (-AndroidUtilities.rectTmp2.height() * .15f)); } drawable.setBounds(AndroidUtilities.rectTmp2); @@ -4087,11 +4215,15 @@ protected void drawInUiThread(Canvas canvas, float alpha) { imageView.skewIndex = i; if (scale != 1 || skewAlpha < 1) { canvas.save(); - if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { + if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_CHAT_REACTIONS) { //scale here only selected emoji canvas.scale(0.85f, 0.85f, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); } - skew(canvas, i, imageView.getHeight()); + if (type == TYPE_CHAT_REACTIONS) { + canvas.scale(scale, scale, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); + } else { + skew(canvas, i, imageView.getHeight()); + } drawImage(canvas, drawable, imageView, alpha); canvas.restore(); } else { @@ -4261,7 +4393,7 @@ public void didReceivedNotification(int id, int account, Object... args) { private AnimationNotificationsLocker notificationsLocker = new AnimationNotificationsLocker(); private boolean isAnimatedShow() { - return type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; + return type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_CHAT_REACTIONS; } public void onShow(Runnable dismiss) { @@ -4336,7 +4468,7 @@ public void onAnimationEnd(Animator animation) { } }); - if (isFirstOpen && type != TYPE_SET_REPLY_ICON) { + if (isFirstOpen && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM) { isFirstOpen = false; AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).setUiDbCallback(() -> { HwEmojis.enableHw(); @@ -4912,6 +5044,67 @@ public void setSelected(Long documentId) { } } + public void setMultiSelected(Long documentId, boolean animated) { + boolean isSelected; + if (!selectedDocumentIds.contains(documentId)) { + isSelected = true; + selectedDocumentIds.add(documentId); + } else { + isSelected = false; + selectedDocumentIds.remove(documentId); + } + if (emojiGridView != null) { + for (int i = 0; i < emojiGridView.getChildCount(); i++) { + if (emojiGridView.getChildAt(i) instanceof ImageViewEmoji) { + ImageViewEmoji imageViewEmoji = (ImageViewEmoji) emojiGridView.getChildAt(i); + if (imageViewEmoji.span != null && imageViewEmoji.span.getDocumentId() == documentId) { + imageViewEmoji.setViewSelectedWithScale(isSelected, animated); + } else if (imageViewEmoji.document != null && imageViewEmoji.document.id == documentId) { + imageViewEmoji.setViewSelectedWithScale(isSelected, animated); + } + } + } + emojiGridView.invalidate(); + } + } + + public boolean unselect(Long documentId) { + selectedDocumentIds.remove(documentId); + boolean found = false; + if (emojiGridView != null) { + for (int i = 0; i < emojiGridView.getChildCount(); i++) { + if (emojiGridView.getChildAt(i) instanceof ImageViewEmoji) { + ImageViewEmoji imageViewEmoji = (ImageViewEmoji) emojiGridView.getChildAt(i); + if (imageViewEmoji.span != null && imageViewEmoji.span.getDocumentId() == documentId) { + imageViewEmoji.unselectWithScale(); + found = true; + } else if (imageViewEmoji.document != null && imageViewEmoji.document.id == documentId) { + imageViewEmoji.unselectWithScale(); + found = true; + } + } + } + emojiGridView.invalidate(); + if (!found) { + for (int i = 0; i < rowHashCodes.size(); i++) { + long hash = rowHashCodes.get(i); + if (hash == 62425L + 13L * documentId || hash == 3212 + 13L * documentId) { + if (adapter != null) { + adapter.notifyItemChanged(i); + } + found = true; + break; + } + } + } + } + return found; + } + + public void clearSelectedDocuments() { + selectedDocumentIds.clear(); + } + public void setScrimDrawable(AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable, View drawableParent) { this.scrimColor = scrimDrawable == null || scrimDrawable.getColor() == null ? 0 : scrimDrawable.getColor(); this.scrimDrawable = scrimDrawable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 72475b6f03..536b08afc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -50,7 +50,6 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; @@ -89,9 +88,13 @@ import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.Stories.StoriesController; +import org.telegram.ui.Stories.StoriesListPlaceProvider; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Locale; @@ -113,6 +116,9 @@ public class StatisticActivity extends BaseFragment implements NotificationCente private ChartViewData newFollowersBySourceData; private ChartViewData languagesData; private ChartViewData notificationsData; + private ChartViewData reactionsByEmotionData; + private ChartViewData storyInteractionsData; + private ChartViewData storyReactionsByEmotionData; //chats private OverviewChatData overviewChatData; @@ -162,11 +168,17 @@ public StatisticActivity(Bundle args) { private int loadFromId = -1; private final SparseIntArray recentPostIdtoIndexMap = new SparseIntArray(); + private final SparseIntArray recentStoriesIdtoIndexMap = new SparseIntArray(); private final ArrayList recentPostsAll = new ArrayList<>(); private final ArrayList recentPostsLoaded = new ArrayList<>(); + private final ArrayList recentStoriesAll = new ArrayList<>(); + private final ArrayList recentStoriesLoaded = new ArrayList<>(); + private final ArrayList recentAllSortedDataLoaded = new ArrayList<>(); private boolean messagesIsLoading; private boolean initialLoading = true; private DiffUtilsCallback diffUtilsCallback; + private StoriesController.StoriesList storiesList; + private int storiesListId; private final Runnable showProgressbar = new Runnable() { @Override @@ -180,6 +192,12 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messagesDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.boostByChannelCreated); + getNotificationCenter().addObserver(this, NotificationCenter.storiesListUpdated); + StoriesController storiesController = getMessagesController().getStoriesController(); + storiesList = storiesController.getStoriesList(-chatId, StoriesController.StoriesList.TYPE_STATISTICS); + if (storiesList != null) { + storiesListId = storiesList.link(); + } if (chat != null) { loadStatistic(); } else { @@ -188,6 +206,13 @@ public boolean onFragmentCreate() { return super.onFragmentCreate(); } + private void sortAllLoadedData() { + recentAllSortedDataLoaded.clear(); + recentAllSortedDataLoaded.addAll(recentPostsLoaded); + recentAllSortedDataLoaded.addAll(recentStoriesLoaded); + Collections.sort(recentAllSortedDataLoaded, Collections.reverseOrder(Comparator.comparingLong(RecentPostInfo::getDate))); + } + private void loadStatistic() { if (onlyBoostsStat) { return; @@ -203,21 +228,23 @@ private void loadStatistic() { getBroadcastStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); } - int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response instanceof TLRPC.TL_stats_broadcastStats) { - final ChartViewData[] chartsViewData = new ChartViewData[9]; + final ChartViewData[] chartsViewData = new ChartViewData[12]; TLRPC.TL_stats_broadcastStats stats = (TLRPC.TL_stats_broadcastStats) response; chartsViewData[0] = createViewData(stats.iv_interactions_graph, LocaleController.getString("IVInteractionsChartTitle", R.string.IVInteractionsChartTitle), 1); chartsViewData[1] = createViewData(stats.followers_graph, LocaleController.getString("FollowersChartTitle", R.string.FollowersChartTitle), 0); chartsViewData[2] = createViewData(stats.top_hours_graph, LocaleController.getString("TopHoursChartTitle", R.string.TopHoursChartTitle), 0); - chartsViewData[3] = createViewData(stats.interactions_graph, LocaleController.getString("InteractionsChartTitle", R.string.InteractionsChartTitle), 1); + chartsViewData[3] = createViewData(stats.interactions_graph, LocaleController.getString("ViewsAndSharesChartTitle", R.string.ViewsAndSharesChartTitle), 1); chartsViewData[4] = createViewData(stats.growth_graph, LocaleController.getString("GrowthChartTitle", R.string.GrowthChartTitle), 0); chartsViewData[5] = createViewData(stats.views_by_source_graph, LocaleController.getString("ViewsBySourceChartTitle", R.string.ViewsBySourceChartTitle), 2); chartsViewData[6] = createViewData(stats.new_followers_by_source_graph, LocaleController.getString("NewFollowersBySourceChartTitle", R.string.NewFollowersBySourceChartTitle), 2); chartsViewData[7] = createViewData(stats.languages_graph, LocaleController.getString("LanguagesChartTitle", R.string.LanguagesChartTitle), 4, true); chartsViewData[8] = createViewData(stats.mute_graph, LocaleController.getString("NotificationsChartTitle", R.string.NotificationsChartTitle), 0); + chartsViewData[9] = createViewData(stats.reactions_by_emotion_graph, LocaleController.getString("ReactionsByEmotionChartTitle", R.string.ReactionsByEmotionChartTitle), 2); + chartsViewData[10] = createViewData(stats.story_interactions_graph, LocaleController.getString("StoryInteractionsChartTitle", R.string.StoryInteractionsChartTitle), 1); + chartsViewData[11] = createViewData(stats.story_reactions_by_emotion_graph, LocaleController.getString("StoryReactionsByEmotionChartTitle", R.string.StoryReactionsByEmotionChartTitle), 2); if (chartsViewData[2] != null) { chartsViewData[2].useHourFormat = true; @@ -229,15 +256,35 @@ private void loadStatistic() { recentPostsAll.clear(); - for (int i = 0; i < stats.recent_message_interactions.size(); i++) { + int msgPos = 0; + int storiesPos = 0; + List storiesIds = new ArrayList<>(); + for (TLRPC.PostInteractionCounters interactionCounters : stats.recent_posts_interactions) { RecentPostInfo recentPostInfo = new RecentPostInfo(); - recentPostInfo.counters = stats.recent_message_interactions.get(i); - recentPostsAll.add(recentPostInfo); - recentPostIdtoIndexMap.put(recentPostInfo.counters.msg_id, i); + recentPostInfo.counters = interactionCounters; + + if (interactionCounters instanceof TLRPC.TL_postInteractionCountersMessage) { + recentPostsAll.add(recentPostInfo); + recentPostIdtoIndexMap.put(recentPostInfo.getId(), msgPos); + msgPos++; + } + if (interactionCounters instanceof TLRPC.TL_postInteractionCountersStory) { + storiesIds.add(recentPostInfo.getId()); + recentStoriesAll.add(recentPostInfo); + recentStoriesIdtoIndexMap.put(recentPostInfo.getId(), storiesPos); + storiesPos++; + } } + AndroidUtilities.runOnUIThread(() -> { + if (!storiesList.load(storiesIds)) { + prepareStoriesLoadedItems(); + sortAllLoadedData(); + } + }); + if (recentPostsAll.size() > 0) { - int lastPostId = recentPostsAll.get(0).counters.msg_id; + int lastPostId = recentPostsAll.get(0).getId(); int count = recentPostsAll.size(); getMessagesStorage().getMessages(-chatId, 0, false, count, lastPostId, 0, 0, classGuid, 0, false, 0, 0, true, false, null); } @@ -254,6 +301,10 @@ private void loadStatistic() { languagesData = chartsViewData[7]; notificationsData = chartsViewData[8]; + reactionsByEmotionData = chartsViewData[9]; + storyInteractionsData = chartsViewData[10]; + storyReactionsByEmotionData = chartsViewData[11]; + dataLoaded(chartsViewData); }); @@ -359,17 +410,45 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.boostByChannelCreated); getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.storiesListUpdated); + if (progressDialog[0] != null) { progressDialog[0].dismiss(); progressDialog[0] = null; } + if (storiesList != null) { + storiesList.unlink(storiesListId); + } super.onFragmentDestroy(); } + private void prepareStoriesLoadedItems() { + recentStoriesLoaded.clear(); + for (RecentPostInfo recentPostInfo : recentStoriesAll) { + MessageObject messageObject = storiesList.findMessageObject(recentPostInfo.getId()); + if (messageObject != null) { + recentPostInfo.message = messageObject; + recentStoriesLoaded.add(recentPostInfo); + } + } + recentStoriesIdtoIndexMap.clear(); + recentStoriesAll.clear(); + } + @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.boostByChannelCreated) { + if (id == NotificationCenter.storiesListUpdated) { + StoriesController.StoriesList list = (StoriesController.StoriesList) args[0]; + if (list == storiesList) { + prepareStoriesLoadedItems(); + sortAllLoadedData(); + if (adapter != null) { + recyclerListView.setItemAnimator(null); + diffUtilsCallback.update(); + } + } + } else if (id == NotificationCenter.boostByChannelCreated) { TLRPC.Chat chat = (TLRPC.Chat) args[0]; boolean isGiveaway = (boolean) args[1]; List fragmentStack = getParentLayout().getFragmentStack(); @@ -403,7 +482,7 @@ public void didReceivedNotification(int id, int account, Object... args) { for (int i = 0; i < n; i++) { MessageObject messageObjectFormCache = messArr.get(i); int index = recentPostIdtoIndexMap.get(messageObjectFormCache.getId(), -1); - if (index >= 0 && recentPostsAll.get(index).counters.msg_id == messageObjectFormCache.getId()) { + if (index >= 0 && recentPostsAll.get(index).getId() == messageObjectFormCache.getId()) { if (messageObjectFormCache.deleted) { deletedMessages.add(recentPostsAll.get(index)); } else { @@ -419,7 +498,7 @@ public void didReceivedNotification(int id, int account, Object... args) { for (int i = 0; i < n; i++) { RecentPostInfo postInfo = recentPostsAll.get(i); if (postInfo.message == null) { - loadFromId = postInfo.counters.msg_id; + loadFromId = postInfo.getId(); break; } else { recentPostsLoaded.add(postInfo); @@ -429,6 +508,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (recentPostsLoaded.size() < 20) { loadMessages(); } + sortAllLoadedData(); if (adapter != null) { recyclerListView.setItemAnimator(null); diffUtilsCallback.update(); @@ -450,13 +530,15 @@ public View createView(Context context) { sharedUi = new BaseChartView.SharedUiComponents(); boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chatId, currentAccount); BottomPagerTabs storiesTabsView = new BottomPagerTabs(context, getResourceProvider()) { - @Override public Tab[] createTabs() { Tab[] tabs = new Tab[]{ new Tab(0, R.raw.stats, LocaleController.getString("Statistics", R.string.Statistics)), new Tab(1, R.raw.boosts, LocaleController.getString("Boosts", R.string.Boosts)) }; + tabs[0].customFrameInvert = true; + tabs[0].customEndFrameMid = 25; + tabs[0].customEndFrameEnd = 49; tabs[1].customEndFrameMid = 25; tabs[1].customEndFrameEnd = 49; return tabs; @@ -600,8 +682,8 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { recyclerListView.setOnItemClickListener((view, position) -> { if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { - MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; - MessageStatisticActivity activity = new MessageStatisticActivity(messageObject); + RecentPostInfo recentPostInfo = recentAllSortedDataLoaded.get(position - adapter.recentPostsStartRow); + MessageStatisticActivity activity = new MessageStatisticActivity(recentPostInfo, chatId, true); presentFragment(activity); } else if (position >= adapter.topAdminsStartRow && position <= adapter.topAdminsEndRow) { int i = position - adapter.topAdminsStartRow; @@ -628,7 +710,11 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { recyclerListView.setOnItemLongClickListener((view, position) -> { if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { - MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; + MessageObject messageObject = recentAllSortedDataLoaded.get(position - adapter.recentPostsStartRow).message; + + if (messageObject.isStory()) { + return false; + } final ArrayList items = new ArrayList<>(); final ArrayList actions = new ArrayList<>(); @@ -680,12 +766,15 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { avatarContainer = new ChatAvatarContainer(context, null, false); avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet()); - actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + avatarContainer.getAvatarImageView().setScaleX(0.9f); + avatarContainer.getAvatarImageView().setScaleY(0.9f); + avatarContainer.setRightAvatarPadding(-AndroidUtilities.dp(3)); + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 50 : 0, 0, 40, 0)); TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); + avatarContainer.setTitle(chatLocal == null ? "" : chatLocal.title); avatarContainer.hideSubtitle(); actionBar.setBackButtonDrawable(new BackDrawable(false)); @@ -703,7 +792,6 @@ public void onItemClick(final int id) { actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - if (initialLoading) { progressLayout.setAlpha(0f); AndroidUtilities.runOnUIThread(showProgressbar, 500); @@ -783,6 +871,9 @@ class Adapter extends RecyclerListView.SelectionAdapter { int newFollowersBySourceCell = -1; int languagesCell = -1; int notificationsCell = -1; + int reactionsByEmotionCell = -1; + int storyInteractionsCell = -1; + int storyReactionsByEmotionCell = -1; int recentPostsHeaderCell = -1; int recentPostsStartRow = -1; @@ -816,9 +907,9 @@ class Adapter extends RecyclerListView.SelectionAdapter { public int getItemViewType(int position) { if (position == growCell || position == folowersCell || position == topHourseCell || position == notificationsCell || position == actionsCell || position == groupMembersCell) { return 0; - } else if (position == interactionsCell || position == ivInteractionsCell) { + } else if (position == interactionsCell || position == ivInteractionsCell || position == storyInteractionsCell) { return 1; - } else if (position == viewsBySourceCell || position == newFollowersBySourceCell || position == newMembersBySourceCell || position == messagesCell) { + } else if (position == viewsBySourceCell || position == newFollowersBySourceCell || position == newMembersBySourceCell || position == messagesCell || position == reactionsByEmotionCell || position == storyReactionsByEmotionCell) { return 2; } else if (position == languagesCell || position == membersLanguageCell || position == topDayOfWeeksCell) { return 4; @@ -847,7 +938,7 @@ public int getItemViewType(int position) { @Override public long getItemId(int position) { if (position >= recentPostsStartRow && position < recentPostsEndRow) { - return recentPostsLoaded.get(position - recentPostsStartRow).counters.msg_id; + return recentAllSortedDataLoaded.get(position - recentPostsStartRow).getId(); } if (position == growCell) { return 1; @@ -879,6 +970,12 @@ public long getItemId(int position) { return 14; } else if (position == topDayOfWeeksCell) { return 15; + } else if (position == reactionsByEmotionCell) { + return 16; + } else if (position == storyInteractionsCell) { + return 17; + } else if (position == storyReactionsByEmotionCell) { + return 18; } return super.getItemId(position); } @@ -898,7 +995,7 @@ protected void onDraw(Canvas canvas) { }; v.setWillNotDraw(false); } else if (viewType == 9) { - v = new StatisticPostInfoCell(parent.getContext(), chat) { + v = new StatisticPostInfoCell(parent.getContext(), chat, getResourceProvider()) { @Override protected void onDraw(Canvas canvas) { if (getTranslationY() != 0) { @@ -927,7 +1024,7 @@ protected void onDraw(Canvas canvas) { headerCell.setPadding(headerCell.getPaddingLeft(), AndroidUtilities.dp(16), headerCell.getRight(), AndroidUtilities.dp(16)); v = headerCell; } else if (viewType == 14) { - v = new OverviewCell(parent.getContext()); + v = new OverviewCell(parent.getContext(), isMegagroup ? 2 : 4); } else if (viewType == 15) { v = new ManageChatTextCell(parent.getContext()); v.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -960,6 +1057,12 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi data = topHoursData; } else if (notificationsCell == position) { data = notificationsData; + } else if (reactionsByEmotionCell == position) { + data = reactionsByEmotionData; + } else if (storyInteractionsCell == position) { + data = storyInteractionsData; + } else if (storyReactionsByEmotionCell == position) { + data = storyReactionsByEmotionData; } else if (groupMembersCell == position) { data = groupMembersData; } else if (newMembersBySourceCell == position) { @@ -990,11 +1093,20 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } } else { int i = position - recentPostsStartRow; - ((StatisticPostInfoCell) holder.itemView).setData(recentPostsLoaded.get(i)); + RecentPostInfo recentPostInfo = recentAllSortedDataLoaded.get(i); + StatisticPostInfoCell cell = ((StatisticPostInfoCell) holder.itemView); + cell.setData(recentPostInfo, i == recentAllSortedDataLoaded.size() - 1); + if (recentPostInfo.isStory()) { + cell.setImageViewAction(v -> getOrCreateStoryViewer().open(getContext(), recentPostInfo.getId(), storiesList, StoriesListPlaceProvider.of(recyclerListView))); + } else { + cell.setImageViewAction(null); + } } } else if (type == 13) { ChartHeaderView headerCell = (ChartHeaderView) holder.itemView; + headerCell.showDate(true); headerCell.setDates(minDateOverview, maxDateOverview); + headerCell.setPadding(0, AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16)); if (position == overviewHeaderCell) { headerCell.setTitle(LocaleController.getString("StatisticOverview", R.string.StatisticOverview)); } else if (position == topAdminsHeaderCell) { @@ -1004,14 +1116,16 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } else if (position == topMembersHeaderCell) { headerCell.setTitle(LocaleController.getString("TopMembers", R.string.TopMembers)); } else { - headerCell.setTitle(LocaleController.getString("RecentPosts", R.string.RecentPosts)); + headerCell.showDate(false); + headerCell.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(15), AndroidUtilities.dp(2), AndroidUtilities.dp(6)); + headerCell.setTitle(LocaleController.getString("RecentPostsCapitalize", R.string.RecentPostsCapitalize)); } } else if (type == 14) { OverviewCell overviewCell = (OverviewCell) holder.itemView; if (isMegagroup) { overviewCell.setData(overviewChatData); } else { - overviewCell.setData(overviewChannelData); + overviewCell.setData(overviewChannelData, chat); } } else if (type == 15) { ManageChatTextCell manageChatTextCell = (ManageChatTextCell) holder.itemView; @@ -1038,6 +1152,9 @@ public void update() { ivInteractionsCell = -1; topHourseCell = -1; notificationsCell = -1; + storyReactionsByEmotionCell = -1; + storyInteractionsCell = -1; + reactionsByEmotionCell = -1; groupMembersCell = -1; newMembersBySourceCell = -1; membersLanguageCell = -1; @@ -1216,13 +1333,31 @@ public void update() { } ivInteractionsCell = count++; } + if (reactionsByEmotionData != null && !reactionsByEmotionData.isEmpty && !reactionsByEmotionData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + reactionsByEmotionCell = count++; + } + if (storyInteractionsData != null && !storyInteractionsData.isEmpty && !storyInteractionsData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + storyInteractionsCell = count++; + } + if (storyReactionsByEmotionData != null && !storyReactionsByEmotionData.isEmpty && !storyReactionsByEmotionData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + storyReactionsByEmotionCell = count++; + } shadowDivideCells.add(count++); - if (recentPostsAll.size() > 0) { + if (recentAllSortedDataLoaded.size() > 0) { recentPostsHeaderCell = count++; recentPostsStartRow = count++; - count = recentPostsEndRow = recentPostsStartRow + recentPostsLoaded.size() - 1; + count = recentPostsEndRow = recentPostsStartRow + recentAllSortedDataLoaded.size() - 1; count++; if (recentPostsLoaded.size() != recentPostsAll.size()) { @@ -1348,6 +1483,11 @@ public static abstract class BaseChartCell extends FrameLayout { @SuppressLint("ClickableViewAccessibility") public BaseChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi) { + this(context, type, sharedUi, null); + } + + @SuppressLint("ClickableViewAccessibility") + public BaseChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi, Theme.ResourcesProvider resourcesProvider) { super(context); setWillNotDraw(false); chartType = type; @@ -1389,19 +1529,19 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } } }; - chartHeaderView = new ChartHeaderView(getContext()); + chartHeaderView = new ChartHeaderView(getContext(), resourcesProvider); chartHeaderView.back.setOnTouchListener(new RecyclerListView.FoucsableOnTouchListener()); chartHeaderView.back.setOnClickListener(v -> zoomOut(true)); switch (type) { case 1: - chartView = new DoubleLinearChartView(getContext()); - zoomedChartView = new DoubleLinearChartView(getContext()); + chartView = new DoubleLinearChartView(getContext(), resourcesProvider); + zoomedChartView = new DoubleLinearChartView(getContext(), resourcesProvider); zoomedChartView.legendSignatureView.useHour = true; break; case 2: - chartView = new StackBarChartView(getContext()); - zoomedChartView = new StackBarChartView(getContext()); + chartView = new StackBarChartView(getContext(), resourcesProvider); + zoomedChartView = new StackBarChartView(getContext(), resourcesProvider); zoomedChartView.legendSignatureView.useHour = true; break; case 3: @@ -1437,7 +1577,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto frameLayout.addView(errorTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); progressView.setVisibility(View.GONE); - errorTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray4)); + errorTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray4, resourcesProvider)); chartView.setDateSelectionListener(date -> { @@ -1705,6 +1845,8 @@ public void updateData(ChartViewData viewData, boolean enterTransition) { } errorTextView.setVisibility(View.VISIBLE); } + checkboxContainer.removeAllViews(); + checkBoxes.clear(); chartView.setData(null); return; } @@ -1989,8 +2131,59 @@ public void load(int accountId, int classGuid, int dc, RecyclerListView recycler } public static class RecentPostInfo { - public TLRPC.TL_messageInteractionCounters counters; + public TLRPC.PostInteractionCounters counters; public MessageObject message; + + public long getDate() { + if (message == null) { + return 0; + } + return message.messageOwner.date; + } + + public boolean isStory() { + return counters instanceof TLRPC.TL_postInteractionCountersStory; + } + + public int getViews() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).views; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).views; + } + return 0; + } + + public int getReactions() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).reactions; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).reactions; + } + return 0; + } + + public int getForwards() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).forwards; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).forwards; + } + return 0; + } + + public int getId() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).msg_id; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).story_id; + } + return 0; + } } private void loadMessages() { @@ -2001,7 +2194,7 @@ private void loadMessages() { int count = 0; for (int i = index; i < n; i++) { if (recentPostsAll.get(i).message == null) { - req.id.add(recentPostsAll.get(i).counters.msg_id); + req.id.add(recentPostsAll.get(i).getId()); count++; if (count > 50) { break; @@ -2031,7 +2224,7 @@ private void loadMessages() { for (int i = 0; i < size; i++) { MessageObject messageObjectFormCache = messageObjects.get(i); int localIndex = recentPostIdtoIndexMap.get(messageObjectFormCache.getId(), -1); - if (localIndex >= 0 && recentPostsAll.get(localIndex).counters.msg_id == messageObjectFormCache.getId()) { + if (localIndex >= 0 && recentPostsAll.get(localIndex).getId() == messageObjectFormCache.getId()) { recentPostsAll.get(localIndex).message = messageObjectFormCache; } } @@ -2041,12 +2234,13 @@ private void loadMessages() { for (int i = 0; i < size; i++) { RecentPostInfo postInfo = recentPostsAll.get(i); if (postInfo.message == null) { - loadFromId = postInfo.counters.msg_id; + loadFromId = postInfo.getId(); break; } else { recentPostsLoaded.add(postInfo); } } + sortAllLoadedData(); recyclerListView.setItemAnimator(null); diffUtilsCallback.update(); }); @@ -2085,6 +2279,9 @@ private static class DiffUtilsCallback extends DiffUtil.Callback { int languagesCell = -1; int topHourseCell = -1; int notificationsCell = -1; + int reactionsByEmotionCell = -1; + int storyInteractionsCell = -1; + int storyReactionsByEmotionCell = -1; int groupMembersCell = -1; int newMembersBySourceCell = -1; @@ -2118,6 +2315,9 @@ public void saveOldState() { notificationsCell = adapter.notificationsCell; startPosts = adapter.recentPostsStartRow; endPosts = adapter.recentPostsEndRow; + reactionsByEmotionCell = adapter.reactionsByEmotionCell; + storyInteractionsCell = adapter.storyInteractionsCell; + storyReactionsByEmotionCell = adapter.storyReactionsByEmotionCell; groupMembersCell = adapter.groupMembersCell; newMembersBySourceCell = adapter.newMembersBySourceCell; @@ -2178,6 +2378,12 @@ public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return true; } else if (oldItemPosition == topDayOfWeeksCell && newItemPosition == adapter.topDayOfWeeksCell) { return true; + } else if (oldItemPosition == reactionsByEmotionCell && newItemPosition == adapter.reactionsByEmotionCell) { + return true; + } else if (oldItemPosition == storyInteractionsCell && newItemPosition == adapter.storyInteractionsCell) { + return true; + } else if (oldItemPosition == storyReactionsByEmotionCell && newItemPosition == adapter.storyReactionsByEmotionCell) { + return true; } return false; } @@ -2256,6 +2462,7 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"message"}, null, null, null, Theme.key_dialogTextBlack)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"views"}, null, null, null, Theme.key_dialogTextBlack)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"shares"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); + arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"likes"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"date"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{ChartHeaderView.class}, new String[]{"textView"}, null, null, null, Theme.key_dialogTextBlack)); @@ -2307,7 +2514,7 @@ public ArrayList getThemeDescriptions() { putColorFromData(chartViewData, arrayList, themeDelegate); } } else { - for (int i = 0; i < 9; i++) { + for (int i = 0; i < 12; i++) { ChartViewData chartViewData; if (i == 0) { chartViewData = growthData; @@ -2325,9 +2532,16 @@ public ArrayList getThemeDescriptions() { chartViewData = notificationsData; } else if (i == 7) { chartViewData = topHoursData; - } else { + } else if (i == 8) { chartViewData = languagesData; + } else if (i == 9) { + chartViewData = reactionsByEmotionData; + } else if (i == 10) { + chartViewData = storyInteractionsData; + } else { + chartViewData = storyReactionsByEmotionData; } + putColorFromData(chartViewData, arrayList, themeDelegate); } } @@ -2369,7 +2583,90 @@ public static class OverviewChannelData { String notificationsTitle; String notificationsPrimary; + String reactionsPerPostTitle; + String reactionsPerPostPrimary; + String reactionsPerPostSecondary; + boolean reactionsPerPostUp; + boolean reactionsPerPostVisible; + + String reactionsPerStoryTitle; + String reactionsPerStoryPrimary; + String reactionsPerStorySecondary; + boolean reactionsPerStoryUp; + boolean reactionsPerStoryVisible; + + String viewsPerStoryTitle; + String viewsPerStoryPrimary; + String viewsPerStorySecondary; + boolean viewsPerStoryUp; + boolean viewsPerStoryVisible; + + String sharesPerStoryTitle; + String sharesPerStoryPrimary; + String sharesPerStorySecondary; + boolean sharesPerStoryUp; + boolean sharesPerStoryVisible; + + public static class Quadruple { + public Quadruple(A fist, B second, C third, D fourth) { + this.fist = fist; + this.second = second; + this.third = third; + this.fourth = fourth; + } + + public A fist; + public B second; + public C third; + public D fourth; + } + + private Quadruple prepare(TLRPC.TL_statsAbsValueAndPrev valueAndPrev) { + int dif = (int) (valueAndPrev.current - valueAndPrev.previous); + float difPercent = valueAndPrev.previous == 0 ? 0 : Math.abs(dif / (float) valueAndPrev.previous * 100f); + String primary = AndroidUtilities.formatWholeNumber((int) valueAndPrev.current, 0); + String secondary; + if (dif == 0 || difPercent == 0) { + secondary = ""; + } else if (difPercent == (int) difPercent) { + secondary = String.format(Locale.ENGLISH, "%s (%d%s)", (dif > 0 ? "+" : "") + AndroidUtilities.formatWholeNumber(dif, 0), (int) difPercent, "%"); + } else { + secondary = String.format(Locale.ENGLISH, "%s (%.1f%s)", (dif > 0 ? "+" : "") + AndroidUtilities.formatWholeNumber(dif, 0), difPercent, "%"); + } + boolean up = dif >= 0; + boolean isSectionVisible = dif != 0 || valueAndPrev.current != 0; + return new Quadruple<>(primary, secondary, up, isSectionVisible); + } + public OverviewChannelData(TLRPC.TL_stats_broadcastStats stats) { + Quadruple quadrupleData = prepare(stats.reactions_per_post); + reactionsPerPostTitle = LocaleController.getString("ReactionsPerPost", R.string.ReactionsPerPost); + reactionsPerPostPrimary = quadrupleData.fist; + reactionsPerPostSecondary = quadrupleData.second; + reactionsPerPostUp = quadrupleData.third; + reactionsPerPostVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.reactions_per_story); + reactionsPerStoryTitle = LocaleController.getString("ReactionsPerStory", R.string.ReactionsPerStory); + reactionsPerStoryPrimary = quadrupleData.fist; + reactionsPerStorySecondary = quadrupleData.second; + reactionsPerStoryUp = quadrupleData.third; + reactionsPerStoryVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.views_per_story); + viewsPerStoryTitle = LocaleController.getString("ViewsPerStory", R.string.ViewsPerStory); + viewsPerStoryPrimary = quadrupleData.fist; + viewsPerStorySecondary = quadrupleData.second; + viewsPerStoryUp = quadrupleData.third; + viewsPerStoryVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.shares_per_story); + sharesPerStoryTitle = LocaleController.getString("SharesPerStory", R.string.SharesPerStory); + sharesPerStoryPrimary = quadrupleData.fist; + sharesPerStorySecondary = quadrupleData.second; + sharesPerStoryUp = quadrupleData.third; + sharesPerStoryVisible = quadrupleData.fourth; + int dif = (int) (stats.followers.current - stats.followers.previous); float difPercent = stats.followers.previous == 0 ? 0 : Math.abs(dif / (float) stats.followers.previous * 100f); followersTitle = LocaleController.getString("FollowersChartTitle", R.string.FollowersChartTitle); @@ -2497,16 +2794,22 @@ public OverviewChatData(TLRPC.TL_stats_megagroupStats stats) { public static class OverviewCell extends LinearLayout { - TextView[] primary = new TextView[4]; - TextView[] secondary = new TextView[4]; - TextView[] title = new TextView[4]; - + TextView[] primary; + TextView[] secondary; + TextView[] title; public OverviewCell(Context context) { + this(context, 2); + } + + public OverviewCell(Context context, int maxRows) { super(context); + primary = new TextView[maxRows * 2]; + secondary = new TextView[maxRows * 2]; + title = new TextView[maxRows * 2]; setOrientation(VERTICAL); - setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(16)); - for (int i = 0; i < 2; i++) { + setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + for (int i = 0; i < maxRows; i++) { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(HORIZONTAL); @@ -2520,9 +2823,10 @@ public OverviewCell(Context context) { secondary[i * 2 + j] = new TextView(context); title[i * 2 + j] = new TextView(context); - primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); primary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); title[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + title[i * 2 + j].setGravity(Gravity.LEFT); secondary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); secondary[i * 2 + j].setPadding(AndroidUtilities.dp(4), 0, 0, 0); @@ -2534,29 +2838,88 @@ public OverviewCell(Context context) { contentCell.addView(title[i * 2 + j]); linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); } - addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, i == 0 ? 16 : 0)); + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 16)); } } - public void setData(OverviewChannelData data) { - primary[0].setText(data.followersPrimary); - primary[1].setText(data.notificationsPrimary); - primary[2].setText(data.viewsPrimary); - primary[3].setText(data.sharesPrimary); - - secondary[0].setText(data.followersSecondary); - secondary[0].setTag(data.followersUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - secondary[1].setText(""); - secondary[2].setText(data.viewsSecondary); - secondary[2].setTag(data.viewsUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - secondary[3].setText(data.sharesSecondary); - secondary[3].setTag(data.sharesUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - - title[0].setText(data.followersTitle); - title[1].setText(data.notificationsTitle); - title[2].setText(data.viewsTitle); - title[3].setText(data.sharesTitle); - + public void setData(OverviewChannelData data, TLRPC.ChatFull chatFull) { + int k = 0; + for (int i = 0; i < primary.length; i++) { + switch (i) { + case 0: + primary[k].setText(data.followersPrimary); + secondary[k].setText(data.followersSecondary); + secondary[k].setTag(data.followersUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.followersTitle); + k++; + break; + case 1: + primary[k].setText(data.notificationsPrimary); + secondary[k].setText(""); + title[k].setText(data.notificationsTitle); + k++; + break; + case 2: + primary[k].setText(data.viewsPrimary); + secondary[k].setText(data.viewsSecondary); + secondary[k].setTag(data.viewsUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.viewsTitle); + k++; + break; + case 3: + primary[k].setText(data.viewsPerStoryPrimary); + secondary[k].setText(data.viewsPerStorySecondary); + secondary[k].setTag(data.viewsPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.viewsPerStoryTitle); + if (data.viewsPerStoryVisible) { + k++; + } + break; + case 4: + primary[k].setText(data.sharesPrimary); + secondary[k].setText(data.sharesSecondary); + secondary[k].setTag(data.sharesUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.sharesTitle); + k++; + break; + case 5: + primary[k].setText(data.sharesPerStoryPrimary); + secondary[k].setText(data.sharesPerStorySecondary); + secondary[k].setTag(data.sharesPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.sharesPerStoryTitle); + if (data.sharesPerStoryVisible) { + k++; + } + break; + case 6: + primary[k].setText(data.reactionsPerPostPrimary); + secondary[k].setText(data.reactionsPerPostSecondary); + secondary[k].setTag(data.reactionsPerPostUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.reactionsPerPostTitle); + if (data.reactionsPerPostVisible) { + k++; + } + break; + case 7: + primary[k].setText(data.reactionsPerStoryPrimary); + secondary[k].setText(data.reactionsPerStorySecondary); + secondary[k].setTag(data.reactionsPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.reactionsPerStoryTitle); + if (data.reactionsPerStoryVisible) { + k++; + } + break; + } + } + for (int i = k; i < primary.length; i++) { + ((ViewGroup) title[i].getParent()).setVisibility(GONE); + } + for (int i = 0; i < getChildCount(); i++) { + ViewGroup viewGroup = (ViewGroup) getChildAt(i); + if (viewGroup.getChildAt(0).getVisibility() == GONE && viewGroup.getChildAt(1).getVisibility() == GONE) { + viewGroup.setVisibility(GONE); + } + } updateColors(); } @@ -2594,7 +2957,7 @@ public void setData(int index, String primary, String secondary, String title) { } private void updateColors() { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < primary.length; i++) { primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java index 2eb82b3b92..2c76eab601 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java @@ -10,11 +10,7 @@ import androidx.core.graphics.ColorUtils; -import com.google.android.exoplayer2.util.Log; - -import org.checkerframework.checker.units.qual.C; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ActionBar.ThemeColors; import java.util.HashSet; import java.util.Objects; @@ -29,7 +25,13 @@ public class DarkThemeResourceProvider implements Theme.ResourcesProvider { ColorFilter animatedEmojiColorFilter; public DarkThemeResourceProvider() { - + sparseIntArray.put(Theme.key_statisticChartSignature, -1214008894); + sparseIntArray.put(Theme.key_statisticChartSignatureAlpha, -1946157057); + sparseIntArray.put(Theme.key_statisticChartHintLine, 452984831); + sparseIntArray.put(Theme.key_statisticChartActiveLine, -665229191); + sparseIntArray.put(Theme.key_statisticChartInactivePickerChart, -667862461); + sparseIntArray.put(Theme.key_statisticChartActivePickerChart, -665229191); + sparseIntArray.put(Theme.key_player_actionBarTitle, Color.WHITE); sparseIntArray.put(Theme.key_dialogIcon, Color.WHITE); sparseIntArray.put(Theme.key_text_RedBold, 0xFFDB4646); sparseIntArray.put(Theme.key_dialogButton, -10177041); @@ -79,7 +81,6 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_chat_messageLinkOut, -5316609); sparseIntArray.put(Theme.key_chat_messagePanelText, -1); sparseIntArray.put(Theme.key_chat_messagePanelIcons, Color.WHITE); - sparseIntArray.put(Theme.key_chat_messagePanelIcons, Color.WHITE); sparseIntArray.put(Theme.key_chat_messagePanelBackground, ColorUtils.setAlphaComponent(Color.BLACK, 122)); sparseIntArray.put(Theme.key_dialogBackground, 0xFF1F1F1F); sparseIntArray.put(Theme.key_dialogBackgroundGray, 0xff000000); @@ -111,6 +112,11 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_actionBarDefaultSubmenuSeparator, 0xF2151515); sparseIntArray.put(Theme.key_chat_emojiPanelStickerSetNameHighlight, Color.WHITE); sparseIntArray.put(Theme.key_windowBackgroundWhiteGrayText4, 0xFF808080); + sparseIntArray.put(Theme.key_voipgroup_nameText, 0xffffffff); + sparseIntArray.put(Theme.key_voipgroup_inviteMembersBackground, 0xff222A33); + sparseIntArray.put(Theme.key_chats_secretName, -9316522); + sparseIntArray.put(Theme.key_chats_name, -1446156); + sparseIntArray.put(Theme.key_chat_serviceBackground, -2110438831); sparseIntArray.put(Theme.key_switchTrack, 0xFF636363); sparseIntArray.put(Theme.key_switchTrackChecked, 0xFF1A9CFF); @@ -118,6 +124,7 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_dialogRadioBackgroundChecked, 0xFF1A9CFF); sparseIntArray.put(Theme.key_dialogTextBlue2, 0xFF1A9CFF); sparseIntArray.put(Theme.key_color_red, -832444); + sparseIntArray.put(Theme.key_checkbox, -12692893); sparseIntArray.put(Theme.key_checkboxDisabled, 0xff626262); sparseIntArray.put(Theme.key_dialogRoundCheckBoxCheck, 0xffffffff); sparseIntArray.put(Theme.key_dialogButtonSelector, 436207615); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index 87556b5d14..d548f11b65 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java @@ -1165,7 +1165,7 @@ public void setDialogId(long dialogId) { avatarImage.clearImage(); return; } - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); avatarImage.setForUserOrChat(object, avatarDrawable); if (mini) { return; @@ -1640,7 +1640,7 @@ public void setCrossfadeTo(long dialogId) { user = null; } if (object != null) { - crossfadeAvatarDrawable.setInfo(object); + crossfadeAvatarDrawable.setInfo(currentAccount, object); crossfageToAvatarImage.setForUserOrChat(object, crossfadeAvatarDrawable); } } else { 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 4b6cfe206a..396554f4cd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; import android.animation.ValueAnimator; import android.app.Activity; import android.app.Dialog; @@ -27,6 +28,7 @@ import android.os.Build; import android.os.Bundle; import android.text.Layout; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -50,6 +52,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; @@ -100,8 +103,10 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.AvatarSpan; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AlertsCreator; @@ -152,8 +157,10 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.EmojiAnimationsOverlay; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.MessageStatisticActivity; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.PremiumPreviewFragment; @@ -174,11 +181,14 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.CountDownLatch; public class PeerStoriesView extends SizeNotifierFrameLayout implements NotificationCenter.NotificationCenterDelegate { + public static boolean DISABLE_STORY_REPOSTING = false; public static final float SHARE_BUTTON_OFFSET = 46; private final static long IMAGE_LIVE_TIME = 10_000; private final ImageView optionsIconView; @@ -198,9 +208,18 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final StoryCaptionView storyCaptionView; private CaptionContainerView storyEditCaptionView; private final ImageView shareButton; + @Nullable + private ImageView repostButton; + private final LinearLayout bottomActionsLinearLayout; + @Nullable + private FrameLayout repostButtonContainer; private AnimatedTextView.AnimatedTextDrawable reactionsCounter; + @Nullable + private AnimatedTextView.AnimatedTextDrawable repostCounter; private AnimatedFloat reactionsCounterProgress; + private AnimatedFloat repostCounterProgress; private boolean reactionsCounterVisible; + private boolean repostCounterVisible; private long currentImageTime; private long lastDrawTime; private boolean switchEventSent; @@ -212,7 +231,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final ImageReceiver imageReceiver; private final ImageReceiver leftPreloadImageReceiver; private final ImageReceiver rightPreloadImageReceiver; - private final ArrayList preloadReactionHolders = new ArrayList<>();; + private final ArrayList preloadReactionHolders = new ArrayList<>(); private Runnable onImageReceiverThumbLoaded; private StoryMediaAreasView storyAreasView; @@ -475,7 +494,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.drawBitmap(playerSharedScope.player.playerStubBitmap, 0, 0, playerSharedScope.player.playerStubPaint); canvas.restore(); } else { - if (!storyViewer.USE_SURFACE_VIEW || allowDrawSurface) { + if (!storyViewer.USE_SURFACE_VIEW || allowDrawSurface && storyViewer.isShown()) { playerSharedScope.renderView.draw(canvas); } } @@ -733,7 +752,7 @@ public int getTopOffset(int tag) { } public boolean clipWithGradient(int tag) { - return tag == 1 || tag == 2; + return tag == 1 || tag == 2 || tag == 3; } @Override @@ -874,6 +893,40 @@ public void onLinkLongPress(URLSpan span, View spoilersTextView, Runnable done) delegate.showDialog(sheet); } + @Override + public void onReplyClick(Reply reply) { + if (reply == null) return; + if (reply.peerId == null || reply.storyId == null) { + BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.StoryHidAccount)) + .setTag(3) + .show(true); + return; + } + MessagesController.getInstance(currentAccount).getStoriesController().resolveStoryLink(reply.peerId, reply.storyId, fwdStoryItem -> { + if (fwdStoryItem != null) { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment == null) { + return; + } + if (lastFragment.getOrCreateOverlayStoryViewer().isShowing) { + return; + } + storyViewer.setOverlayVisible(true); + fwdStoryItem.dialogId = reply.peerId; + lastFragment.getOrCreateOverlayStoryViewer().open(getContext(), fwdStoryItem, null); + lastFragment.getOrCreateOverlayStoryViewer().setOnCloseListener(() -> { + storyViewer.setOverlayVisible(false); + }); + } else { + BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.story_bomb2, LocaleController.getString(R.string.StoryNotFound)) + .setTag(3) + .show(true); + } + }); + } + @Override public void onEmojiClick(AnimatedEmojiSpan span) { if (span == null || delegate == null) { @@ -923,7 +976,62 @@ public void onEmojiClick(AnimatedEmojiSpan span) { }); ScaleStateListAnimator.apply(shareButton); - likeButtonContainer = new FrameLayout(getContext()); + if (!DISABLE_STORY_REPOSTING) { + repostButton = new ImageView(context); + repostButton.setImageDrawable(sharedResources.repostDrawable); + repostButton.setPadding(padding, padding, padding, padding); + + repostButtonContainer = new FrameLayout(getContext()) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (isChannel && repostCounter != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - repostCounter.getCurrentWidth() - AndroidUtilities.dp(6), 0); + float repostScale = repostCounterProgress.set(repostCounterVisible ? 1f : 0); + canvas.scale(repostScale, repostScale, repostCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); + repostCounter.setAlpha(0xFF); + repostCounter.draw(canvas); + canvas.restore(); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == repostCounter || super.verifyDrawable(who); + } + }; + if (repostCounter != null) { + repostCounter.setCallback(repostButtonContainer); + } + repostButtonContainer.setWillNotDraw(false); + repostButtonContainer.setOnClickListener(v -> tryToOpenRepostStory()); + } + + likeButtonContainer = new FrameLayout(getContext()) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (isChannel && reactionsCounter != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(6), 0); + float reactionScale = reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0); + canvas.scale(reactionScale, reactionScale, reactionsCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); + reactionsCounter.setAlpha(0xFF); + reactionsCounter.draw(canvas); + canvas.restore(); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == reactionsCounter || super.verifyDrawable(who); + } + }; + if (reactionsCounter != null) { + reactionsCounter.setCallback(likeButtonContainer); + } + likeButtonContainer.setWillNotDraw(false); likeButtonContainer.setOnClickListener(v -> { if (currentStory.storyItem != null && currentStory.storyItem.sent_reaction == null) { applyMessageToChat(() -> { @@ -950,7 +1058,13 @@ public void onEmojiClick(AnimatedEmojiSpan span) { storiesLikeButton = new StoriesLikeButton(context, sharedResources); storiesLikeButton.setPadding(padding, padding, padding, padding); likeButtonContainer.addView(storiesLikeButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); + if (repostButtonContainer != null) { + repostButtonContainer.addView(repostButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); + } ScaleStateListAnimator.apply(likeButtonContainer, 0.3f, 5f); + if (repostButtonContainer != null) { + ScaleStateListAnimator.apply(repostButtonContainer, 0.3f, 5f); + } imageReceiver.setAllowLoadingOnAttachedOnly(true); imageReceiver.setParentView(storyContainer); @@ -975,15 +1089,23 @@ public void onEmojiClick(AnimatedEmojiSpan span) { storyViewer.presentFragment(ChatActivity.of(dialogId)); } } - -// LaunchActivity.getLastFragment().showAsSheet(profileActivity, params); -// profileActivity.showAsActivity(); }); storyContainer.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 17, 0, 0)); + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(150); + layoutTransition.disableTransitionType(LayoutTransition.APPEARING); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + bottomActionsLinearLayout = new LinearLayout(context); + bottomActionsLinearLayout.setOrientation(LinearLayout.HORIZONTAL); + bottomActionsLinearLayout.setLayoutTransition(layoutTransition); + bottomActionsLinearLayout.addView(shareButton, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); + if (repostButtonContainer != null) { + bottomActionsLinearLayout.addView(repostButtonContainer, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); + } + bottomActionsLinearLayout.addView(likeButtonContainer, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); - addView(shareButton, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10 + 40, 10)); - addView(likeButtonContainer, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10, 10)); + addView(bottomActionsLinearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT, 0, 0,4,0)); optionsIconView = new ImageView(context); optionsIconView.setImageDrawable(sharedResources.optionsDrawable); @@ -1002,6 +1124,41 @@ public void onEmojiClick(AnimatedEmojiSpan span) { } popupMenu = new CustomPopupMenu(getContext(), resourcesProvider, isSelf) { private boolean edit; + + private void addViewStatistics(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout, TL_stories.StoryItem storyItem) { + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat != null) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(chat.id); + if (chatFull == null) { + chatFull = MessagesStorage.getInstance(currentAccount).loadChatInfo(chat.id, true, new CountDownLatch(1), false, false); + } + if (chatFull != null && chatFull.can_view_stats) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_stats, LocaleController.getString("ViewStatistics", R.string.ViewStatistics), false, resourcesProvider).setOnClickListener(v -> { + if (popupMenu != null) { + popupMenu.dismiss(); + } + storyItem.dialogId = dialogId; + storyItem.messageId = storyItem.id; + MessageObject msg = new MessageObject(currentAccount, storyItem); + msg.generateThumbs(false); + storyViewer.presentFragment(new MessageStatisticActivity(msg, chat.id, false) { + @Override + public Theme.ResourcesProvider getResourceProvider() { + return new DarkThemeResourceProvider(); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + }); + }); + } + } + } + } + @Override protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { final boolean userCanEditStory = isSelf || MessagesController.getInstance(currentAccount).getStoriesController().canEditStory(currentStory.storyItem); @@ -1077,7 +1234,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay editOpened = true; setActive(false); }); - editor.setOnPrepareCloseListener((t, close, sent) -> { + editor.setOnPrepareCloseListener((t, close, sent, did) -> { final long start = System.currentTimeMillis(); if (playerSharedScope.player == null) { delegate.setPopupIsVisible(false); @@ -1158,6 +1315,8 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } + addViewStatistics(popupLayout, storyItem); + if (!unsupported || true) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, str, false, resourcesProvider).setOnClickListener(v -> { saveToGallery(); @@ -1174,7 +1333,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay if (isChannel && allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { AndroidUtilities.addToClipboard(currentStory.createLink()); - onLickCopied(); + onLinkCopied(); if (popupMenu != null) { popupMenu.dismiss(); } @@ -1321,7 +1480,7 @@ public void setColorFilter(ColorFilter colorFilter) { if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { AndroidUtilities.addToClipboard(currentStory.createLink()); - onLickCopied(); + onLinkCopied(); if (popupMenu != null) { popupMenu.dismiss(); } @@ -1375,6 +1534,8 @@ public void setColorFilter(ColorFilter colorFilter) { } } + addViewStatistics(popupLayout, currentStory.storyItem); + if (!unsupported) { if (!UserObject.isService(dialogId)) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat), false, resourcesProvider).setOnClickListener(v -> { @@ -1516,6 +1677,9 @@ protected void onDismissed() { optionsIconView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); shareButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); likeButtonContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); + if (repostButtonContainer != null) { + repostButtonContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); + } View overlay = storyCaptionView.textSelectionHelper.getOverlayView(context); if (overlay != null) { @@ -2411,6 +2575,21 @@ public void startDocumentSelectActivity() { } } + private void tryToOpenRepostStory() { + if (!MessagesController.getInstance(currentAccount).storiesEnabled()) { + return; + } + File f = currentStory.getPath(); + if (f != null && f.exists()) { + if (shareAlert != null) { + shareAlert.dismiss(); + } + AndroidUtilities.runOnUIThread(PeerStoriesView.this::openRepostStory, 120); + } else { + showDownloadAlert(); + } + } + private void shareStory(boolean internal) { if (currentStory.storyItem != null && storyViewer.fragment != null) { TL_stories.StoryItem storyItem = currentStory.storyItem; @@ -2420,9 +2599,12 @@ private void shareStory(boolean internal) { @Override public void appendColors() { sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.2f)); + sparseIntArray.put(Theme.key_chat_messagePanelIcons, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.5f)); } }; - shareAlert = new ShareAlert(storyViewer.fragment.getContext(), null, link, false, link, false, shareResourceProvider) { + TLRPC.Chat chat = isChannel ? MessagesController.getInstance(currentAccount).getChat(-dialogId) : null; + final boolean canRepost = !DISABLE_STORY_REPOSTING && MessagesController.getInstance(currentAccount).storiesEnabled() && (!isChannel && !UserObject.isService(dialogId) || ChatObject.isPublic(chat)); + shareAlert = new ShareAlert(storyViewer.fragment.getContext(), null, null, link, null, false, link, null, false, false, canRepost, shareResourceProvider) { @Override public void dismissInternal() { @@ -2437,7 +2619,9 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo if (bulletinFactory != null) { if (dids.size() == 1) { long did = dids.keyAt(0); - if (did == UserConfig.getInstance(currentAccount).clientUserId) { + if (did == Long.MAX_VALUE) { + tryToOpenRepostStory(); + } else if (did == UserConfig.getInstance(currentAccount).clientUserId) { bulletinFactory.createSimpleBulletin(R.raw.saved_messages, AndroidUtilities.replaceTags(LocaleController.formatString("StorySharedToSavedMessages", R.string.StorySharedToSavedMessages)), Bulletin.DURATION_PROLONG).hideAfterBottomSheet(false).show(); } else if (did < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); @@ -2453,13 +2637,13 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } } }; + shareAlert.forceDarkThemeForHint = true; currentStory.storyItem.dialogId = dialogId; shareAlert.setStoryToShare(currentStory.storyItem); shareAlert.setDelegate(new ShareAlert.ShareAlertDelegate() { - @Override public boolean didCopy() { - onLickCopied(); + onLinkCopied(); return true; } }); @@ -2473,7 +2657,116 @@ public boolean didCopy() { } } - private void onLickCopied() { + private void openRepostStory() { + Activity activity = AndroidUtilities.findActivity(getContext()); + if (activity == null) { + return; + } + Runnable openRepost = () -> { + StoryRecorder editor = StoryRecorder.getInstance(activity, currentAccount); + long time = 0; + if (playerSharedScope != null && playerSharedScope.player != null) { + time = playerSharedScope.player.currentPosition; + } + StoryEntry entry = StoryEntry.repostStoryItem(currentStory.getPath(), currentStory.storyItem); + editor.openForward(StoryRecorder.SourceView.fromStoryViewer(storyViewer), entry, time, true); + editor.setOnFullyOpenListener(() -> { + editOpened = true; + setActive(false); + }); + editor.setOnPrepareCloseListener((t, close, sent, did) -> { + if (sent) { + DialogStoriesCell.StoryCell cell = null; + DialogStoriesCell storiesCell = null; + if (storyViewer.fragment != null) { + INavigationLayout layout = storyViewer.fragment.getParentLayout(); + if (layout != null) { + List fragmentList = layout.getFragmentStack(); + ArrayList toClose = new ArrayList<>(); + for (int i = fragmentList.size() - 1; i >= 0; --i) { + BaseFragment fragment = fragmentList.get(i); + if (fragment instanceof DialogsActivity) { + DialogsActivity dialogsActivity = (DialogsActivity) fragment; + dialogsActivity.closeSearching(); + storiesCell = dialogsActivity.dialogStoriesCell; + if (storiesCell != null) { + cell = storiesCell.findStoryCell(did); + } + for (int j = 0; j < toClose.size(); ++j) { + layout.removeFragmentFromStack(toClose.get(j)); + } + break; + } + toClose.add(fragment); + } + } + } + if (storyViewer.fragment != null && storyViewer.fragment.overlayStoryViewer != null) { + storyViewer.fragment.overlayStoryViewer.instantClose(); + } + if (storyViewer.fragment != null && storyViewer.fragment.storyViewer != null) { + storyViewer.fragment.storyViewer.instantClose(); + } + storyViewer.instantClose(); + editOpened = false; + final DialogStoriesCell.StoryCell finalCell = cell; + if (storiesCell != null && storiesCell.scrollTo(did)) { + final DialogStoriesCell finalStoriesCell = storiesCell; + storiesCell.afterNextLayout(() -> { + DialogStoriesCell.StoryCell cell2 = finalCell; + if (cell2 == null) { + cell2 = finalStoriesCell.findStoryCell(did); + } + editor.replaceSourceView(StoryRecorder.SourceView.fromStoryCell(cell2)); + close.run(); + }); + } else { + editor.replaceSourceView(StoryRecorder.SourceView.fromStoryCell(finalCell)); + AndroidUtilities.runOnUIThread(close, 400); + } + return; + } + final long start = System.currentTimeMillis(); + if (playerSharedScope != null && playerSharedScope.player == null) { + delegate.setPopupIsVisible(false); + setActive(true); + editOpened = false; + onImageReceiverThumbLoaded = () -> { + AndroidUtilities.cancelRunOnUIThread(close); + AndroidUtilities.runOnUIThread(close); + }; + if (sent) { + updatePosition(); + } + AndroidUtilities.runOnUIThread(close, 400); + return; + } + playerSharedScope.firstFrameRendered = playerSharedScope.player.firstFrameRendered = false; + playerSharedScope.player.setOnReadyListener(() -> { + AndroidUtilities.cancelRunOnUIThread(close); + AndroidUtilities.runOnUIThread(close, Math.max(0, 32L - (System.currentTimeMillis() - start))); + }); + delegate.setPopupIsVisible(false); + if (muteIconView != null) { + muteIconView.setAnimation(sharedResources.muteDrawable); + } + if (videoDuration > 0 && t > videoDuration - 1400) { + t = 0L; + } + setActive(t, true); + editOpened = false; + AndroidUtilities.runOnUIThread(close, 400); + if (sent) { + updatePosition(); + } + }); + }; + if (!delegate.releasePlayer(openRepost)) { + AndroidUtilities.runOnUIThread(openRepost, 80); + } + } + + private void onLinkCopied() { if (currentStory.storyItem == null) { return; } @@ -2516,7 +2809,7 @@ private void bindInternal(int startFromPosition) { if (dialogId >= 0) { isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); headerView.backupImageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); if (isSelf) { headerView.titleView.setText(LocaleController.getString("SelfStoryTitle", R.string.SelfStoryTitle)); @@ -2549,7 +2842,7 @@ private void bindInternal(int startFromPosition) { // userCanSeeViews = true; // } TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable); headerView.titleView.setText(chat.title); @@ -2580,16 +2873,21 @@ private void bindInternal(int startFromPosition) { chatActivityEnterView.setVisibility(View.GONE); } if (reactionsCounter == null) { - reactionsCounter = new AnimatedTextView.AnimatedTextDrawable() { - @Override - public void invalidateSelf() { - invalidate(); - } - }; + reactionsCounter = new AnimatedTextView.AnimatedTextDrawable(); + reactionsCounter.setCallback(likeButtonContainer); reactionsCounter.setTextColor(resourcesProvider.getColor(Theme.key_windowBackgroundWhiteBlackText)); reactionsCounter.setTextSize(AndroidUtilities.dp(14)); - reactionsCounterProgress = new AnimatedFloat(this); + reactionsCounterProgress = new AnimatedFloat(likeButtonContainer); + } + + if (repostButtonContainer != null && repostCounter == null) { + repostCounter = new AnimatedTextView.AnimatedTextDrawable(); + repostCounter.setCallback(repostButtonContainer); + repostCounter.setTextColor(resourcesProvider.getColor(Theme.key_windowBackgroundWhiteBlackText)); + repostCounter.setTextSize(AndroidUtilities.dp(14)); + repostCounterProgress = new AnimatedFloat(repostButtonContainer); } + if (startFromPosition == -1) { updateSelectedPosition(); } @@ -2817,7 +3115,7 @@ protected void dispatchDraw(Canvas canvas) { } }; selfView.setClickable(true); - addView(selfView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 0, 0, 56 + 40, 0)); + addView(selfView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 0, 0, 56 + 80, 0)); selfAvatarsContainer = new View(getContext()) { @@ -2925,21 +3223,13 @@ protected void dispatchDraw(Canvas canvas) { if (isChannel && reactionsCounter != null) { reactionsCounter.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(40)); } - super.dispatchDraw(canvas); - float reactionScale = 0; - if (isChannel && reactionsCounter != null) { - canvas.save(); - canvas.translate(getMeasuredWidth() - reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(12), likeButtonContainer.getY()); - reactionScale = reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0); - canvas.scale(reactionScale, reactionScale, reactionsCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); - reactionsCounter.setAlpha((int) (255 * likeButtonContainer.getAlpha())); - reactionsCounter.draw(canvas); - canvas.restore(); + if (isChannel && repostCounter != null) { + repostCounter.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(40)); } - updateButtonsOffsets(reactionScale); + super.dispatchDraw(canvas); if (movingReaction) { - float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; - float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + float cX = bottomActionsLinearLayout.getX() + likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = bottomActionsLinearLayout.getY() + likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; int size = AndroidUtilities.dp(24); float finalX = AndroidUtilities.lerp(movingReactionFromX, cX - size / 2f, CubicBezierInterpolator.EASE_OUT.getInterpolation(movingReactionProgress)); float finalY = AndroidUtilities.lerp(movingReactionFromY, cY - size / 2f, movingReactionProgress); @@ -2955,8 +3245,8 @@ protected void dispatchDraw(Canvas canvas) { } } if (drawReactionEffect) { - float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; - float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + float cX = bottomActionsLinearLayout.getX() + likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = bottomActionsLinearLayout.getY() + likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; int size = AndroidUtilities.dp(120); if (!drawAnimatedEmojiAsMovingReaction) { reactionEffectImageReceiver.setImageCoords(cX - size / 2f, cY - size / 2f, size, size); @@ -2984,21 +3274,6 @@ protected void dispatchDraw(Canvas canvas) { } } - private void updateButtonsOffsets(float reactionScale) { - if (isChannel) { - float x = -reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(4); - x *= reactionScale; - shareButton.setTranslationX(x); - likeButtonContainer.setTranslationX(x); - } else if (isSelf) { - shareButton.setTranslationX(AndroidUtilities.dp(40)); - likeButtonContainer.setTranslationX(0); - } else { - shareButton.setTranslationX(0); - likeButtonContainer.setTranslationX(0); - } - } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -3356,6 +3631,7 @@ private void updatePosition(boolean preload) { } if (storyChanged || oldUploadingStory != null && currentStory.uploadingStory == null) { + headerView.setOnSubtitleClick(null); if (currentStory.uploadingStory != null) { if (currentStory.uploadingStory.failed) { headerView.setSubtitle(LocaleController.getString("FailedToUploadStory", R.string.FailedToUploadStory), animateSubtitle); @@ -3365,6 +3641,57 @@ private void updatePosition(boolean preload) { } else if (currentStory.storyItem != null) { if (currentStory.storyItem.date == -1) { headerView.setSubtitle(LocaleController.getString("CachedStory", R.string.CachedStory)); + } else if (currentStory.storyItem.fwd_from != null) { + SpannableStringBuilder ssb = new SpannableStringBuilder(); + SpannableString repostIcon = new SpannableString("r"); + repostIcon.setSpan(new ColoredImageSpan(R.drawable.mini_repost_story), 0, repostIcon.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(repostIcon).append(" "); + if (currentStory.storyItem.fwd_from.from != null) { + AvatarSpan avatar = new AvatarSpan(headerView.subtitleView[0], currentAccount, 15); + SpannableString avatarStr = new SpannableString("a"); + avatarStr.setSpan(avatar, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(avatarStr).append(" "); + long did = DialogObject.getPeerDialogId(currentStory.storyItem.fwd_from.from); + if (did > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); + avatar.setUser(user); + ssb.append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + avatar.setChat(chat); + if (chat != null) { + ssb.append(chat.title); + } + } + } else if (currentStory.storyItem.fwd_from.from_name != null) { + ssb.append(currentStory.storyItem.fwd_from.from_name); + } + headerView.setOnSubtitleClick(v -> { + if (currentStory.storyItem.fwd_from.from != null) { + long did = DialogObject.getPeerDialogId(currentStory.storyItem.fwd_from.from); + Bundle args = new Bundle(); + if (did >= 0) { + args.putLong("user_id", did); + } else { + args.putLong("chat_id", -did); + } + storyViewer.presentFragment(new ProfileActivity(args)); + } else { + BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.StoryHidAccount)) + .setTag(3) + .show(true); + } + }); + + SpannableString dot = new SpannableString("."); + DotDividerSpan dotDividerSpan = new DotDividerSpan(); + dotDividerSpan.setTopPadding(AndroidUtilities.dp(1.5f)); + dotDividerSpan.setSize(5); + dot.setSpan(dotDividerSpan, 0, dot.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + ssb.append(" ").append(dot).append(" ").append(LocaleController.formatShortDate(currentStory.storyItem.date)); + headerView.setSubtitle(ssb, false); } else { CharSequence string = LocaleController.formatStoryDate(currentStory.storyItem.date); if (currentStory.storyItem.edited) { @@ -3431,8 +3758,8 @@ private void updatePosition(boolean preload) { } } - if (currentStory.caption != null && !unsupported) { - storyCaptionView.captionTextview.setText(currentStory.caption, storyViewer.isTranslating &&!currentStory.captionTranslated && currentStory.storyItem != null && currentStory.storyItem.translated, oldStoryItem == currentStory.storyItem); + if ((currentStory.caption != null || currentStory.getReply() != null) && !unsupported) { + storyCaptionView.captionTextview.setText(currentStory.caption, currentStory.getReply(), storyViewer.isTranslating && !currentStory.captionTranslated && currentStory.storyItem != null && currentStory.storyItem.translated, oldStoryItem == currentStory.storyItem); storyCaptionView.setVisibility(View.VISIBLE); } else { if (isActive) { @@ -3446,13 +3773,20 @@ private void updatePosition(boolean preload) { delegate.onPeerSelected(dialogId, selectedPosition); } if (isChannel) { - shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + shareButton.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + if (repostButtonContainer != null) { + repostButtonContainer.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + } likeButtonContainer.setVisibility(isFailed ? View.GONE : View.VISIBLE); } else { - shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + shareButton.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + if (repostButtonContainer != null) { + repostButtonContainer.setVisibility(View.GONE); + } likeButtonContainer.setVisibility(isSelf ? View.GONE : View.VISIBLE); + likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); } - + likeButtonContainer.requestLayout(); storyViewer.savedPositions.append(dialogId, position); @@ -3665,7 +3999,8 @@ private void updatePreloadImages() { "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + "&rid=" + storyItem.fileReference + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + - "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]) + + "&sid=" + storyItem.id + "&did=" + storyItem.dialogId; uriesToPrepare.add(Uri.parse("tg://" + FileLoader.getAttachFileName(document) + params)); documentsToPrepare.add(document); } catch (UnsupportedEncodingException e) { @@ -3765,6 +4100,12 @@ private void updateUserViews(boolean animated) { if (storyItem.views.views_count <= 0) { storyItem.views.views_count = 1; } + if (repostCounter != null && storyItem.views.forwards_count > 0) { + repostCounter.setText(Integer.toString(storyItem.views.forwards_count), animated && repostCounterVisible); + repostCounterVisible = true; + } else { + repostCounterVisible = false; + } if (storyItem.views.reactions_count > 0) { reactionsCounter.setText(Integer.toString(storyItem.views.reactions_count), animated && reactionsCounterVisible); reactionsCounterVisible = true; @@ -3773,6 +4114,9 @@ private void updateUserViews(boolean animated) { } if (!animated) { reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0, true); + if (repostCounterProgress != null) { + repostCounterProgress.set(repostCounterVisible ? 1f : 0, true); + } } if (storyItem.views.views_count > 0) { selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); @@ -3786,13 +4130,14 @@ private void updateUserViews(boolean animated) { } else { selfStatusView.setText(""); } - if (reactionsCounterVisible) { - likeButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + reactionsCounter.getAnimateToWidth() + AndroidUtilities.dp(4)); - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10) + AndroidUtilities.dp(40) - likeButtonContainer.getLayoutParams().width; - } else { - likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); + likeButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + (reactionsCounterVisible ? (reactionsCounter.getAnimateToWidth() + AndroidUtilities.dp(4)) : 0)); + ((MarginLayoutParams) selfView.getLayoutParams()).rightMargin = AndroidUtilities.dp(40) + likeButtonContainer.getLayoutParams().width; + if (repostButtonContainer != null) { + repostButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + (repostCounterVisible ? (repostCounter.getAnimateToWidth() + AndroidUtilities.dp(4)) : 0)); + ((MarginLayoutParams) selfView.getLayoutParams()).rightMargin += repostButtonContainer.getLayoutParams().width; + repostButtonContainer.requestLayout(); } + selfView.requestLayout(); likeButtonContainer.requestLayout(); selfAvatarsView.setVisibility(View.GONE); selfAvatarsContainer.setVisibility(View.GONE); @@ -3826,6 +4171,14 @@ private void updateUserViews(boolean animated) { spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); spannableStringBuilder.append(String.valueOf(storyItem.views.reactions_count)); } + if (storyItem.views.forwards_count > 0) { + spannableStringBuilder.append(" d "); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_repost_story); + span.setOverrideColor(0xFF27E861); + span.setTopOffset(AndroidUtilities.dp(0.2f)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); + spannableStringBuilder.append(String.valueOf(storyItem.views.forwards_count)); + } selfStatusView.setText(spannableStringBuilder); if (k == 0) { selfAvatarsView.setVisibility(View.GONE); @@ -3841,8 +4194,8 @@ private void updateUserViews(boolean animated) { selfAvatarsView.setVisibility(View.GONE); selfAvatarsContainer.setVisibility(View.GONE); } - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); + bottomActionsLinearLayout.requestLayout(); } } else { selfStatusView.setText(""); @@ -3874,7 +4227,8 @@ private void requestVideoPlayer(long t) { "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + "&rid=" + currentStory.storyItem.fileReference + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + - "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]) + + "&sid=" + currentStory.storyItem.id + "&did=" + currentStory.storyItem.dialogId; uri = Uri.parse("tg://" + FileLoader.getAttachFileName(document) + params); videoDuration = (long) (MessageObject.getDocumentDuration(document) * 1000); } catch (Exception exception) { @@ -4155,7 +4509,7 @@ public void reset() { headerView.backupImageView.getImageReceiver().setVisible(true, true); if (changeBoundAnimator != null) { chatActivityEnterView.reset(); - chatActivityEnterView.setAlpha(1f); + chatActivityEnterView.setAlpha(1f - outT); } if (reactionsContainerLayout != null) { reactionsContainerLayout.reset(); @@ -4465,9 +4819,10 @@ protected void onDraw(Canvas canvas) { subtitleView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); subtitleView[a].setMaxLines(1); subtitleView[a].setSingleLine(true); - subtitleView[a].setEllipsize(TextUtils.TruncateAt.END); + subtitleView[a].setEllipsize(TextUtils.TruncateAt.MIDDLE); subtitleView[a].setTextColor(Color.WHITE); - addView(subtitleView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 54, 18, 86, 0)); + subtitleView[a].setPadding(dp(3), 0, dp(3), dp(1)); + addView(subtitleView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 51, 18, 83, 0)); } titleView.setTextColor(Color.WHITE); @@ -4477,6 +4832,12 @@ public void setSubtitle(CharSequence text) { setSubtitle(text, false); } + public void setOnSubtitleClick(View.OnClickListener listener) { + subtitleView[0].setOnClickListener(listener); + subtitleView[0].setClickable(listener != null); + subtitleView[0].setBackground(listener == null ? null : Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + } + private ValueAnimator subtitleAnimator; public void setSubtitle(CharSequence text, boolean animated) { if (subtitleAnimator != null) { @@ -4484,6 +4845,7 @@ public void setSubtitle(CharSequence text, boolean animated) { subtitleAnimator = null; } if (animated) { + subtitleView[1].setOnClickListener(null); subtitleView[1].setText(subtitleView[0].getText()); subtitleView[1].setVisibility(View.VISIBLE); subtitleView[1].setAlpha(1f); @@ -4662,6 +5024,19 @@ public class StoryItemHolder { public boolean captionTranslated; public CharSequence caption; + private StoryCaptionView.Reply reply; + + public StoryCaptionView.Reply getReply() { + if (reply == null) { + if (storyItem != null) { + reply = StoryCaptionView.Reply.from(currentAccount, storyItem); + } else if (uploadingStory != null) { + reply = StoryCaptionView.Reply.from(uploadingStory); + } + } + return reply; + } + public void updateCaption() { captionTranslated = false; if (currentStory.uploadingStory != null) { @@ -4709,6 +5084,7 @@ public void updateCaption() { void set(TL_stories.StoryItem storyItem) { this.storyItem = storyItem; + this.reply = null; this.uploadingStory = null; skipped = storyItem instanceof TL_stories.TL_storyItemSkipped; isVideo = isVideoInternal(); @@ -4729,6 +5105,7 @@ private boolean isVideoInternal() { void set(StoriesController.UploadingStory uploadingStory) { this.uploadingStory = uploadingStory; + this.reply = null; this.storyItem = null; skipped = false; isVideo = isVideoInternal(); @@ -5063,14 +5440,12 @@ public void onAnimationEnd(Animator animation) { } if (!BIG_SCREEN) { - ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); - ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); + ((LayoutParams) bottomActionsLinearLayout.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); int bottomPadding = isSelf ? AndroidUtilities.dp(40) : AndroidUtilities.dp(56); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = bottomPadding; storyCaptionView.blackoutBottomOffset = bottomPadding; } else { - ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); - ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); + ((LayoutParams) bottomActionsLinearLayout.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = AndroidUtilities.dp(8); storyCaptionView.blackoutBottomOffset = AndroidUtilities.dp(8); } @@ -5135,6 +5510,17 @@ private void updateViewOffsets() { chatActivityEnterView.checkAnimation(); } boolean popupVisible = chatActivityEnterView != null && chatActivityEnterView.isPopupShowing(); + float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (BIG_SCREEN) { + inputBackgroundPaint.setColor(ColorUtils.blendARGB( + ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), + ColorUtils.setAlphaComponent(Color.BLACK, 170), + progressToKeyboard + )); + inputBackgroundPaint.setAlpha((int) (inputBackgroundPaint.getAlpha() * (1f - progressToDismiss) * hideInterfaceAlpha * (1f - outT))); + } else { + inputBackgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (140 * hideInterfaceAlpha * (1f - outT)))); + } if (forceUpdateOffsets || progressToReply != storyViewer.swipeToReplyProgress || progressToHideInterface.get() != prevToHideProgress || lastAnimatingKeyboardHeight != animatingKeyboardHeight || progressToKeyboardLocal != progressToKeyboard || progressToDismissLocal != progressToDismiss || progressToRecord != progressToRecording.get() || popupVisible || progressToStickerExpandedLocal != progressToStickerExpanded.get() || progressToText != progressToTextA.get()) { forceUpdateOffsets = false; lastAnimatingKeyboardHeight = animatingKeyboardHeight; @@ -5158,17 +5544,6 @@ private void updateViewOffsets() { if (reactionsContainerLayout != null) { reactionsContainerLayout.setVisibility(progressToKeyboard > 0 ? View.VISIBLE : View.GONE); } - float hideInterfaceAlpha = getHideInterfaceAlpha(); - if (BIG_SCREEN) { - inputBackgroundPaint.setColor(ColorUtils.blendARGB( - ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), - ColorUtils.setAlphaComponent(Color.BLACK, 170), - progressToKeyboard - )); - inputBackgroundPaint.setAlpha((int) (inputBackgroundPaint.getAlpha() * (1f - progressToDismiss) * hideInterfaceAlpha)); - } else { - inputBackgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (140 * hideInterfaceAlpha))); - } for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); @@ -5187,7 +5562,7 @@ private void updateViewOffsets() { } else if (child instanceof HintView) { HintView hintView = (HintView) child; hintView.updatePosition(); - } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != mediaBanTooltip && child != likeButtonContainer && (likesReactionLayout == null || likesReactionLayout.getReactionsWindow() == null || child != likesReactionLayout.getReactionsWindow().windowView)) { + } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != bottomActionsLinearLayout && child != repostButtonContainer && child != mediaBanTooltip && child != likeButtonContainer && (likesReactionLayout == null || likesReactionLayout.getReactionsWindow() == null || child != likesReactionLayout.getReactionsWindow().windowView)) { float alpha; float translationY = -enterViewBottomOffset * (1f - progressToKeyboard) - animatingKeyboardHeight - AndroidUtilities.dp(8) * (1f - progressToKeyboard) - AndroidUtilities.dp(20) * storyViewer.swipeToReplyProgress; if (BIG_SCREEN) { @@ -5219,8 +5594,11 @@ private void updateViewOffsets() { } } } - shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); - likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } for (int i = 0; i < storyContainer.getChildCount(); i++) { View child = storyContainer.getChildAt(i); @@ -5255,7 +5633,7 @@ private boolean hideCaptionWithInterface() { } private float getHideInterfaceAlpha() { - return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); + return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); } @Override @@ -5312,7 +5690,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); } } else if (child == likesReactionLayout) { - child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() - AndroidUtilities.dp(18)); + child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() + bottomActionsLinearLayout.getY() - AndroidUtilities.dp(18)); // if (progressToKeyboard > 0) { // sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); // canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); @@ -5719,6 +6097,7 @@ public static class SharedResources { private final RectF finalRect = new RectF(); private final Paint dimPaint = new Paint(); public Drawable shareDrawable; + public Drawable repostDrawable; public Drawable likeDrawable; public Drawable likeDrawableFilled; public Drawable optionsDrawable; @@ -5730,6 +6109,7 @@ public static class SharedResources { SharedResources(Context context) { shareDrawable = ContextCompat.getDrawable(context, R.drawable.media_share); likeDrawable = ContextCompat.getDrawable(context, R.drawable.media_like); + repostDrawable = ContextCompat.getDrawable(context, R.drawable.media_repost); likeDrawableFilled = ContextCompat.getDrawable(context, R.drawable.media_like_active); likeDrawableFilled.setColorFilter(new PorterDuffColorFilter(0xFFFF2E38, PorterDuff.Mode.MULTIPLY)); optionsDrawable = ContextCompat.getDrawable(context, R.drawable.media_more); @@ -5883,6 +6263,21 @@ public void animateOut(boolean out) { privacyButton.setAlpha(1f - outT); } storyCaptionView.setAlpha(1f - outT); + final float progressToDismissLocal = delegate == null ? 0 : delegate.getProgressToDismiss(); + final float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (likeButtonContainer != null) { + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (shareButton != null) { + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (chatActivityEnterView != null) { + chatActivityEnterView.setAlpha(1f - outT); + invalidate(); + } storyContainer.invalidate(); }); outAnimator.addListener(new AnimatorListenerAdapter() { @@ -5904,6 +6299,21 @@ public void onAnimationEnd(Animator animation) { privacyButton.setAlpha(1f - outT); } storyCaptionView.setAlpha(1f - outT); + final float progressToDismissLocal = delegate == null ? 0 : delegate.getProgressToDismiss(); + final float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (likeButtonContainer != null) { + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (shareButton != null) { + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (chatActivityEnterView != null) { + chatActivityEnterView.setAlpha(1f - outT); + invalidate(); + } storyContainer.invalidate(); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java index 07fa34e56a..c5bb953630 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java @@ -37,6 +37,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedFloat; @@ -83,6 +84,7 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif private float fragmentTransitionProgress; private int uploadingStoriesCount; private StoriesController.UploadingStory lastUploadingStory; + private final StoriesUtilities.StoryGradientTools gradientTools = new StoriesUtilities.StoryGradientTools(this, false); public void setProgressToStoriesInsets(float progressToInsets) { if (this.progressToInsets == progressToInsets) { @@ -362,6 +364,14 @@ private void updateStories(boolean animated, boolean asUpdate) { this.count = newCount; titleDrawable.setText(this.count > 0 ? LocaleController.formatPluralString("Stories", this.count) : "", animated && !LocaleController.isRTL); + if (dialogId >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + gradientTools.setUser(user, animated); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + gradientTools.setChat(chat, animated); + } + invalidate(); } @@ -505,7 +515,7 @@ protected void dispatchDraw(Canvas canvas) { if (progressToUploading > 0) { rect2.set(rect1); rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); if (radialProgress == null) { radialProgress = new RadialProgress(this); radialProgress.setBackground(null, true, false); @@ -600,7 +610,7 @@ protected void dispatchDraw(Canvas canvas) { } if (read < 1) { - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); unreadPaint.setAlpha((int) (0xFF * (1f - read) * segmentsAlpha)); unreadPaint.setStrokeWidth(dpf2(2.33f)); canvas.drawArc(rect2, a, -widthAngle * appear, false, unreadPaint); @@ -653,7 +663,7 @@ protected void dispatchDraw(Canvas canvas) { } readPaint.setColor(ColorUtils.blendARGB(0x5affffff, 0x80BBC4CC, expandProgress)); readPaintAlpha = readPaint.getAlpha(); - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); unreadPaint.setStrokeWidth(lerp(dpf2(2.33f), dpf2(1.5f), expandProgress)); readPaint.setStrokeWidth(lerp(dpf2(1.125f), dpf2(1.5f), expandProgress)); if (expandProgress > 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java index 8054064bf0..6a50026fe2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -1261,10 +1261,12 @@ public boolean hasUnreadStories(long dialogId) { } } for (int i = 0; i < userStories.stories.size(); i++) { + TL_stories.StoryItem storyItem = userStories.stories.get(i); + if (storyItem == null) continue; // if (userStories.stories.get(i).justUploaded) { // return true; // } - if (userStories.stories.get(i).id > userStories.max_read_id) { + if (storyItem.id > userStories.max_read_id) { return true; } } @@ -1445,6 +1447,8 @@ public void run(TLObject res, TLRPC.TL_error error) { TL_stories.StoryItem storyItem = null; if (res != null) { TL_stories.TL_stories_stories response = (TL_stories.TL_stories_stories) res; + MessagesController.getInstance(currentAccount).putUsers(response.users, false); + MessagesController.getInstance(currentAccount).putChats(response.chats, false); if (response.stories.size() > 0) { storyItem = response.stories.get(0); resolvedStories.put(hash, storyItem); @@ -1726,7 +1730,7 @@ private void startForeground() { } public void start() { - if (entry.isEdit && !entry.editedMedia) { + if ((entry.isEdit || entry.isRepost && entry.repostMedia != null) && (!entry.editedMedia && entry.round == null)) { sendUploadedRequest(null); return; } @@ -1897,8 +1901,31 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { return; } + boolean sendingSameInput = false; TLRPC.InputMedia media = null; - if (uploadedFile != null) { + if (entry.isRepost && !entry.editedMedia && entry.repostMedia != null) { + if (entry.repostMedia instanceof TLRPC.TL_messageMediaDocument) { + TLRPC.TL_inputMediaDocument inputMedia = new TLRPC.TL_inputMediaDocument(); + TLRPC.TL_inputDocument inputDocument = new TLRPC.TL_inputDocument(); + inputDocument.id = entry.repostMedia.document.id; + inputDocument.access_hash = entry.repostMedia.document.access_hash; + inputDocument.file_reference = entry.repostMedia.document.file_reference; + inputMedia.id = inputDocument; + inputMedia.spoiler = entry.repostMedia.spoiler; + media = inputMedia; + sendingSameInput = true; + } else if (entry.repostMedia instanceof TLRPC.TL_messageMediaPhoto) { + TLRPC.TL_inputMediaPhoto inputMedia = new TLRPC.TL_inputMediaPhoto(); + TLRPC.TL_inputPhoto inputPhoto = new TLRPC.TL_inputPhoto(); + inputPhoto.id = entry.repostMedia.photo.id; + inputPhoto.access_hash = entry.repostMedia.photo.access_hash; + inputPhoto.file_reference = entry.repostMedia.photo.file_reference; + inputMedia.id = inputPhoto; + media = inputMedia; + sendingSameInput = true; + } + } + if (media == null && uploadedFile != null) { if (entry.wouldBeVideo()) { TLRPC.TL_inputMediaUploadedDocument inputMediaVideo = new TLRPC.TL_inputMediaUploadedDocument(); inputMediaVideo.file = uploadedFile; @@ -2017,6 +2044,13 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { sendStory.caption = caption[0].toString(); } + if (entry.isRepost) { + sendStory.flags |= 64; + sendStory.fwd_from_id = MessagesController.getInstance(currentAccount).getInputPeer(entry.repostPeer); + sendStory.fwd_from_story = entry.repostStoryId; + sendStory.fwd_modified = !sendingSameInput; + } + if (entry.period == Integer.MAX_VALUE) { sendStory.pinned = true; } else { @@ -2184,7 +2218,7 @@ public boolean isCloseFriends() { } } - private final HashMap[] storiesLists = new HashMap[2]; + private final HashMap[] storiesLists = new HashMap[3]; @Nullable public StoriesList getStoriesList(long dialogId, int type) { @@ -2291,6 +2325,7 @@ public void unlink(int id) { public static final int TYPE_PINNED = 0; public static final int TYPE_ARCHIVE = 1; + public static final int TYPE_STATISTICS = 2; public final int currentAccount; public final long dialogId; @@ -2399,8 +2434,10 @@ private void preloadCache() { storage.getStorageQueue().postRunnable(() -> { SQLiteCursor cursor = null; HashSet loadUserIds = new HashSet<>(); + HashSet loadChatIds = new HashSet<>(); ArrayList cacheResult = new ArrayList<>(); final ArrayList loadedUsers = new ArrayList<>(); + final ArrayList loadedChats = new ArrayList<>(); try { SQLiteDatabase database = storage.getDatabase(); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM profile_stories WHERE dialog_id = %d AND type = %d ORDER BY story_id DESC", dialogId, type)); @@ -2418,6 +2455,14 @@ private void preloadCache() { loadUserIds.addAll(((TLRPC.TL_privacyValueAllowUsers) rule).users); } } + if (storyItem.fwd_from != null && storyItem.fwd_from.from != null) { + long did = DialogObject.getPeerDialogId(storyItem.fwd_from.from); + if (did >= 0) { + loadUserIds.add(did); + } else { + loadChatIds.add(-did); + } + } msg.generateThumbs(false); cacheResult.add(msg); data.reuse(); @@ -2428,6 +2473,9 @@ private void preloadCache() { if (!loadUserIds.isEmpty()) { storage.getUsersInternal(TextUtils.join(",", loadUserIds), loadedUsers); } + if (!loadChatIds.isEmpty()) { + storage.getChatsInternal(TextUtils.join(",", loadChatIds), loadedChats); + } } catch (Throwable e) { storage.checkSQLException(e); } finally { @@ -2441,6 +2489,7 @@ private void preloadCache() { FileLog.d("StoriesList "+type+"{"+ dialogId +"} preloadCache {" + storyItemMessageIds(cacheResult) + "}"); preloading = false; MessagesController.getInstance(currentAccount).putUsers(loadedUsers, true); + MessagesController.getInstance(currentAccount).putChats(loadedChats, true); if (invalidateAfterPreload) { invalidateAfterPreload = false; toLoad = null; @@ -2623,11 +2672,26 @@ private void resetCanLoad() { } public boolean load(boolean force, final int count) { + return load(force, count, Collections.emptyList()); + } + + public boolean load(List ids) { + boolean force = false; + for (Integer id : ids) { + if (!messageObjectsMap.containsKey(id)) { + force = true; + break; + } + } + return load(force, 0, ids); + } + + public boolean load(boolean force, final int count, List ids) { if (loading || (done || error || !canLoad()) && !force) { return false; } if (preloading) { - toLoad = i -> load(force, count); + toLoad = i -> load(force, count, ids); return false; } @@ -2643,6 +2707,12 @@ public boolean load(boolean force, final int count) { } req.limit = count; request = req; + } else if (type == TYPE_STATISTICS) { + TL_stories.TL_stories_getStoriesByID req = new TL_stories.TL_stories_getStoriesByID(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + req.id.addAll(ids); + request = req; + offset_id = -1; } else { TL_stories.TL_stories_getStoriesArchive req = new TL_stories.TL_stories_getStoriesArchive(); req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java index cd3998657e..f54614683b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java @@ -16,9 +16,11 @@ import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.DialogCell; +import org.telegram.ui.Cells.ManageChatUserCell; import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ReactedUserHolderView; import org.telegram.ui.Cells.SharedPhotoVideoCell2; +import org.telegram.ui.Cells.StatisticPostInfoCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.Components.BlurredRecyclerView; import org.telegram.ui.Components.RecyclerListView; @@ -227,6 +229,28 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto updateClip(holder); return true; } + } else if (child instanceof StatisticPostInfoCell) { + StatisticPostInfoCell cell = (StatisticPostInfoCell) child; + if (cell.getPostInfo().getId() == storyId) { + holder.view = cell.getImageView(); + holder.params = cell.getStoryAvatarParams(); + holder.storyImage = cell.getImageView().getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; + updateClip(holder); + return true; + } + } else if (child instanceof ManageChatUserCell) { + ManageChatUserCell cell = (ManageChatUserCell) child; + if (cell.getStoryItem() != null && cell.getStoryItem().dialogId == dialogId && cell.getStoryItem().messageId == messageId) { + holder.view = cell.getAvatarImageView(); + holder.params = cell.getStoryAvatarParams(); + holder.avatarImage = cell.getAvatarImageView().getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; + updateClip(holder); + return true; + } } } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java index e43c492ff8..555ededf81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -78,6 +78,9 @@ public void getAllStories(Consumer consumer) { if (data != null) { TL_stories.StoryItem storyItem = TL_stories.StoryItem.TLdeserialize(data, data.readInt32(true), true); storyItem.dialogId = dialogId; + if (storyItem.fwd_from != null && storyItem.fwd_from.from != null) { + MessagesStorage.addLoadPeerInfo(storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } StoryCustomParamsHelper.readLocalParams(storyItem, customData); storyItems.add(storyItem); data.reuse(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java index 4f752fcb79..68a1ddf1da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -42,6 +42,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ColoredImageSpan; @@ -140,6 +141,10 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv unreadState = state = getPredictiveUnreadState(storiesController, dialogId); } + if (params.forceState != 0) { + unreadState = state = params.forceState; + } + if (params.currentState != state) { if (params.currentState == STATE_PROGRESS) { animated = true; @@ -1044,6 +1049,7 @@ public static class AvatarStoryParams { private long dialogId; public int currentState; + public int forceState; public int prevState; public float progressToSate = 1f; public boolean showProgress = false; @@ -1317,4 +1323,90 @@ void cancel() { params = null; } } + + public static class StoryGradientTools { + public final int currentAccount = UserConfig.selectedAccount; + + private final Runnable invalidate; + private final boolean isDialogCell; + private final GradientTools tools; + + private int color1, color2; + private final AnimatedColor animatedColor1, animatedColor2; + + public StoryGradientTools(View view, boolean isDialogCell) { + this(view::invalidate, isDialogCell); + } + + public StoryGradientTools(Runnable invalidate, boolean isDialogCell) { + this.invalidate = invalidate; + this.isDialogCell = isDialogCell; + + animatedColor1 = new AnimatedColor(invalidate, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + animatedColor2 = new AnimatedColor(invalidate, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + tools = new GradientTools(); + tools.isDiagonal = true; + tools.isRotate = true; + resetColors(false); + tools.paint.setStrokeWidth(AndroidUtilities.dpf2(2.3f)); + tools.paint.setStyle(Paint.Style.STROKE); + tools.paint.setStrokeCap(Paint.Cap.ROUND); + } + + public void setUser(TLRPC.User user, boolean animated) { + int colorId = -1; + if (user != null && user.profile_color != null) { + colorId = user.profile_color.color; + } + setColorId(colorId, animated); + } + + public void setChat(TLRPC.Chat chat, boolean animated) { + int colorId = -1; +// if (chat != null && chat.profile_color != null) { +// colorId = chat.profile_color.color; +// } + setColorId(colorId, animated); + } + + public void setColorId(int colorId, boolean animated) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (peerColor != null) { + setColors( + peerColor.getStoryColor1(Theme.isCurrentThemeDark()), + peerColor.getStoryColor2(Theme.isCurrentThemeDark()), + animated + ); + } else { + resetColors(animated); + } + } + private void resetColors(boolean animated) { + if (isDialogCell) { + setColors(Theme.getColor(Theme.key_stories_circle_dialog1), Theme.getColor(Theme.key_stories_circle_dialog2), animated); + } else { + setColors(Theme.getColor(Theme.key_stories_circle1), Theme.getColor(Theme.key_stories_circle2), animated); + } + } + + private void setColors(int color1, int color2, boolean animated) { + this.color1 = color1; + this.color2 = color2; + if (!animated) { + this.animatedColor1.set(color1, true); + this.animatedColor2.set(color2, true); + } + if (invalidate != null) { + invalidate.run(); + } + } + + public Paint getPaint(RectF bounds) { + tools.setColors(animatedColor1.set(color1), animatedColor2.set(color2)); + tools.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); + return tools.paint; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java index 1187a302af..57b35053fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -1,5 +1,8 @@ package org.telegram.ui.Stories; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.lerp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -13,6 +16,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -20,6 +24,7 @@ import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; @@ -43,22 +48,32 @@ import androidx.dynamicanimation.animation.SpringForce; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingDrawable; +import org.telegram.ui.Components.ReplyMessageLine; import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilersClickDetector; @@ -67,6 +82,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Stack; import java.util.concurrent.atomic.AtomicReference; @@ -93,7 +109,7 @@ public class StoryCaptionView extends NestedScrollView { private OverScroller scroller; private boolean isLandscape; - private int textHash; + private int textHash, replytitleHash, replytextHash; private int prevHeight; private float backgroundAlpha = 1f; @@ -124,7 +140,7 @@ public StoryCaptionView(@NonNull Context context, Theme.ResourcesProvider resour addView(captionContainer, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); paint.setColor(Color.BLACK); - setFadingEdgeLength(AndroidUtilities.dp(12)); + setFadingEdgeLength(dp(12)); setVerticalFadingEdgeEnabled(true); setWillNotDraw(false); @@ -155,6 +171,10 @@ public StoryCaptionView(@NonNull Context context, Theme.ResourcesProvider resour } } + public void onReplyClick(Reply reply) { + + } + public void onLinkLongPress(URLSpan span, View spoilersTextView, Runnable done) { } @@ -251,15 +271,21 @@ public int calculateNewContainerMarginTop(int width, int height) { final StoryCaptionTextView textView = captionTextview; final CharSequence text = textView.state[0].text; + final CharSequence replytitle = textView.state[0].reply != null ? textView.state[0].reply.title : null; + final CharSequence replytext = textView.state[0].reply != null ? textView.state[0].reply.text : null; final int textHash = text.hashCode(); + final int replytitleHash = replytitle != null ? replytitle.hashCode() : 0; + final int replytextHash = replytext != null ? replytext.hashCode() : 0; final boolean isLandscape = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; - if (this.textHash == textHash && this.isLandscape == isLandscape && this.prevHeight == height && !textView.updating) { + if (this.textHash == textHash && this.replytitleHash == replytitleHash && this.replytextHash == replytextHash && this.isLandscape == isLandscape && this.prevHeight == height && !textView.updating) { return -1; } this.textHash = textHash; + this.replytitleHash = replytitleHash; + this.replytextHash = replytextHash; this.isLandscape = isLandscape; this.prevHeight = height; @@ -364,7 +390,7 @@ private void startSpringAnimationIfNotRunning(float velocityY) { springAnimation.setStartVelocity(velocityY); springAnimation.start(); } - if (getScrollY() < AndroidUtilities.dp(2)) { + if (getScrollY() < dp(2)) { collapse(); } } @@ -468,7 +494,7 @@ public void invalidate() { } public float getProgressToBlackout() { - int maxHeight = Math.min(prevHeight, AndroidUtilities.dp(40)); + int maxHeight = Math.min(prevHeight, dp(40)); return Utilities.clamp((getScrollY() - captionTextview.getTranslationY()) / maxHeight, 1f, 0); } @@ -488,9 +514,9 @@ public void expand(boolean force) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); valueAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); - final float toScrollY = Math.min(getMeasuredHeight() - blackoutBottomOffset - AndroidUtilities.dp(64), captionContainer.getBottom() - getMeasuredHeight()); - setScrollY((int) AndroidUtilities.lerp(fromScrollY, toScrollY, value)); - captionTextview.progressToExpand = AndroidUtilities.lerp(fromP, toP, value); + final float toScrollY = Math.min(getMeasuredHeight() - blackoutBottomOffset - dp(64), captionContainer.getBottom() - getMeasuredHeight()); + setScrollY((int) lerp(fromScrollY, toScrollY, value)); + captionTextview.progressToExpand = lerp(fromP, toP, value); captionTextview.invalidate(); }); valueAnimator.setDuration(250); @@ -511,8 +537,8 @@ public void collapse() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); valueAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); - setScrollY((int) AndroidUtilities.lerp(fromScrollY, toScrollY, value)); - captionTextview.progressToExpand = AndroidUtilities.lerp(fromP, toP, value); + setScrollY((int) lerp(fromScrollY, toScrollY, value)); + captionTextview.progressToExpand = lerp(fromP, toP, value); captionTextview.invalidate(); }); valueAnimator.setDuration(250); @@ -548,6 +574,162 @@ public void checkCancelTextSelection() { } } + public static class Reply { + private int currentAccount; + public Long peerId; + public Integer storyId; + + private boolean small = true; + private final AnimatedFloat animatedSmall = new AnimatedFloat(0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + public final ButtonBounce bounce = new ButtonBounce(null); + public final Drawable ripple = Theme.createRadSelectorDrawable(0x20ffffff, 0, 0); + + public CharSequence title, text; + public boolean updateText; + + public Text titleLayout, textLayout; + + private boolean loaded, loading; + private View view; + public ReplyMessageLine repostLine; + private Runnable whenLoaded; + + public void listen(View view, Runnable whenLoaded) { + this.view = view; + this.whenLoaded = whenLoaded; + this.repostLine = new ReplyMessageLine(view); + ripple.setCallback(view); + animatedSmall.setParent(view); + bounce.setView(view); + load(); + } + + public void load() { + if (!loaded && !loading && peerId != null && storyId != null && view != null) { + loading = true; + MessagesController.getInstance(currentAccount).getStoriesController().resolveStoryLink(peerId, storyId, fwdStoryItem -> { + loaded = true; + if (fwdStoryItem != null && fwdStoryItem.caption != null) { + updateText = true; + text = fwdStoryItem.caption; + small = TextUtils.isEmpty(text); + if (view != null) { + view.invalidate(); + } + if (whenLoaded != null) { + whenLoaded.run(); + } + } + }); + } + } + + public static Reply from(int currentAccount, TL_stories.StoryItem storyItem) { + if (storyItem == null || storyItem.fwd_from == null) { + return null; + } + Reply reply = new Reply(); + reply.currentAccount = currentAccount; + if (storyItem.fwd_from.from != null) { + long did = reply.peerId = DialogObject.getPeerDialogId(storyItem.fwd_from.from); + if (did >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); + reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + reply.title = new SpannableStringBuilder(ChatObject.isChannelAndNotMegaGroup(chat) ? MessageObject.channelSpan() : MessageObject.groupSpan()).append(" ").append(chat != null ? chat.title : ""); + } + } else if (storyItem.fwd_from.from_name != null) { + reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(storyItem.fwd_from.from_name); + } + reply.small = true; + if ((storyItem.fwd_from.flags & 4) != 0) { + reply.storyId = storyItem.fwd_from.story_id; + } + reply.load(); + return reply; + } + + public static Reply from(StoriesController.UploadingStory uploadingStory) { + if (uploadingStory == null || uploadingStory.entry == null || !uploadingStory.entry.isRepost) { + return null; + } + Reply reply = new Reply(); + reply.title = uploadingStory.entry.repostPeerName; + reply.text = uploadingStory.entry.repostCaption; + reply.small = TextUtils.isEmpty(reply.text); + return reply; + } + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Path clipRipple = new Path(); + public final RectF bounds = new RectF(); + private int width; + + public int height() { + return small ? dp(22) : dp(42); + } + + public int width() { + return width; + } + + public void setPressed(boolean pressed, float x, float y) { + bounce.setPressed(pressed); + ripple.setState(pressed ? new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled} : new int[] {}); + if (pressed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ripple.setHotspot(x, y); + } + } + + public void draw(Canvas canvas, float width) { + if (titleLayout == null) { + titleLayout = new Text(title == null ? "" : title, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + if (textLayout == null || updateText) { + textLayout = new Text(text == null ? "" : text, 14); + } + + final float smallT = animatedSmall.set(small); + + backgroundPaint.setColor(0x40000000); + final int boxwidth = this.width = (int) Math.min(width, lerp(dp(20), dp(18), smallT) + Math.max(titleLayout.getCurrentWidth(), textLayout.getCurrentWidth())); + final int boxheight = lerp(dp(42), dp(22), smallT); + bounds.set(0, 0, boxwidth, boxheight); + + canvas.save(); + final float s = bounce.getScale(.02f); + canvas.scale(s, s, bounds.centerX(), bounds.centerY()); + final float r = lerp(dp(5), dp(11), smallT); + canvas.drawRoundRect(bounds, r, r, backgroundPaint); + + canvas.save(); + clipRipple.rewind(); + clipRipple.addRoundRect(bounds, r, r, Path.Direction.CW); + canvas.clipPath(clipRipple); + ripple.setBounds(0, 0, boxwidth, boxheight); + ripple.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.clipRect(0, 0, dp(3), dp(42)); + AndroidUtilities.rectTmp.set(0, 0, dp(10), dp(42)); + linePaint.setColor(0xFFFFFFFF); + linePaint.setAlpha((int) (0xFF * (1f - smallT))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), linePaint); + canvas.restore(); + int ellipsize = boxwidth - dp(20); + if (boxwidth < width) { + ellipsize = (int) Math.min(ellipsize + dp(12), width - dp(20)); + } + titleLayout.ellipsize(ellipsize).draw(canvas, lerp(dp(10), dp(7), smallT), lerp(dp(12), dp(11), smallT), 0xFFFFFFFF, 1f); + textLayout.ellipsize(ellipsize).draw(canvas, dp(10), dp(30), 0xFFFFFFFF, 1f - smallT); + canvas.restore(); + } + } + public class StoryCaptionTextView extends View implements TextSelectionHelper.SimpleSelectabeleView { private final PorterDuffColorFilter emojiColorFilter; @@ -562,7 +744,7 @@ public class StoryCaptionTextView extends View implements TextSelectionHelper.Si float showMoreX; public int collapsedTextHeight(int height) { - return AndroidUtilities.lerp(state[0].collapsedTextHeight(height), state[1] == null ? 0 : state[1].collapsedTextHeight(height), updateT); + return lerp(state[0].collapsedTextHeight(height), state[1] == null ? 0 : state[1].collapsedTextHeight(height), updateT); } public class TextState { @@ -582,6 +764,7 @@ public class TextState { int textHeight; CharSequence text = ""; + public Reply reply; public boolean translating; public final AnimatedFloat translateT = new AnimatedFloat(StoryCaptionView.this, 0, 400, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -590,6 +773,7 @@ public class TextState { private Path loadingPath = new Path(); public int collapsedTextHeight(int height) { + final int replyOffset = reply != null ? reply.height() + dp(8) : 0; if (fullLayout == null) { return height - (verticalPadding * 2 + textHeight); } @@ -600,7 +784,7 @@ public int collapsedTextHeight(int height) { } int i = Math.min(3, lineCount); final int lineHeight = textPaint.getFontMetricsInt(null); - return height - lineHeight * (i + 1); + return height - lineHeight * (i + 1) - replyOffset; } public TextState() { @@ -629,8 +813,17 @@ public TextState() { loadingDrawable.setCallback(StoryCaptionTextView.this); } - public void setup(CharSequence text) { + public void setup(CharSequence text, Reply reply) { this.text = text; + this.reply = reply; + if (this.reply != null) { + this.reply.listen(StoryCaptionTextView.this, () -> { + sizeCached = 0; + requestLayout(); + StoryCaptionView.this.updateTopMargin(); + StoryCaptionView.this.requestLayout(); + }); + } sizeCached = 0; requestLayout(); } @@ -639,6 +832,9 @@ public void measure(int width) { if (TextUtils.isEmpty(text)) { fullLayout = null; textHeight = 0; + if (reply != null) { + textHeight += reply.height() + dp(4); + } if (this == state[0]) { showMore = null; } @@ -649,6 +845,10 @@ public void measure(int width) { } fullLayout = makeTextLayout(textPaint, text, width); textHeight = fullLayout.getHeight(); + int replyOffset = 0; + if (reply != null) { + textHeight += (replyOffset = reply.height() + dp(8)); + } float space = textPaint.measureText(" "); shouldCollapse = fullLayout.getLineCount() > 3; if (shouldCollapse && fullLayout.getLineCount() == 4) { @@ -664,7 +864,7 @@ public void measure(int width) { String showMoreText = LocaleController.getString("ShowMore", R.string.ShowMore); showMore = makeTextLayout(showMorePaint, showMoreText, width); - showMoreY = verticalPadding + collapsedY - AndroidUtilities.dpf2(0.3f); + showMoreY = verticalPadding + replyOffset + collapsedY - AndroidUtilities.dpf2(0.3f); showMoreX = width + horizontalPadding - showMorePaint.measureText(showMoreText); } @@ -698,7 +898,7 @@ public void measure(int width) { lineInfo.staticLayout = layout; lineInfo.finalX = fullLayout.getLineLeft(line); lineInfo.finalY = fullLayout.getLineTop(line) + fullLayout.getTopPadding(); - if (x < showMoreX - AndroidUtilities.dp(16)) { + if (x < showMoreX - dp(16)) { lineInfo.collapsedY = collapsedY; lineInfo.collapsedX = x; x += Math.abs(layout.getLineRight(0) - layout.getLineLeft(0)) + space; @@ -726,7 +926,7 @@ public void draw(Canvas canvas, float alpha) { return; } - alpha = AndroidUtilities.lerp(alpha, alpha * .7f, loadingT); + alpha = lerp(alpha, alpha * .7f, loadingT); if (alpha >= 1) { drawInternal(canvas, loadingT); } else { @@ -760,8 +960,17 @@ private void putLayoutRects(Layout layout, float tx, float ty) { } private void drawInternal(Canvas canvas, float loadingT) { + int replyOffset = 0; + if (reply != null) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + reply.draw(canvas, getWidth() - horizontalPadding - horizontalPadding); + replyOffset = reply.height() + dp(8); + canvas.restore(); + } + canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); if (links.draw(canvas)) { invalidate(); } @@ -773,7 +982,7 @@ private void drawInternal(Canvas canvas, float loadingT) { if (!spoilers.isEmpty() || firstLayout == null) { if (fullLayout != null) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); if (textSelectionHelper.isInSelectionMode()) { textSelectionHelper.draw(canvas); } @@ -783,26 +992,26 @@ private void drawInternal(Canvas canvas, float loadingT) { canvas.restore(); if (drawLoading) { - putLayoutRects(fullLayout, horizontalPadding, verticalPadding); + putLayoutRects(fullLayout, horizontalPadding, verticalPadding + replyOffset); } } } else { if (textSelectionHelper.isInSelectionMode()) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); textSelectionHelper.draw(canvas); canvas.restore(); } if (firstLayout != null) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); drawLayout(firstLayout, canvas, spoilers); firstLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, firstLayoutEmoji, firstLayout); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, firstLayout, firstLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); canvas.restore(); if (drawLoading) { - putLayoutRects(firstLayout, horizontalPadding, verticalPadding); + putLayoutRects(firstLayout, horizontalPadding, verticalPadding + replyOffset); } } @@ -817,12 +1026,12 @@ private void drawInternal(Canvas canvas, float loadingT) { if (progressToExpand == 0) { continue; } - canvas.translate(horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + canvas.translate(horizontalPadding + lineInfo.finalX, verticalPadding + replyOffset + lineInfo.finalY); canvas.saveLayerAlpha(0, 0, lineInfo.staticLayout.getWidth(), lineInfo.staticLayout.getHeight(), (int) (255 * progressToExpand), Canvas.ALL_SAVE_FLAG); drawLayout(lineInfo.staticLayout, canvas, spoilers); if (drawLoading) { - putLayoutRects(lineInfo.staticLayout, horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + putLayoutRects(lineInfo.staticLayout, horizontalPadding + lineInfo.finalX, verticalPadding + replyOffset + lineInfo.finalY); } lineInfo.staticLayout.draw(canvas); @@ -831,12 +1040,12 @@ private void drawInternal(Canvas canvas, float loadingT) { canvas.restore(); //textPaint.setAlpha(255); } else { - float offsetX = AndroidUtilities.lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); - float offsetY = AndroidUtilities.lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); - canvas.translate(horizontalPadding + offsetX, verticalPadding + offsetY); + float offsetX = lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); + float offsetY = lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); + canvas.translate(horizontalPadding + offsetX, verticalPadding + replyOffset + offsetY); //drawLayout(lineInfo.staticLayout, canvas, -offsetX, -offsetY); if (drawLoading) { - putLayoutRects(lineInfo.staticLayout, horizontalPadding + offsetX, verticalPadding + offsetY); + putLayoutRects(lineInfo.staticLayout, horizontalPadding + offsetX, verticalPadding + replyOffset + offsetY); } lineInfo.staticLayout.draw(canvas); lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, lineInfo.layoutEmoji, lineInfo.staticLayout); @@ -868,8 +1077,9 @@ public boolean touch(MotionEvent event) { } boolean linkResult = false; if (allowIntercept && event.getAction() == MotionEvent.ACTION_DOWN || (pressedLink != null || pressedEmoji != null) && event.getAction() == MotionEvent.ACTION_UP) { + final int replyOffset = reply == null ? 0 : reply.height() + dp(8); int x = (int) (event.getX() - horizontalPadding); - int y = (int) (event.getY() - verticalPadding); + int y = (int) (event.getY() - verticalPadding - replyOffset); final int line = fullLayout.getLineForVertical(y); final int off = fullLayout.getOffsetForHorizontal(line, x); final float left = fullLayout.getLineLeft(line); @@ -986,16 +1196,16 @@ public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesPr textPaint.setColor(Color.WHITE); textPaint.linkColor = Color.WHITE;//Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider); - textPaint.setTextSize(AndroidUtilities.dp(15)); + textPaint.setTextSize(dp(15)); showMorePaint.setColor(Color.WHITE); showMorePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - showMorePaint.setTextSize(AndroidUtilities.dp(16)); + showMorePaint.setTextSize(dp(16)); xRefPaint.setColor(0xff000000); xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); - xRefGradinetPaint.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(16), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); + xRefGradinetPaint.setShader(new LinearGradient(0, 0, dp(16), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); xRefGradinetPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); emojiColorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); @@ -1003,20 +1213,20 @@ public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesPr @Override protected boolean verifyDrawable(@NonNull Drawable who) { - if (state[0] != null && state[0].loadingDrawable == who) { + if (state[0] != null && (state[0].loadingDrawable == who || state[0].reply != null && state[0].reply.ripple == who)) { return true; } - if (state[1] != null && state[1].loadingDrawable == who) { + if (state[1] != null && (state[1].loadingDrawable == who || state[1].reply != null && state[1].reply.ripple == who)) { return true; } return super.verifyDrawable(who); } - public void setText(CharSequence text, boolean translating, boolean animated) { + public void setText(CharSequence text, Reply reply, boolean translating, boolean animated) { if (text == null) { text = ""; } - if (TextUtils.equals(state[0].text, text)) { + if (TextUtils.equals(state[0].text, text) && state[0].reply == reply) { state[0].translating = translating; invalidate(); return; @@ -1030,16 +1240,16 @@ public void setText(CharSequence text, boolean translating, boolean animated) { if (state[1] == null) { state[1] = new TextState(); } - state[1].setup(state[0].text); + state[1].setup(state[0].text, state[0].reply); state[1].translating = state[0].translating; state[1].translateT.set(state[0].translateT.get(), true); - state[0].setup(text); + state[0].setup(text, reply); state[0].translating = translating; state[0].translateT.set(0, true); updateT = 1; animateUpdate(); } else { - state[0].setup(text); + state[0].setup(text, reply); state[0].translating = translating; invalidate(); updateT = 0; @@ -1080,8 +1290,8 @@ public void onAnimationEnd(Animator animation) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int size = widthMeasureSpec + heightMeasureSpec << 16; - horizontalPadding = AndroidUtilities.dp(16); - verticalPadding = AndroidUtilities.dp(8); + horizontalPadding = dp(16); + verticalPadding = dp(8); if (sizeCached != size) { sizeCached = size; int width = MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding * 2; @@ -1090,7 +1300,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { state[1].measure(width); } } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + AndroidUtilities.lerp(state[0].textHeight, state[1] == null ? 0 : state[1].textHeight, updateT), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + lerp(state[0].textHeight, state[1] == null ? 0 : state[1].textHeight, updateT), MeasureSpec.EXACTLY)); } @Override @@ -1113,11 +1323,11 @@ protected void onDraw(Canvas canvas) { xRefPaint.setAlpha((int) (255 * alpha)); showMorePaint.setAlpha((int) (255 * alpha)); canvas.save(); - canvas.translate(showMoreX - AndroidUtilities.dp(32), showMoreY); - canvas.drawRect(0, 0, AndroidUtilities.dp(32), showMore.getHeight() + verticalPadding, xRefGradinetPaint); + canvas.translate(showMoreX - dp(32), showMoreY); + canvas.drawRect(0, 0, dp(32), showMore.getHeight() + verticalPadding, xRefGradinetPaint); canvas.restore(); - canvas.drawRect(showMoreX - AndroidUtilities.dp(16), showMoreY, getMeasuredWidth(), showMoreY + showMore.getHeight() + verticalPadding, xRefPaint); + canvas.drawRect(showMoreX - dp(16), showMoreY, getMeasuredWidth(), showMoreY + showMore.getHeight() + verticalPadding, xRefPaint); canvas.save(); canvas.translate(showMoreX, showMoreY); showMore.draw(canvas); @@ -1207,8 +1417,26 @@ public boolean dispatchTouchEvent(MotionEvent event) { allowIntercept = false; } } + boolean r = false; + if (state[0] != null && state[0].reply != null) { + AndroidUtilities.rectTmp.set(horizontalPadding, verticalPadding, horizontalPadding + state[0].reply.width(), verticalPadding + state[0].reply.height()); + final boolean hit = AndroidUtilities.rectTmp.contains(event.getX(), event.getY()); + if (hit) { + allowIntercept = false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN && hit) { + state[0].reply.setPressed(true, event.getX(), event.getY()); + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (event.getAction() == MotionEvent.ACTION_UP && state[0].reply.bounce.isPressed()) { + onReplyClick(state[0].reply); + } + state[0].reply.setPressed(false, event.getX(), event.getY()); + } + r = hit; + } if (allowIntercept && (expanded || state[0].firstLayout == null)) { - textSelectionHelper.update(horizontalPadding, verticalPadding); + final int replyOffset = state[0] != null && state[0].reply != null ? state[0].reply.height() + dp(8) : 0; + textSelectionHelper.update(horizontalPadding, verticalPadding + replyOffset); textSelectionHelper.onTouchEvent(event); } if (!textSelectionHelper.isInSelectionMode() && allowIntercept && allowClickSpoilers && state[0].clickDetector.onTouchEvent(event)) { @@ -1216,7 +1444,7 @@ public boolean dispatchTouchEvent(MotionEvent event) { textSelectionHelper.clear(); return true; } - return super.dispatchTouchEvent(event); + return super.dispatchTouchEvent(event) || r; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java index 90000e9883..c0ff28159e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -1616,6 +1616,9 @@ public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets i AndroidUtilities.hideKeyboard(fragment.getFragmentView()); } + static int J = 0; + int j = J++; + private void showKeyboard() { PeerStoriesView currentPeerView = storiesViewPager.getCurrentPeerView(); if (currentPeerView != null) { @@ -2208,7 +2211,6 @@ public void instantClose() { transitionViewHolder.storyImage = null; transitionViewHolder.avatarImage = null; containerView.disableHwAcceleration(); - checkNavBarColor(); locker.unlock(); if (currentPlayerScope != null) { currentPlayerScope.invalidate(); @@ -2222,6 +2224,7 @@ public void instantClose() { windowView = null; isShowing = false; foundViewToClose = false; + checkNavBarColor(); if (onCloseListener != null) { onCloseListener.run(); onCloseListener = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java index 64520608bd..b0f56f9ac4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java @@ -11,7 +11,7 @@ import org.telegram.ui.Components.CubicBezierInterpolator; public class UploadingDotsSpannable extends ReplacementSpan { - private String text = "…"; + private final String text = "…"; private View parent; int swapPosition1 = 1; @@ -28,12 +28,14 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon return (int) paint.measureText(this.text); } + public boolean fixTop; + @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { TextPaint textPaint = (TextPaint) paint; float characterWidth = paint.measureText(this.text) / 3; - float baseline = -textPaint.getFontMetrics().top; + float baseline = fixTop ? -textPaint.getFontMetrics().ascent : -textPaint.getFontMetrics().top; float textThickness = (float) ((textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top) * (isMediumTypeface ? 0.05f : 0.0365f)); baseline -= textThickness; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java index b45faddfd9..c58074d033 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java @@ -7,7 +7,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -21,7 +20,6 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; -import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.R; @@ -39,10 +37,12 @@ public class ButtonWithCounterView extends FrameLayout { private final Paint paint; public final AnimatedTextView.AnimatedTextDrawable text; + public final AnimatedTextView.AnimatedTextDrawable subText; private final AnimatedTextView.AnimatedTextDrawable countText; private float countAlpha; private final AnimatedFloat countAlphaAnimated = new AnimatedFloat(350, CubicBezierInterpolator.EASE_OUT_QUINT); private final View rippleView; + private final boolean filled; public ButtonWithCounterView(Context context, Theme.ResourcesProvider resourcesProvider) { this(context, true, resourcesProvider); @@ -51,6 +51,7 @@ public ButtonWithCounterView(Context context, Theme.ResourcesProvider resourcesP public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesProvider resourcesProvider) { super(context); + this.filled = filled; this.resourcesProvider = resourcesProvider; ScaleStateListAnimator.apply(this, .02f, 1.2f); @@ -76,6 +77,13 @@ public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesPro text.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); text.setGravity(Gravity.CENTER_HORIZONTAL); + subText = new AnimatedTextView.AnimatedTextDrawable(true, true, false); + subText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + subText.setCallback(this); + subText.setTextSize(dp(12)); + subText.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + subText.setGravity(Gravity.CENTER_HORIZONTAL); + countText = new AnimatedTextView.AnimatedTextDrawable(false, false, true); countText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); countText.setCallback(this); @@ -88,6 +96,13 @@ public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesPro setWillNotDraw(false); } + public void updateColors() { + rippleView.setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), 8, 8)); + text.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + subText.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + countText.setTextColor(Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider)); + } + public void setCounterColor(int color) { countText.setTextColor(color); counterDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); @@ -138,6 +153,64 @@ public void setText(CharSequence newText, boolean animated) { invalidate(); } + private float subTextT = 0f; + private ValueAnimator subTextVisibleAnimator; + private boolean subTextVisible; + + public boolean isSubTextVisible() { + return subTextVisible; + } + + private void cleanSubTextVisibleAnimator(){ + if (subTextVisibleAnimator != null) { + subTextVisibleAnimator.cancel(); + subTextVisibleAnimator = null; + } + } + + public void setSubText(CharSequence newText, boolean animated) { + boolean isNewTextVisible = newText != null; + if (animated) { + subText.cancelAnimation(); + } + + setContentDescription(newText); + invalidate(); + if (subTextVisible && !isNewTextVisible) { + cleanSubTextVisibleAnimator(); + subTextVisibleAnimator = ValueAnimator.ofFloat(subTextT, 0f); + subTextVisibleAnimator.addUpdateListener(anm -> { + subTextT = (float) anm.getAnimatedValue(); + invalidate(); + }); + subTextVisibleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + subTextVisible = false; + subText.setText(null, false); + } + }); + subTextVisibleAnimator.setDuration(200); + subTextVisibleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + subTextVisibleAnimator.start(); + } else { + subText.setText(newText, animated); + } + + if (!subTextVisible && isNewTextVisible) { + subTextVisible = true; + cleanSubTextVisibleAnimator(); + subTextVisibleAnimator = ValueAnimator.ofFloat(subTextT, 1f); + subTextVisibleAnimator.addUpdateListener(anm -> { + subTextT = (float) anm.getAnimatedValue(); + invalidate(); + }); + subTextVisibleAnimator.setDuration(200); + subTextVisibleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + subTextVisibleAnimator.start(); + } + } + private float loadingT = 0; private boolean loading; private ValueAnimator loadingAnimator; @@ -257,7 +330,7 @@ public void setEnabled(boolean enabled) { @Override protected boolean verifyDrawable(@NonNull Drawable who) { - return text == who || countText == who || super.verifyDrawable(who); + return text == who || subText == who || countText == who || super.verifyDrawable(who); } @Override @@ -268,6 +341,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private CircularProgressDrawable loadingDrawable; private int globalAlpha = 255; + private final int subTextAlpha = 200; @Override protected void onDraw(Canvas canvas) { @@ -303,10 +377,30 @@ protected void onDraw(Canvas canvas) { (int) ((getMeasuredWidth() - width + getWidth()) / 2f + textWidth), (int) ((getMeasuredHeight() + text.getHeight()) / 2f - dp(1)) ); + AndroidUtilities.rectTmp2.offset(0, (int) (-dp(7) * subTextT)); text.setAlpha((int) (globalAlpha * (1f - loadingT) * AndroidUtilities.lerp(.5f, 1f, enabledT))); text.setBounds(AndroidUtilities.rectTmp2); text.draw(canvas); + if (subTextVisible) { + float subTextWidth = subText.getCurrentWidth(); + width = subTextWidth; + AndroidUtilities.rectTmp2.set( + (int) ((getMeasuredWidth() - width - getWidth()) / 2f), + (int) ((getMeasuredHeight() - subText.getHeight()) / 2f - dp(1)), + (int) ((getMeasuredWidth() - width + getWidth()) / 2f + subTextWidth), + (int) ((getMeasuredHeight() + subText.getHeight()) / 2f - dp(1)) + ); + AndroidUtilities.rectTmp2.offset(0, dp(11)); + canvas.save(); + float scale = AndroidUtilities.lerp(.1f, 1f, subTextT); + canvas.scale(scale, scale, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.bottom); + subText.setAlpha((int) (subTextAlpha * (1f - loadingT) * subTextT * AndroidUtilities.lerp(.5f, 1f, enabledT))); + subText.setBounds(AndroidUtilities.rectTmp2); + subText.draw(canvas); + canvas.restore(); + } + AndroidUtilities.rectTmp2.set( (int) ((getMeasuredWidth() - width) / 2f + textWidth + dp(countFilled ? 5 : 2)), (int) ((getMeasuredHeight() - dp(18)) / 2f), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java index df224c8c0b..6843959032 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -17,10 +17,12 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; +import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -43,6 +45,8 @@ import androidx.annotation.Nullable; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import com.google.zxing.common.detector.MathUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; @@ -73,6 +77,7 @@ import org.telegram.ui.Components.MentionsContainerView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.Text; import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.DarkThemeResourceProvider; @@ -81,7 +86,7 @@ public class CaptionContainerView extends FrameLayout { protected Theme.ResourcesProvider resourcesProvider; private final FrameLayout containerView; - private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + protected final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public final EditTextEmoji editText; private Drawable applyButtonCheck; private CombinedDrawable applyButtonDrawable; @@ -94,8 +99,8 @@ public class CaptionContainerView extends FrameLayout { private final LinearGradient fadeGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(10), new int[] { 0xffff0000, 0x00000000 }, new float[] { 0.05f, 1 }, Shader.TileMode.CLAMP); private final Matrix matrix = new Matrix(); - private final TextPaint hintTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private Bitmap hintTextBitmap; + private final TextPaint hintTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final Paint hintTextBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final FrameLayout rootView; @@ -107,8 +112,8 @@ public class CaptionContainerView extends FrameLayout { private int shiftDp = -4; private final BlurringShader.BlurManager blurManager; - private final BlurringShader.StoryBlurDrawer captionBlur; - private final BlurringShader.StoryBlurDrawer backgroundBlur; + protected final BlurringShader.StoryBlurDrawer captionBlur, replyTextBlur; + protected final BlurringShader.StoryBlurDrawer backgroundBlur, replyBackgroundBlur; private BlurringShader.StoryBlurDrawer mentionBackgroundBlur; protected int currentAccount = UserConfig.selectedAccount; @@ -136,12 +141,22 @@ public CaptionContainerView(Context context, FrameLayout rootView, SizeNotifierF this.blurManager = blurManager; backgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_BACKGROUND, !customBlur()); + replyBackgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_REPLY_BACKGROUND); + replyTextBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_REPLY_TEXT_XFER); backgroundPaint.setColor(0x80000000); keyboardNotifier = new KeyboardNotifier(rootView, this::updateKeyboard); editText = new EditTextEmoji(context, sizeNotifierFrameLayout, null, getEditTextStyle(), true, new DarkThemeResourceProvider()) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (CaptionContainerView.this instanceof CaptionStory && ((CaptionStory) CaptionContainerView.this).isRecording()) { + return false; + } + return super.dispatchTouchEvent(ev); + } + @Override protected void onEmojiKeyboardUpdate() { keyboardNotifier.fire(); @@ -221,7 +236,7 @@ public void onAnimationEnd(Animator animation) { editText.getEditText().drawHint = this::drawHint; editText.getEditText().setSupportRtlHint(true); captionBlur = new BlurringShader.StoryBlurDrawer(blurManager, editText.getEditText(), customBlur() ? BlurringShader.StoryBlurDrawer.BLUR_TYPE_CAPTION : BlurringShader.StoryBlurDrawer.BLUR_TYPE_CAPTION_XFER); - editText.getEditText().setHintColor(0x80ffffff); + editText.getEditText().setHintColor(0xffffffff); editText.getEditText().setHintText(LocaleController.getString(R.string.AddCaption), false); hintTextBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); editText.getEditText().setTranslationX(AndroidUtilities.dp(-40 + 18)); @@ -288,7 +303,7 @@ public void afterTextChanged(Editable s) { } }); editText.getEditText().setLinkTextColor(Color.WHITE); - addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 12, 12, 12, 12)); + addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 12, 12, 12 + additionalRightMargin(), 12)); applyButton = new BounceableImageView(context); ScaleStateListAnimator.apply(applyButton, 0.05f, 1.25f); @@ -323,6 +338,10 @@ public void afterTextChanged(Editable s) { fadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + public int additionalRightMargin() { + return 0; + } + private final Runnable textChangeRunnable = () -> onTextChange(); protected void onTextChange() {} @@ -360,6 +379,9 @@ public boolean dispatchTouchEvent(MotionEvent ev) { return false; } if (ev.getAction() == MotionEvent.ACTION_DOWN && !keyboardShown) { + if (this instanceof CaptionStory && ((CaptionStory) this).isRecording()) { + return super.dispatchTouchEvent(ev); + } for (int i = 0; i < getChildCount(); ++i) { View child = getChildAt(i); if (child == null || !child.isClickable() || child.getVisibility() != View.VISIBLE || child.getAlpha() < .5f || editText == child) { @@ -372,7 +394,6 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } editText.getEditText().setForceCursorEnd(true); editText.getEditText().requestFocus(); -// editText.getEditText().setSelection(editText.getEditText().length(), editText.getEditText().length()); editText.openKeyboard(); editText.getEditText().setScrollY(0); bounce.setPressed(true); @@ -746,17 +767,111 @@ public boolean onBackPressed() { protected void onEditHeightChange(int height) {} + private boolean hasReply; + private Text replyTitle, replyText; + public void setReply(CharSequence title, CharSequence text) { + if (title == null && text == null) { + hasReply = false; + invalidate(); + } else { + hasReply = true; + + replyTitle = new Text(title == null ? "" : title, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + replyText = new Text(text == null ? "" : text, 14); + } + } + + private Path replyClipPath; + private Paint replyLinePaint; + private Path replyLinePath; + private float[] replyLinePathRadii; + private void drawReply(Canvas canvas) { + if (!hasReply || replyBackgroundBlur == null || replyTextBlur == null || customBlur()) { + return; + } + + float alpha = 1f; + float top; + if (collapsed) { + if (keyboardShown) { + top = bounds.bottom - Math.max(dp(46), editText.getHeight()); + } else { + top = bounds.bottom - Math.min(dp(82), editText.getHeight()); + } + alpha = 1f - collapsedT.get(); + top -= dp(42 + 8); + } else { + top = bounds.top; + } + + Paint bgBlurPaint = replyBackgroundBlur.getPaint(alpha); + Paint textBlurPaint = replyTextBlur.getPaint(alpha); + + AndroidUtilities.rectTmp.set(bounds.left + dp(10), top + dp(10), bounds.right - dp(10), top + dp(10 + 42)); + if (bgBlurPaint != null) { + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), bgBlurPaint); + } + + if (textBlurPaint != null) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xFF, Canvas.ALL_SAVE_FLAG); + } + if (replyClipPath == null) { + replyClipPath = new Path(); + } else { + replyClipPath.rewind(); + } + final float r = lerp(AndroidUtilities.dp(21), 0, keyboardT); + replyClipPath.addRoundRect(bounds, r, r, Path.Direction.CW); + canvas.clipPath(replyClipPath); + if (replyTitle != null) { + replyTitle.ellipsize((int) (bounds.width() - dp(40))).draw(canvas, bounds.left + dp(20), top + dp(22), 0xFFFFFFFF, 1f); + } + if (replyLinePath == null) { + replyLinePath = new Path(); + replyLinePathRadii = new float[8]; + replyLinePathRadii[0] = replyLinePathRadii[1] = dp(5); + replyLinePathRadii[2] = replyLinePathRadii[3] = 0; + replyLinePathRadii[4] = replyLinePathRadii[5] = 0; + replyLinePathRadii[6] = replyLinePathRadii[7] = dp(5); + } else { + replyLinePath.rewind(); + } + AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top, AndroidUtilities.rectTmp.left + dp(3), AndroidUtilities.rectTmp.bottom); + replyLinePath.addRoundRect(AndroidUtilities.rectTmp, replyLinePathRadii, Path.Direction.CW); + if (replyLinePaint == null) { + replyLinePaint = new Paint(); + replyLinePaint.setColor(0xFFFFFFFF); + } + replyLinePaint.setAlpha((int) (0xFF * alpha)); + canvas.drawPath(replyLinePath, replyLinePaint); + if (textBlurPaint != null) { + canvas.save(); + canvas.drawRect(bounds, textBlurPaint); + canvas.restore(); + canvas.restore(); + } + + if (replyText != null) { + replyText.ellipsize((int) (bounds.width() - dp(40))).draw(canvas, bounds.left + dp(20), top + dp(40), 0xFFFFFFFF, 1f); + } + } + @Override protected void dispatchDraw(Canvas canvas) { if (ignoreDraw) { return; } int height = editText.getHeight(); - if (keyboardShown) { + if (collapsed) { + height = dp(40); + } else if (keyboardShown) { height = Math.max(dp(46), height); } else { height = Math.min(dp(82), height); } + if (!collapsed && hasReply) { + height += dp(42 + 8); + } final int heightAnimated = (int) this.heightAnimated.set(height); if (heightAnimated != lastHeight) { onEditHeightChange(heightAnimated); @@ -767,10 +882,9 @@ protected void dispatchDraw(Canvas canvas) { } updateMentionsLayoutPosition(); final float heightTranslation = dpf2(-1) * keyboardT + height - heightAnimated; - if (Math.abs(lastHeightTranslation - heightTranslation) >= 1) { - editText.getEditText().setTranslationY(heightTranslation); + if (Math.abs(lastHeightTranslation - heightTranslation) >= 1 && !collapsed) { + editText.getEditText().setTranslationY(lastHeightTranslation = heightTranslation); } - lastHeightTranslation = heightTranslation; final float pad = lerp(AndroidUtilities.dp(12), 0, keyboardT); bounds.set( @@ -806,11 +920,109 @@ protected void dispatchDraw(Canvas canvas) { } } + final float wasCollapseT = collapsedT.get(); + final float collapseT = collapsedT.set(collapsed); + if (Math.abs(wasCollapseT - collapseT) > 0.001f || (wasCollapseT <= 0) != (collapseT <= 0)) { + invalidateDrawOver2(); + } + if (collapseT > 0) { + canvas.saveLayerAlpha(bounds, 0xFF, Canvas.ALL_SAVE_FLAG); + } + + drawReply(canvas); + super.dispatchDraw(canvas); + if (collapseT > 0) { + final float cx; + if (collapsedFromX == Integer.MAX_VALUE) { + cx = bounds.right - dp(20); + } else if (collapsedFromX == Integer.MIN_VALUE) { + cx = bounds.left + dp(20); + } else { + cx = collapsedFromX; + } + final float cy = bounds.bottom - dp(20); + final float mxr = Math.max( + Math.max(MathUtils.distance(bounds.left, bounds.top, cx, cy), MathUtils.distance(bounds.left, bounds.bottom, cx, cy)), + Math.max(MathUtils.distance(bounds.right, bounds.top, cx, cy), MathUtils.distance(bounds.right, bounds.bottom, cx, cy)) + ); + final float R = mxr * collapseT; + if (collapsePaint == null) { + collapsePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + collapsePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + collapseGradient = new RadialGradient(0, 0, 32, new int[] { -1, -1, 0 }, new float[] { 0, .6f, 1 }, Shader.TileMode.CLAMP); + collapsePaint.setShader(collapseGradient); + collapseGradientMatrix = new Matrix(); + + collapseOutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + collapseOutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + collapseOutGradient = new RadialGradient(0, 0, 32, new int[] { 0, 0, -1 }, new float[] { 0, .5f, 1 }, Shader.TileMode.CLAMP); + collapseOutPaint.setShader(collapseOutGradient); + } + collapseGradientMatrix.reset(); + collapseGradientMatrix.postTranslate(cx, cy); + collapseGradientMatrix.preScale(Math.max(1, R) / 16f, Math.max(1, R) / 16f); + collapseGradient.setLocalMatrix(collapseGradientMatrix); + canvas.save(); + canvas.drawRoundRect(bounds, r, r, collapsePaint); + canvas.restore(); + canvas.restore(); + + canvas.saveLayerAlpha(bounds, 0xFF, Canvas.ALL_SAVE_FLAG); + drawOver(canvas, bounds); + collapseGradientMatrix.reset(); + collapseGradientMatrix.postTranslate(cx, cy); + collapseGradientMatrix.preScale(Math.max(1, R) / 16f, Math.max(1, R) / 16f); + collapseOutGradient.setLocalMatrix(collapseGradientMatrix); + canvas.save(); + canvas.drawRoundRect(bounds, r, r, collapseOutPaint); + canvas.restore(); + canvas.restore(); + + if (!drawOver2FromParent()) { + drawOver2(canvas, bounds, collapseT); + } + } + canvas.restore(); } + public void drawOver(Canvas canvas, RectF bounds) { + + } + + public void drawOver2(Canvas canvas, RectF bounds, float alpha) { + + } + + public float getOver2Alpha() { + return collapsedT.get(); + } + + public boolean drawOver2FromParent() { + return false; + } + + public void invalidateDrawOver2() { + + } + + public boolean collapsed; + public int collapsedFromX; + public final AnimatedFloat collapsedT = new AnimatedFloat(this, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + public void setCollapsed(boolean collapsed, int cx) { + this.collapsed = collapsed; + this.collapsedFromX = cx; + invalidate(); + } + + private Paint collapsePaint; + private RadialGradient collapseGradient; + private Paint collapseOutPaint; + private RadialGradient collapseOutGradient; + private Matrix collapseGradientMatrix; + public RectF getBounds() { return bounds; } @@ -834,6 +1046,7 @@ private void drawHint(Canvas canvas, Runnable draw) { return; } Paint blurPaint = captionBlur.getPaint(1f); + editText.getEditText().setHintColor(blurPaint != null ? 0xffffffff : 0x80ffffff); if (blurPaint == null) { draw.run(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java index d9642cae32..82dd9c7f16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java @@ -1,30 +1,66 @@ package org.telegram.ui.Stories.recorder; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.AndroidUtilities.lerp; import static org.telegram.ui.ActionBar.Theme.RIPPLE_MASK_CIRCLE_20DP; import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextPaint; import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.BlobDrawable; import org.telegram.ui.Components.BlurringShader; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.Text; +import org.telegram.ui.Components.WaveDrawable; public class CaptionStory extends CaptionContainerView { + public ButtonBounce roundButtonBounce; + public ImageView roundButton; + public ImageView periodButton; public PeriodDrawable periodDrawable; private ItemOptions periodPopup; @@ -34,13 +70,27 @@ public class CaptionStory extends CaptionContainerView { public static final int[] periodDrawables = new int[] { R.drawable.msg_story_6h, R.drawable.msg_story_12h, R.drawable.msg_story_24h, R.drawable.msg_story_48h }; private int periodIndex = 0; + private Drawable flipButton; + public CaptionStory(Context context, FrameLayout rootView, SizeNotifierFrameLayout sizeNotifierFrameLayout, FrameLayout containerView, Theme.ResourcesProvider resourcesProvider, BlurringShader.BlurManager blurManager) { super(context, rootView, sizeNotifierFrameLayout, containerView, resourcesProvider, blurManager); + roundButton = new ImageView(context); + roundButtonBounce = new ButtonBounce(roundButton); + roundButton.setImageResource(R.drawable.input_video_story); + roundButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, dp(18))); + roundButton.setScaleType(ImageView.ScaleType.CENTER); + addView(roundButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 10)); + roundButton.setOnClickListener(e -> { + showRemoveRoundAlert(); + }); + periodButton = new ImageView(context); periodButton.setImageDrawable(periodDrawable = new PeriodDrawable()); - periodButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(18))); + periodButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, dp(18))); periodButton.setScaleType(ImageView.ScaleType.CENTER); + setPeriod(86400, false); + addView(periodButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11 + 44 - 4, 10)); periodButton.setOnClickListener(e -> { if (periodPopup != null && periodPopup.isShown()) { return; @@ -82,8 +132,342 @@ public CaptionStory(Context context, FrameLayout rootView, SizeNotifierFrameLayo } periodPopup.setDimAlpha(0).show(); }); - setPeriod(86400, false); - addView(periodButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 10)); + } + + private void checkFlipButton() { + if (flipButton != null) return; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + flipButton = (AnimatedVectorDrawable) ContextCompat.getDrawable(getContext(), R.drawable.avd_flip); + } else { + flipButton = getContext().getResources().getDrawable(R.drawable.vd_flip).mutate(); + } + } + + private boolean hasRoundVideo; + public void setHasRoundVideo(boolean hasRoundVideo) { + roundButton.setImageResource(hasRoundVideo ? R.drawable.input_video_story_remove : R.drawable.input_video_story); + this.hasRoundVideo = hasRoundVideo; + } + + private final RecordDot recordPaint = new RecordDot(this); + private final AnimatedTextView.AnimatedTextDrawable timerTextDrawable = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + { + timerTextDrawable.setAnimationProperties(.16f, 0, 50, CubicBezierInterpolator.DEFAULT); + timerTextDrawable.setTextSize(AndroidUtilities.dp(15)); + timerTextDrawable.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + timerTextDrawable.setText("0:00.0"); + timerTextDrawable.setTextColor(Color.WHITE); + } + + private float slideProgress; + private float lockProgress; + private long startTime; + + @Override + public void drawOver(Canvas canvas, RectF bounds) { + if (currentRecorder != null) { + final float cancel = cancelT.set(cancelling); + final float lock = lockT.set(locked); + + if (startTime <= 0) startTime = System.currentTimeMillis(); + final float wobble = (1f + (float) Math.sin((System.currentTimeMillis() - startTime) / 900f * Math.PI)) / 2f; + + final float rcx = bounds.left + dp(21), rcy = bounds.bottom - dp(20); + recordPaint.setBounds( + (int) (rcx - dp(12)), + (int) (rcy - dp(12)), + (int) (rcx + dp(12)), + (int) (rcy + dp(12)) + ); + recordPaint.draw(canvas); + + timerTextDrawable.setBounds((int) (bounds.left + dp(33.3f) - dp(10) * cancel), (int) (bounds.bottom - dp(20) - dp(9)), (int) (bounds.left + dp(33.3f + 100)), (int) (bounds.bottom - dp(20) + dp(9))); + timerTextDrawable.setText(currentRecorder.sinceRecordingText()); + timerTextDrawable.setAlpha((int) (0xFF * (1f - cancel))); + timerTextDrawable.draw(canvas); + + final float slideToCancelAlpha = (1f - slideProgress) * (1f - lock); + final float cancelAlpha = lock; + + final Paint blurPaint = captionBlur.getPaint(1f); + if (blurPaint != null) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xff, Canvas.ALL_SAVE_FLAG); + } + + if (slideToCancelAlpha > 0) { + if (slideToCancelText == null) { + slideToCancelText = new Text(LocaleController.getString(R.string.SlideToCancel2), 15); + } + if (slideToCancelArrowPath == null) { + slideToCancelArrowPath = new Path(); + slideToCancelArrowPath.moveTo(dp(3.83f), 0); + slideToCancelArrowPath.lineTo(0, dp(5)); + slideToCancelArrowPath.lineTo(dp(3.83f), dp(10)); + + slideToCancelArrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + slideToCancelArrowPaint.setStyle(Paint.Style.STROKE); + slideToCancelArrowPaint.setStrokeCap(Paint.Cap.ROUND); + slideToCancelArrowPaint.setStrokeJoin(Paint.Join.ROUND); + } + + slideToCancelArrowPaint.setStrokeWidth(dp(1.33f)); + + slideToCancelText.ellipsize((int) (bounds.width() - dp(5 + 21 + 16 + 10 + 64) - timerTextDrawable.getCurrentWidth())); + final float width = dp(5 + 6.33f) + slideToCancelText.getWidth(); + final float x = bounds.centerX() - width / 2f - (bounds.width() / 6f) * lerp(slideProgress, 1f, lock) - wobble * dp(6) * (1f - slideProgress); + + int color = blurPaint != null ? 0xffffffff : 0x80ffffff; + color = Theme.multAlpha(color, slideToCancelAlpha); + + canvas.save(); + canvas.translate(x, bounds.centerY() - dp(5)); + slideToCancelArrowPaint.setColor(color); + canvas.drawPath(slideToCancelArrowPath, slideToCancelArrowPaint); + canvas.restore(); + slideToCancelText.draw(canvas, x + dp(5 + 6.33f), bounds.centerY(), color, 1f); + } + + if (cancelAlpha > 0) { + if (cancelText == null) { + cancelText = new Text(LocaleController.getString(R.string.CancelRound), 15, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + + cancelText.ellipsize((int) (bounds.width() - dp(5 + 21 + 16 + 10 + 64) - timerTextDrawable.getCurrentWidth())); + final float x = bounds.centerX() - cancelText.getWidth() / 2f + (bounds.width() / 4f) * (1f - cancelAlpha); + + int color = blurPaint != null ? 0xffffffff : 0x80ffffff; + color = Theme.multAlpha(color, cancelAlpha); + cancelText.draw(canvas, x, bounds.centerY(), color, 1f); + cancelBounds.set(x - dp(12), bounds.top, x + cancelText.getWidth() + dp(12), bounds.bottom); + } + + if (blurPaint != null) { + canvas.drawRect(bounds, blurPaint); + canvas.restore(); + } + + invalidate(); + } + } + + private final Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final BlobDrawable tinyWaveDrawable = new BlobDrawable(11, LiteMode.FLAGS_CHAT); + private final BlobDrawable bigWaveDrawable = new BlobDrawable(12, LiteMode.FLAGS_CHAT); + private final Drawable roundDrawable; + { + whitePaint.setColor(0xFFFFFFFF); + roundPaint.setColor(0xFF1A9CFF); + + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(55); + tinyWaveDrawable.generateBlob(); + + bigWaveDrawable.minRadius = dp(47); + bigWaveDrawable.maxRadius = dp(55); + bigWaveDrawable.generateBlob(); + + roundDrawable = getContext().getResources().getDrawable(R.drawable.input_video_pressed).mutate(); + } + + private float amplitude; + private final AnimatedFloat animatedAmplitude = new AnimatedFloat(this::invalidateDrawOver2, 0, 200, CubicBezierInterpolator.DEFAULT); + public void setAmplitude(double value) { + amplitude = (float) (Math.min(WaveDrawable.MAX_AMPLITUDE, value) / WaveDrawable.MAX_AMPLITUDE); + invalidate(); + } + + private final Path circlePath = new Path(); + private final Path boundsPath = new Path(); + + @Override + public void drawOver2(Canvas canvas, RectF bounds, float alpha) { + if (alpha <= 0) { + return; + } + + final float cancel = cancel2T.set(cancelling); + final float lock = lock2T.set(locked); + final float amplitude = animatedAmplitude.set(this.amplitude); + + final float radius = (dp(41) + dp(30) * amplitude * (1f - slideProgress)) * (1f - cancel) * alpha; + final float cx = lerp(bounds.right - dp(20) - (getWidth() * .35f) * slideProgress * (1f - lock), bounds.left + dp(20), cancel); + final float cy = bounds.bottom - dp(20); + + if (LiteMode.isEnabled(LiteMode.FLAGS_CHAT)) { + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(47) + dp(15) * BlobDrawable.FORM_SMALL_MAX; + + bigWaveDrawable.minRadius = dp(50); + bigWaveDrawable.maxRadius = dp(50) + dp(12) * BlobDrawable.FORM_BIG_MAX; + + bigWaveDrawable.update(amplitude, 1.01f); + tinyWaveDrawable.update(amplitude, 1.02f); + + bigWaveDrawable.paint.setColor(Theme.multAlpha(roundPaint.getColor(), WaveDrawable.CIRCLE_ALPHA_2 * alpha)); + canvas.save(); + final float s1 = radius / bigWaveDrawable.minRadius; + canvas.scale(s1, s1, cx, cy); + bigWaveDrawable.draw(cx, cy, canvas, bigWaveDrawable.paint); + canvas.restore(); + + tinyWaveDrawable.paint.setColor(Theme.multAlpha(roundPaint.getColor(), WaveDrawable.CIRCLE_ALPHA_1 * alpha)); + canvas.save(); + final float s2 = radius / tinyWaveDrawable.minRadius; + canvas.scale(s2, s2, cx, cy); + tinyWaveDrawable.draw(cx, cy, canvas, tinyWaveDrawable.paint); + canvas.restore(); + } + + final float R = Math.min(radius, dp(41 + 14)); + roundPaint.setAlpha((int) (0xFF * alpha)); + canvas.drawCircle(cx, cy, R, roundPaint); + + canvas.save(); + circlePath.rewind(); + circlePath.addCircle(cx, cy, R, Path.Direction.CW); + canvas.clipPath(circlePath); + roundDrawable.setBounds( + (int) (cx - roundDrawable.getIntrinsicWidth() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cy - roundDrawable.getIntrinsicHeight() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cx + roundDrawable.getIntrinsicWidth() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cy + roundDrawable.getIntrinsicHeight() / 2f * (1f - cancel) * (stopping ? alpha : 1f)) + ); + roundDrawable.setAlpha((int) (0xFF * (1f - cancel) * (stopping ? alpha : 1f))); + roundDrawable.draw(canvas); + if (lock > 0) { + final float sz = dpf2(19.33f) / 2f * lock * alpha; + AndroidUtilities.rectTmp.set(cx - sz, cy - sz, cx + sz, cy + sz); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5.33f), dp(5.33f), whitePaint); + } + canvas.restore(); + + drawLock(canvas, bounds, alpha); + + if (cancelling && (roundButton.getVisibility() == View.INVISIBLE || periodButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0)) { + canvas.saveLayerAlpha(bounds, (int) (0xFF * (1f - keyboardT)), Canvas.ALL_SAVE_FLAG); + + boundsPath.rewind(); + boundsPath.addRoundRect(bounds, dp(21), dp(21), Path.Direction.CW); + canvas.clipPath(boundsPath); + + if (roundButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0) { + canvas.save(); + canvas.translate(roundButton.getX() + dp(180) * (1f - cancel), roundButton.getY()); + roundButton.draw(canvas); + canvas.restore(); + } + + if (periodButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0) { + canvas.save(); + canvas.translate(periodButton.getX() + dp(180) * (1f - cancel), periodButton.getY()); + periodButton.draw(canvas); + canvas.restore(); + } + + canvas.restore(); + } + + checkFlipButton(); + flipButton.setAlpha((int) (0xFF * alpha * (1f - cancel))); + final int timelineHeight = getTimelineHeight(); + flipButton.setBounds((int) bounds.left + dp(4), (int) (bounds.top - timelineHeight - dp(36 + 12)), (int) (bounds.left + dp(4 + 36)), (int) (bounds.top - timelineHeight - dp(12))); + flipButton.draw(canvas); + } + + public int getTimelineHeight() { + return 0; + } + + private final Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockHandlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { lockHandlePaint.setStyle(Paint.Style.STROKE); } + private final AnimatedFloat lockCancelledT = new AnimatedFloat(this::invalidateDrawOver2, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private final RectF lockBounds = new RectF(); + private final RectF cancelBounds = new RectF(); + private final RectF lockRect = new RectF(); + private final Path lockHandle = new Path(); + + private void drawLock(Canvas canvas, RectF bounds, float alpha) { + final float cancel = cancel2T.get(); + final float lock = lock2T.get(); + + final float scale = lerp(lockCancelledT.set(slideProgress < .4f), 0f, lock) * (1f - cancel) * alpha; + + final float w = scale * dp(36), h = scale * lerp(dp(50), dp(36), lock); + final float cx = bounds.right - dp(20); + final float cy = lerp( + bounds.bottom - dp(20 + 60) - h / 2f - dp(120) * lockProgress * (1f - lock), + bounds.bottom - dp(20), + 1f - scale + ); + lockBounds.set(cx - w / 2f, cy - h / 2f, cx + w / 2f, cy + h / 2f); + + final float r = lerp(dp(18), dp(14), lock); + lockShadowPaint.setShadowLayer(dp(1), 0, dp(.66f), Theme.multAlpha(0x20000000, scale)); + lockShadowPaint.setColor(0); + canvas.drawRoundRect(lockBounds, r, r, lockShadowPaint); + + Paint backgroundBlurPaint = backgroundBlur.getPaint(scale); + if (backgroundBlurPaint == null) { + lockBackgroundPaint.setColor(0x40000000); + lockBackgroundPaint.setAlpha((int) (0x40 * scale)); + canvas.drawRoundRect(lockBounds, r, r, lockBackgroundPaint); + } else { + canvas.drawRoundRect(lockBounds, r, r, backgroundBlurPaint); + backgroundPaint.setAlpha((int) (0x33 * scale)); + canvas.drawRoundRect(lockBounds, r, r, backgroundPaint); + } + + canvas.save(); + canvas.scale(scale, scale, cx, cy); + + lockPaint.setColor(Theme.multAlpha(0xFFFFFFFF, scale)); + lockHandlePaint.setColor(Theme.multAlpha(0xFFFFFFFF, scale * (1f - lock))); + + final float lockRectW = lerp(dp(15.33f), dp(13), lock); + final float lockRectH = lerp(dp(12.66f), dp(13), lock); + final float lockRectY = cy + dp(4) * (1f - lock); + canvas.rotate(12 * lockProgress * (1f - lock), cx, lockRectY); + + lockRect.set(cx - lockRectW / 2f, lockRectY - lockRectH / 2f, cx + lockRectW / 2f, lockRectY + lockRectH / 2f); + canvas.drawRoundRect(lockRect, dp(3.66f), dp(3.66f), lockPaint); + + if (lock < 1) { + canvas.save(); + canvas.rotate(12 * lockProgress * (1f - lock), cx, lockRectY - lockRectH / 2f); + canvas.translate(0, lockRectH / 2f * lock); + canvas.scale(1f - lock, 1f - lock, cx, lockRectY - lockRectH / 2f); + + lockHandle.rewind(); + final float radius = dp(4.33f); + final float y = lockRectY - lockRectH / 2f - dp(3.66f); + lockHandle.moveTo(cx + radius, y + dp(3.66f)); + lockHandle.lineTo(cx + radius, y); + AndroidUtilities.rectTmp.set(cx - radius, y - radius, cx + radius, y + radius); + lockHandle.arcTo(AndroidUtilities.rectTmp, 0, -180, false); + lockHandle.lineTo(cx - radius, y + dp(3.66f) * lerp(lerp(.4f, 0, lockProgress), 1f, lock)); + + lockHandlePaint.setStrokeWidth(dp(2)); + canvas.drawPath(lockHandle, lockHandlePaint); + canvas.restore(); + } + + canvas.restore(); + } + + private Text slideToCancelText; + private Path slideToCancelArrowPath; + private Paint slideToCancelArrowPaint; + + private Text cancelText; + + @Override + public int additionalRightMargin() { + return 36; } public void setPeriod(int period) { @@ -131,17 +515,20 @@ public void setOnPremiumHint(Utilities.Callback listener) { protected void beforeUpdateShownKeyboard(boolean show) { if (!show) { periodButton.setVisibility(periodVisible ? View.VISIBLE : View.GONE); + roundButton.setVisibility(View.VISIBLE); } } @Override protected void onUpdateShowKeyboard(float keyboardT) { periodButton.setAlpha(1f - keyboardT); + roundButton.setAlpha(1f - keyboardT); } @Override protected void afterUpdateShownKeyboard(boolean show) { periodButton.setVisibility(!show && periodVisible ? View.VISIBLE : View.GONE); + roundButton.setVisibility(!show ? View.VISIBLE : View.GONE); if (show) { periodButton.setVisibility(View.GONE); } @@ -156,4 +543,327 @@ protected int getCaptionPremiumLimit() { protected int getCaptionDefaultLimit() { return MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault; } + + private RoundVideoRecorder currentRecorder; + private float fromX, fromY; + private final AnimatedFloat cancelT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat cancel2T = new AnimatedFloat(this::invalidateDrawOver2, 0, 420, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat lockT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat lock2T = new AnimatedFloat(this::invalidateDrawOver2, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean cancelling, stopping, locked; + private boolean recordTouch; + private boolean recording; + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (recording && currentRecorder != null && currentRecorder.cameraView != null && flipButton != null) { + AndroidUtilities.rectTmp.set(flipButton.getBounds()); + AndroidUtilities.rectTmp.inset(-dp(12), -dp(12)); + for (int i = 0; i < ev.getPointerCount(); ++i) { + if (AndroidUtilities.rectTmp.contains(ev.getX(i), ev.getY(i))) { + if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { + currentRecorder.cameraView.switchCamera(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && flipButton instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) flipButton).start(); + } + } + if (!recordTouch) { + return true; + } + break; + } + } + } + AndroidUtilities.rectTmp.set(roundButton.getX(), roundButton.getY(), roundButton.getX() + roundButton.getMeasuredWidth(), roundButton.getY() + roundButton.getMeasuredHeight()); + if (recordTouch || !hasRoundVideo && !keyboardShown && AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY())) { + return roundButtonTouchEvent(ev); + } + if (recording && locked && cancelBounds.contains(ev.getX(), ev.getY())) { + releaseRecord(false, true); + recordTouch = false; + return true; + } + if (recording && (lockBounds.contains(ev.getX(), ev.getY()) || getBounds().contains(ev.getX(), ev.getY()))) { + releaseRecord(false, false); + recordTouch = false; + return true; + } + return super.dispatchTouchEvent(ev); + } + + private final Runnable doneCancel = () -> { + setCollapsed(false, Integer.MIN_VALUE); + roundButton.setVisibility(VISIBLE); + periodButton.setVisibility(VISIBLE); + }; + + private boolean roundButtonTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (stopRecording()) { + return true; + } + recordTouch = true; + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + if (!canRecord()) { + return true; + } + AndroidUtilities.cancelRunOnUIThread(doneCancel); + fromX = ev.getX(); + fromY = ev.getY(); + amplitude = 0; + slideProgress = 0f; + cancelT.set(0, true); + cancel2T.set(0, true); + cancelling = false; + stopping = false; + locked = false; + recordPaint.reset(); + recording = true; + startTime = System.currentTimeMillis(); + setCollapsed(true, Integer.MAX_VALUE); + invalidateDrawOver2(); + + putRecorder(currentRecorder = new RoundVideoRecorder(getContext()) { + @Override + protected void receivedAmplitude(double amplitude) { + setAmplitude(amplitude); + } + + @Override + public void stop() { + super.stop(); + if (recording) { + releaseRecord(true, false); + } + } + }); + return true; + } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { + if (!cancelling) { + slideProgress = Utilities.clamp((fromX - ev.getX()) / (getWidth() * .35f), 1, 0); + lockProgress = Utilities.clamp((fromY - ev.getY()) / (getWidth() * .3f), 1, 0); + if (!locked && !cancelling && slideProgress >= 1) { + cancelling = true; + recording = false; + roundButton.setVisibility(INVISIBLE); + periodButton.setVisibility(INVISIBLE); + recordPaint.playDeleteAnimation(); + + if (currentRecorder != null) { + currentRecorder.cancel(); + } + + AndroidUtilities.runOnUIThread(doneCancel, 800); + } else if (!locked && !cancelling && lockProgress >= 1 && slideProgress < .4f) { + locked = true; + + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) {} + } + invalidate(); + invalidateDrawOver2(); + } + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + if (!cancelling && !locked) { + releaseRecord(false, false); + } + recordTouch = false; + } + return recordTouch; + } + + private void releaseRecord(boolean byRecorder, boolean cancel) { + AndroidUtilities.cancelRunOnUIThread(doneCancel); + + stopping = true; + recording = false; + setCollapsed(false, (int) (getBounds().right - dp(20) - (getWidth() * .35f) * slideProgress)); + + if (currentRecorder != null) { + if (!byRecorder) { + if (cancel) { + currentRecorder.cancel(); + } else { + currentRecorder.stop(); + } + } + currentRecorder = null; + } + invalidateDrawOver2(); + } + + public boolean isRecording() { + return recording; + } + + public boolean stopRecording() { + if (recording) { + recordTouch = false; + releaseRecord(false, false); + return true; + } + return false; + } + + public boolean canRecord() { + return false; + } + + public void putRecorder(RoundVideoRecorder recorder) { + // Override + } + + public void showRemoveRoundAlert() { + if (!hasRoundVideo) return; + AlertDialog d = new AlertDialog.Builder(getContext(), resourcesProvider) + .setTitle(LocaleController.getString(R.string.StoryRemoveRoundTitle)) + .setMessage(LocaleController.getString(R.string.StoryRemoveRoundMessage)) + .setPositiveButton(LocaleController.getString(R.string.Remove), (di, w) -> removeRound()) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + TextView button = (TextView) d.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold, resourcesProvider)); + } + } + + public void removeRound() { + // Override + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + recordPaint.attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + recordPaint.detach(); + } + + private class RecordDot extends Drawable { + + private final Paint redDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float alpha; + private float alpha2 = 1f; + private long lastUpdateTime; + private boolean isIncr; + boolean attachedToWindow; + boolean playing; + RLottieDrawable drawable; + private boolean enterAnimation; + + private final View parent; + + public void attach() { + attachedToWindow = true; + if (playing) { + drawable.start(); + } + drawable.setMasterParent(parent); + } + + public void detach() { + attachedToWindow = false; + drawable.stop(); + drawable.setMasterParent(null); + } + + public RecordDot(View parent) { + this.parent = parent; + int resId = R.raw.chat_audio_record_delete_3; + drawable = new RLottieDrawable(resId, "" + resId, AndroidUtilities.dp(28), AndroidUtilities.dp(28), false, null); + drawable.setCurrentParentView(parent); + drawable.setInvalidateOnProgressSet(true); + updateColors(); + } + + public void updateColors() { + int dotColor = 0xffDB4646; + redDotPaint.setColor(dotColor); + drawable.beginApplyLayerColors(); + drawable.setLayerColor("Cup Red.**", dotColor); + drawable.setLayerColor("Box.**", dotColor); + drawable.commitApplyLayerColors(); + } + + public void resetAlpha() { + alpha = 1.0f; + lastUpdateTime = System.currentTimeMillis(); + isIncr = false; + playing = false; + drawable.stop(); + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + if (playing) { + drawable.setAlpha((int) (255 * alpha * alpha2)); + } + redDotPaint.setAlpha((int) (255 * alpha * alpha2)); + + long dt = (System.currentTimeMillis() - lastUpdateTime); + if (enterAnimation) { + alpha = 1; + } else { + if (!isIncr && !playing) { + alpha -= dt / 600.0f; + if (alpha <= 0) { + alpha = 0; + isIncr = true; + } + } else { + alpha += dt / 600.0f; + if (alpha >= 1) { + alpha = 1; + isIncr = false; + } + } + } + lastUpdateTime = System.currentTimeMillis(); + drawable.setBounds(getBounds()); + if (playing) { + drawable.draw(canvas); + } + if (!playing || !drawable.hasBitmap()) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), dp(5), redDotPaint); + } + invalidate(); + } + + @Override + public void setAlpha(int alpha) { + alpha2 = (float) alpha / 0xFF; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + public void playDeleteAnimation() { + playing = true; + drawable.setProgress(0); + if (attachedToWindow) { + drawable.start(); + } + } + + public void reset() { + playing = false; + drawable.stop(); + drawable.setProgress(0); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java index 15fb236dc0..1b689d2b78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java @@ -39,6 +39,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; +import org.telegram.messenger.VideoEncodingService; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedFloat; @@ -343,6 +344,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (finalSize > 0) { onDone.run(); + VideoEncodingService.stop(); stop(false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index abe8e175c4..876204da07 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java @@ -496,6 +496,16 @@ public static class StoryDraft { public float audioLeft, audioRight = 1; public float audioVolume = 1; + public String roundPath; + public String roundThumb; + public long roundDuration; + public long roundOffset; + public float roundLeft; + public float roundRight; + public float roundVolume = 1; + + public float videoVolume = 1f; + public TLRPC.InputPeer peer; public StoryDraft(@NonNull StoryEntry entry) { @@ -545,6 +555,16 @@ public StoryDraft(@NonNull StoryEntry entry) { this.audioRight = entry.audioRight; this.audioVolume = entry.audioVolume; + this.roundPath = entry.round == null ? "" : entry.round.getAbsolutePath(); + this.roundThumb = entry.roundThumb; + this.roundDuration = entry.roundDuration; + this.roundOffset = entry.roundOffset; + this.roundLeft = entry.roundLeft; + this.roundRight = entry.roundRight; + this.roundVolume = entry.roundVolume; + + this.videoVolume = entry.videoVolume; + this.peer = entry.peer; } @@ -632,6 +652,19 @@ public StoryEntry toEntry() { entry.audioLeft = audioLeft; entry.audioRight = audioRight; entry.audioVolume = audioVolume; + + if (roundPath != null) { + entry.round = new File(roundPath); + } + entry.roundThumb = roundThumb; + entry.roundDuration = roundDuration; + entry.roundOffset = roundOffset; + entry.roundLeft = roundLeft; + entry.roundRight = roundRight; + entry.roundVolume = roundVolume; + + entry.videoVolume = videoVolume; + entry.peer = peer; return entry; } @@ -741,11 +774,26 @@ public void toStream(AbstractSerializedData stream) { stream.writeFloat(audioRight); stream.writeFloat(audioVolume); } + if (peer != null) { peer.serializeToStream(stream); } else { new TLRPC.TL_inputPeerSelf().serializeToStream(stream); } + + if (roundPath == null) { + stream.writeInt32(TLRPC.TL_null.constructor); + } else { + stream.writeInt32(TLRPC.TL_documentAttributeVideo.constructor); + stream.writeString(roundPath); + stream.writeInt64(roundDuration); + stream.writeInt64(roundOffset); + stream.writeFloat(roundLeft); + stream.writeFloat(roundRight); + stream.writeFloat(roundVolume); + } + + stream.writeFloat(videoVolume); } public int getObjectSize() { @@ -923,6 +971,20 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { if (stream.remaining() > 0) { peer = TLRPC.InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); } + if (stream.remaining() > 0) { + magic = stream.readInt32(exception); + if (magic == TLRPC.TL_documentAttributeVideo.constructor) { + roundPath = stream.readString(exception); + roundDuration = stream.readInt64(exception); + roundOffset = stream.readInt64(exception); + roundLeft = stream.readFloat(exception); + roundRight = stream.readFloat(exception); + roundVolume = stream.readFloat(exception); + } + } + if (stream.remaining() > 0) { + videoVolume = stream.readFloat(exception); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java index 848269d9e9..4ced1ab848 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java @@ -72,8 +72,8 @@ public void destroy(boolean async, Runnable beforeDestroyRunnable) { private boolean doNotSpanRotation; private float[] tempPoint = new float[4]; - private Matrix toScreen = new Matrix(); - private Matrix toGL = new Matrix(); + private final Matrix toScreen = new Matrix(); + private final Matrix toGL = new Matrix(); private boolean firstMeasure = true; private boolean atTop, atBottom; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java index 6d64da61b8..12582c56c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java @@ -121,6 +121,7 @@ import org.telegram.ui.Components.Paint.Views.PaintWeightChooserView; import org.telegram.ui.Components.Paint.Views.PhotoView; import org.telegram.ui.Components.Paint.Views.ReactionWidgetEntityView; +import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.Paint.Views.StickerView; import org.telegram.ui.Components.Paint.Views.TextPaintView; import org.telegram.ui.Components.Point; @@ -257,6 +258,7 @@ public void set(float val) { private AnimatorSet keyboardAnimator; public final KeyboardNotifier keyboardNotifier; + private StoryEntry initialEntry; private ArrayList initialEntities; private int w, h; @@ -272,7 +274,7 @@ public void set(float val) { private BlurringShader.BlurManager blurManager; @SuppressLint("NotifyDataSetChanged") - public PaintView(Context context, boolean fileFromGallery, File file, boolean isVideo, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap blurBitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, BlurringShader.BlurManager blurManager, Theme.ResourcesProvider resourcesProvider) { + public PaintView(Context context, boolean fileFromGallery, File file, boolean isVideo, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap blurBitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, StoryEntry entry, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, BlurringShader.BlurManager blurManager, Theme.ResourcesProvider resourcesProvider) { super(context, activity, true); setDelegate(this); this.fileFromGallery = fileFromGallery; @@ -571,6 +573,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }; // addView(entitiesView); + this.initialEntry = entry; this.initialEntities = entities; if (w > 0 && h > 0) { setupEntities(); @@ -1252,7 +1255,7 @@ public void updateZoom(boolean zoomedOut) { } } - private boolean selectEntity(EntityView entityView) { + public boolean selectEntity(EntityView entityView) { return selectEntity(entityView, true); } @@ -1328,6 +1331,8 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { AndroidUtilities.hideKeyboard(((TextPaintView) currentEntityView).getFocusedView()); hideEmojiPopup(false); } + } else if (currentEntityView instanceof RoundView) { + onDeselectRound((RoundView) currentEntityView); } } changed = true; @@ -1341,6 +1346,9 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { removeEntity(oldEntity); } } + if (oldEntity != currentEntityView && currentEntityView instanceof RoundView) { + onSelectRound((RoundView) currentEntityView); + } if (currentEntityView != null) { currentEntityView.select(selectionContainerView); @@ -2095,6 +2103,8 @@ public void init() { private void setupEntities() { if (initialEntities != null) { ArrayList entities = initialEntities; + StoryEntry entry = initialEntry; + initialEntry = null; initialEntities = null; for (int a = 0, N = entities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = entities.get(a); @@ -2156,6 +2166,16 @@ private void setupEntities() { entityView.changeStyle(false); } view = entityView; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + if (entry.round == null) { + continue; + } + RoundView roundView = createRound(entry.roundThumb, false); + onCreateRound(roundView); + if ((entity.subType & 2) != 0) { + roundView.mirror(false); + } + view = roundView; } else { continue; } @@ -2290,10 +2310,10 @@ public static boolean isVideoStickerDocument(TLRPC.Document document) { @Override public Bitmap getBitmap(ArrayList entities, Bitmap[] thumbBitmap) { - return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false); + return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false, null); } - public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean drawBlur) { + public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean drawBlur, StoryEntry entry) { Bitmap bitmap; if (drawPaint) { bitmap = renderView.getResultBitmap(false, drawBlur); @@ -2453,6 +2473,24 @@ public Bitmap getBitmap(ArrayList entities, int res mediaEntity.mediaArea.dark = reactionView.isDark(); mediaEntity.mediaArea.flipped = reactionView.isMirrored(); mediaEntity.mediaArea.coordinates = new TL_stories.TL_mediaAreaCoordinates(); + } else if (entity instanceof RoundView) { + skipDrawToBitmap = true; + RoundView roundView = (RoundView) entity; + Size size = roundView.getBaseSize(); + mediaEntity.width = size.width; + mediaEntity.height = size.height; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_ROUND; + if (entry != null) { + mediaEntity.text = entry.round.getAbsolutePath(); + mediaEntity.roundOffset = entry.roundOffset; + mediaEntity.roundDuration = entry.roundDuration; + mediaEntity.roundLeft = (long) (entry.roundLeft * entry.roundDuration); + mediaEntity.roundRight = (long) (entry.roundRight * entry.roundDuration); + } + mediaEntity.subType = 4; + if (roundView.isMirrored()) { + mediaEntity.subType |= 2; + } } else { continue; } @@ -3374,7 +3412,11 @@ private void showMenuForEntity(final EntityView entityView) { deleteView.setTag(0); deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); deleteView.setOnClickListener(v -> { - removeEntity(entityView); + if (entityView instanceof RoundView) { + onTryDeleteRound(); + } else { + removeEntity(entityView); + } if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(true); @@ -3433,13 +3475,15 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (entityView instanceof StickerView || entityView instanceof PhotoView || entityView instanceof ReactionWidgetEntityView) { + if (entityView instanceof StickerView || entityView instanceof RoundView || entityView instanceof PhotoView || entityView instanceof ReactionWidgetEntityView) { TextView flipView = createActionLayoutButton(4, LocaleController.getString("Flip", R.string.Flip)); flipView.setOnClickListener(v -> { if (entityView instanceof StickerView) { ((StickerView) entityView).mirror(true); - } else if (entityView instanceof ReactionWidgetEntityView){ + } else if (entityView instanceof ReactionWidgetEntityView) { ((ReactionWidgetEntityView) entityView).mirror(true); + } else if (entityView instanceof RoundView) { + ((RoundView) entityView).mirror(true); } else { ((PhotoView) entityView).mirror(true); } @@ -3450,7 +3494,7 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (!(entityView instanceof PhotoView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { + if (!(entityView instanceof PhotoView) && !(entityView instanceof RoundView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { TextView duplicateView = new TextView(getContext()); duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); duplicateView.setLines(1); @@ -3878,6 +3922,63 @@ public PhotoView createPhoto(String path, boolean select) { return view; } + public void onCreateRound(RoundView roundView) { + + } + + public void onTryDeleteRound() { + + } + + public void onDeleteRound() { + + } + + public void onDeselectRound(RoundView roundView) { + + } + + public void onSelectRound(RoundView roundView) { + + } + + public void deleteRound() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child instanceof RoundView) { + if (currentEntityView == child) { + selectEntity(null); + } + child.animate().scaleX(0).scaleY(0) + .setDuration(280).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT) + .withEndAction(() -> removeEntity((RoundView) child)).start(); + } + } + } + + private boolean creatingNewRound; + public RoundView createRound(String thumbPath, boolean select) { + forceChanges = true; + creatingNewRound = true; + deleteRound(); + int w = entitiesView.getMeasuredWidth(), h = entitiesView.getMeasuredHeight(); + if (w <= 0) w = this.w; + if (h <= 0) h = this.h; + float side = (float) Math.floor(w * 0.43f); + Size size = new Size(side, side); + float x = w - size.width / 2f - dp(16); + float y = dp(72) + size.height / 2f; + RoundView view = new RoundView(getContext(), new Point(x, y), 0, 1f, size, thumbPath); + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + post(() -> selectEntity(view)); + } + creatingNewRound = false; + return view; + } + public PhotoView createPhoto(TLObject obj, boolean select) { forceChanges = true; Size size = basePhotoSize(obj); @@ -3981,6 +4082,10 @@ private void removeEntity(EntityView entityView) { weightChooserView.setShowPreview(true); colorSwatch.brushWeight = weightDefaultValueOverride.get(); setCurrentSwatch(colorSwatch, true); + + if (!creatingNewRound && entityView instanceof RoundView) { + onDeleteRound(); + } } private void registerRemovalUndo(final EntityView entityView) { @@ -4518,4 +4623,19 @@ protected void onDetachedFromWindow() { protected void onGalleryClick() { } + + public EntityView getSelectedEntity() { + return currentEntityView; + } + + public RoundView findRoundView() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child instanceof RoundView) { + return (RoundView) child; + } + } + return null; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java index 99d4bdb02f..509d073e2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java @@ -3,7 +3,6 @@ import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -73,7 +72,7 @@ protected void dispatchDraw(Canvas canvas) { } }; PeerStoriesView.PeerHeaderView headerView = new PeerStoriesView.PeerHeaderView(getContext(), null); - headerView.backupImageView.getAvatarDrawable().setInfo(me); + headerView.backupImageView.getAvatarDrawable().setInfo(currentAccount, me); headerView.backupImageView.setForUserOrChat(me, headerView.backupImageView.getAvatarDrawable()); CharSequence text = UserObject.getUserName(me); text = Emoji.replaceEmoji(text, headerView.titleView.getPaint().getFontMetricsInt(), false); @@ -144,7 +143,7 @@ public void updateCount() { public void updateCaption(CharSequence caption) { caption = AnimatedEmojiSpan.cloneSpans(new SpannableString(caption)); - storyCaptionView.captionTextview.setText(caption, false, false); + storyCaptionView.captionTextview.setText(caption, null, false, false); } private boolean shownTop = false, shownBottom = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java index 060bf8efcb..7000412b2f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java @@ -37,6 +37,7 @@ import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.PhotoFilterView; import org.telegram.ui.Components.VideoEditTextureView; import org.telegram.ui.Components.VideoPlayer; @@ -60,6 +61,10 @@ public class PreviewView extends FrameLayout { private PhotoFilterView photoFilterView; public Runnable invalidateBlur; + private RoundView roundView; + private VideoPlayer roundPlayer; + private int roundPlayerWidth, roundPlayerHeight; + private VideoPlayer audioPlayer; // private VideoTimelinePlayView videoTimelineView; @@ -110,6 +115,7 @@ public void set(StoryEntry entry, Runnable whenReady, long seekTo) { setupParts(null); gradientPaint.setShader(null); setupAudio((StoryEntry) null, false); + setupRound(null, null, false); return; } if (entry.isVideo) { @@ -128,6 +134,7 @@ public void set(StoryEntry entry, Runnable whenReady, long seekTo) { setupParts(entry); applyMatrix(); setupAudio(entry, false); + setupRound(entry, null, false); } public void setupAudio(StoryEntry entry, boolean animated) { @@ -180,7 +187,7 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { } }); audioPlayer.preparePlayer(Uri.fromFile(new File(entry.audioPath)), "other"); - audioPlayer.setVolume(entry.audioVolume); + checkVolumes(); if (videoPlayer != null && getDuration() > 0) { long startPos = (long) (entry.left * getDuration()); @@ -235,10 +242,20 @@ public void setupAudio(MessageObject messageObject, boolean animated) { private void seekTo(long position) { if (videoPlayer != null) { videoPlayer.seekTo(position, false); + } else if (roundPlayer != null) { + roundPlayer.seekTo(position, false); } else if (audioPlayer != null) { audioPlayer.seekTo(position, false); } updateAudioPlayer(true); + updateRoundPlayer(true); + } + + public void seek(long position) { + seekTo(position); + if (timelineView != null) { + timelineView.setProgress(0); + } } public void setVideoTimelineView(TimelineView timelineView) { @@ -261,6 +278,15 @@ public void onProgressChange(long progress, boolean fast) { } } + @Override + public void onVideoVolumeChange(float volume) { + if (entry == null) { + return; + } + entry.videoVolume = volume; + checkVolumes(); + } + @Override public void onVideoLeftChange(float left) { if (entry == null) { @@ -324,14 +350,71 @@ public void onAudioVolumeChange(float volume) { } entry.audioVolume = volume; entry.editedMedia = true; - if (audioPlayer != null) { - audioPlayer.setVolume(volume); + checkVolumes(); + } + + @Override + public void onRoundLeftChange(float left) { + if (entry == null) { + return; + } + entry.roundLeft = left; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundRightChange(float right) { + if (entry == null) { + return; + } + entry.roundRight = right; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundOffsetChange(long offset) { + if (entry == null) { + return; + } + entry.roundOffset = offset; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundRemove() { + setupRound(null, null, true); + PreviewView.this.onRoundRemove(); + } + + @Override + public void onRoundVolumeChange(float volume) { + if (entry == null) { + return; } + entry.roundVolume = volume; + entry.editedMedia = true; + checkVolumes(); + } + + @Override + public void onRoundSelectChange(boolean selected) { + PreviewView.this.onRoundSelectChange(selected); } }); } } + public void onRoundRemove() { + // Override + } + + public void onRoundSelectChange(boolean selected) { + // Override + } + private void setupImage(StoryEntry entry) { if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); @@ -483,7 +566,7 @@ private void setupVideoPlayer(StoryEntry entry, Runnable whenReady, long seekTo) }).start(); } if (timelineView != null) { - timelineView.setVideo(null, 1); + timelineView.setVideo(null, 1, 0); } AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (whenReady != null) { @@ -539,10 +622,6 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre if (textureView != null) { textureView.setVideoSize(videoWidth, videoHeight); } -// if (whenReadyFinal[0] != null && entry != null && entry.width > 0 && entry.height > 0) { -// post(whenReadyFinal[0]); -// whenReadyFinal[0] = null; -// } } @Override @@ -612,10 +691,10 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { if (seekTo > 0) { videoPlayer.seekTo(seekTo); } - videoPlayer.setMute(entry.muted); + checkVolumes(); updateAudioPlayer(true); - timelineView.setVideo(entry.getOriginalFile().getAbsolutePath(), getDuration()); + timelineView.setVideo(entry.getOriginalFile().getAbsolutePath(), getDuration(), entry.videoVolume); timelineView.setVideoLeft(entry.left); timelineView.setVideoRight(entry.right); if (timelineView != null && seekTo > 0) { @@ -624,20 +703,103 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { } } + public void setupRound(StoryEntry entry, RoundView roundView, boolean animated) { + if (entry == null || entry.round == null) { + if (roundPlayer != null) { + roundPlayer.pause(); + roundPlayer.releasePlayer(true); + roundPlayer = null; + } + if (timelineView != null) { + timelineView.setRoundNull(animated); + } + this.roundView = null; + AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); + } else { + if (roundPlayer != null) { + roundPlayer.releasePlayer(true); + roundPlayer = null; + } + + roundPlayer = new VideoPlayer(); + roundPlayer.allowMultipleInstances = true; + roundPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + @Override + public void onStateChanged(boolean playWhenReady, int playbackState) { + if (roundPlayer == null) { + return; + } + if (roundPlayer != null && roundPlayer.isPlaying()) { + AndroidUtilities.runOnUIThread(updateRoundProgressRunnable); + } else { + AndroidUtilities.cancelRunOnUIThread(updateRoundProgressRunnable); + } + } + + @Override + public void onError(VideoPlayer player, Exception e) { + + } + + @Override + public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + roundPlayerWidth = width; + roundPlayerHeight = height; + if (PreviewView.this.roundView != null) { + PreviewView.this.roundView.resizeTextureView(width, height); + } + } + + @Override + public void onRenderedFirstFrame() { + + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} + + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + }); + + Uri uri = Uri.fromFile(entry.round); + roundPlayer.preparePlayer(uri, "other"); + checkVolumes(); + attachRoundView(roundView); + timelineView.setRound(entry.round.getAbsolutePath(), entry.roundDuration, entry.roundOffset, entry.roundLeft, entry.roundRight, entry.roundVolume, animated); + updateRoundPlayer(true); + } + } + + public void attachRoundView(RoundView roundView) { + this.roundView = roundView; + if (roundView != null && roundPlayer != null) { + roundPlayer.setTextureView(roundView.textureView); + } + } + public long release() { if (audioPlayer != null) { audioPlayer.pause(); audioPlayer.releasePlayer(true); audioPlayer = null; } + long t = 0; + if (roundPlayer != null) { + t = roundPlayer.getCurrentPosition(); + roundPlayer.pause(); + roundPlayer.releasePlayer(true); + roundPlayer = null; + } if (videoPlayer != null) { - long t = videoPlayer.getCurrentPosition(); + t = videoPlayer.getCurrentPosition(); videoPlayer.pause(); videoPlayer.releasePlayer(true); videoPlayer = null; - return t; } - return 0; + return t; } public void setupParts(StoryEntry entry) { @@ -716,8 +878,10 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi seekedLastTime = System.currentTimeMillis(); videoPlayer.seekTo(pos = (long) (entry.left * getDuration())); updateAudioPlayer(true); + updateRoundPlayer(true); } else { updateAudioPlayer(pos < lastPos); + updateRoundPlayer(pos < lastPos); } timelineView.setProgress(videoPlayer.getCurrentPosition()); } else { @@ -731,7 +895,7 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi }; private final Runnable updateAudioProgressRunnable = () -> { - if (audioPlayer == null || videoPlayer != null || timelineView == null) { + if (audioPlayer == null || videoPlayer != null || roundPlayer != null || timelineView == null) { return; } @@ -748,12 +912,31 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi } }; + private final Runnable updateRoundProgressRunnable = () -> { + if (roundPlayer == null || videoPlayer != null || timelineView == null) { + return; + } + + long pos = roundPlayer.getCurrentPosition(); + if (entry != null && (pos < entry.roundLeft * entry.roundDuration || pos > entry.roundRight * entry.roundDuration) && System.currentTimeMillis() - seekedLastTime > MIN_DURATION / 2) { + seekedLastTime = System.currentTimeMillis(); + roundPlayer.seekTo(pos = (long) (entry.roundLeft * entry.roundDuration)); + updateAudioPlayer(true); + } + timelineView.setProgress(pos); + + if (roundPlayer.isPlaying()) { + AndroidUtilities.cancelRunOnUIThread(this.updateRoundProgressRunnable); + AndroidUtilities.runOnUIThread(this.updateRoundProgressRunnable, (long) (1000L / AndroidUtilities.screenRefreshRate)); + } + }; + private void updateAudioPlayer(boolean updateSeek) { if (audioPlayer == null || entry == null) { return; } - if (videoPlayer == null) { + if (videoPlayer == null && roundPlayer == null) { audioPlayer.setPlayWhenReady(pauseLinks.isEmpty()); audioPlayer.setLooping(true); @@ -768,9 +951,11 @@ private void updateAudioPlayer(boolean updateSeek) { return; } - final long pos = videoPlayer.getCurrentPosition(); + VideoPlayer player = videoPlayer != null ? videoPlayer : roundPlayer; + + final long pos = player.getCurrentPosition(); final long duration = (long) ((entry.audioRight - entry.audioLeft) * entry.audioDuration); - boolean shouldPlaying = videoPlayer.isPlaying() && pos >= entry.audioOffset && pos <= entry.audioOffset + duration; + boolean shouldPlaying = player.isPlaying() && pos >= entry.audioOffset && pos <= entry.audioOffset + duration; long audioPos = pos - entry.audioOffset + (long) (entry.audioLeft * entry.audioDuration); if (audioPlayer.isPlaying() != shouldPlaying) { audioPlayer.setPlayWhenReady(shouldPlaying); @@ -780,16 +965,65 @@ private void updateAudioPlayer(boolean updateSeek) { } } + private void updateRoundPlayer(boolean updateSeek) { + if (roundPlayer == null || entry == null) { + return; + } + + if (videoPlayer == null) { + roundPlayer.setPlayWhenReady(pauseLinks.isEmpty()); + roundPlayer.setLooping(true); + if (roundView != null) { + roundView.setShown(true, false); + } + + long pos = roundPlayer.getCurrentPosition(); + if (updateSeek && roundPlayer.getDuration() != C.TIME_UNSET) { + final float progress = pos / (float) roundPlayer.getDuration(); + if ((progress < entry.roundLeft || progress > entry.roundRight) && System.currentTimeMillis() - seekedLastTime > MIN_DURATION / 2) { + seekedLastTime = System.currentTimeMillis(); + roundPlayer.seekTo(pos = -entry.roundOffset); + } + } + return; + } + + final long pos = videoPlayer.getCurrentPosition(); + final long duration = (long) ((entry.roundRight - entry.roundLeft) * entry.roundDuration); + boolean shouldPlayingInSeek = pos >= entry.roundOffset && pos <= entry.roundOffset + duration; + boolean shouldPlaying = videoPlayer.isPlaying() && shouldPlayingInSeek; + long roundPos = pos - entry.roundOffset + (long) (entry.roundLeft * entry.roundDuration); + if (roundView != null) { + roundView.setShown(shouldPlayingInSeek, true); + } + if (roundPlayer.isPlaying() != shouldPlaying) { + roundPlayer.setPlayWhenReady(shouldPlaying); + roundPlayer.seekTo(roundPos); + } else if (updateSeek && Math.abs(roundPlayer.getCurrentPosition() - roundPos) > 120) { + roundPlayer.seekTo(roundPos); + } + } + private Runnable onErrorListener; public void whenError(Runnable listener) { onErrorListener = listener; } + public boolean isMuted; public void mute(boolean value) { - if (videoPlayer == null) { - return; + isMuted = value; + checkVolumes(); + } + public void checkVolumes() { + if (videoPlayer != null) { + videoPlayer.setVolume(isMuted || (entry != null && entry.muted) ? 0 : (entry != null ? entry.videoVolume : 1f)); + } + if (roundPlayer != null) { + roundPlayer.setVolume(isMuted ? 0 : (entry != null ? entry.roundVolume : 1f)); + } + if (audioPlayer != null) { + audioPlayer.setVolume(isMuted ? 0 : (entry != null ? entry.audioVolume : 1f)); } - videoPlayer.setMute(value); } private final Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); @@ -1234,6 +1468,7 @@ public void updatePauseReason(int reasonId, boolean pause) { videoPlayer.setPlayWhenReady(pauseLinks.isEmpty()); } updateAudioPlayer(true); + updateRoundPlayer(true); } // ignores actual player and other reasons to pause a video diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java index 7538878026..6081706dd7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java @@ -211,6 +211,15 @@ public void setInvert(float invert) { unlockDrawable.setColorFilter(new PorterDuffColorFilter(ColorUtils.blendARGB(0xffffffff, 0xff000000, invert), PorterDuff.Mode.MULTIPLY)); } + public float amplitude; + public final AnimatedFloat animatedAmplitude = new AnimatedFloat(this, 0, 200, CubicBezierInterpolator.DEFAULT); + public void setAmplitude(float amplitude, boolean animated) { + this.amplitude = amplitude; + if (!animated) { + this.animatedAmplitude.set(amplitude, true); + } + } + private float cx, cy; private float leftCx, rightCx; @@ -340,7 +349,7 @@ protected void onDraw(Canvas canvas) { } canvas.save(); - scale = lerp(recordButton.getScale(startModeIsVideo ? 0 : .2f), 1, recordingT); + scale = lerp(recordButton.getScale(startModeIsVideo ? 0 : .2f), 1 + .2f * animatedAmplitude.set(amplitude), recordingT); canvas.scale(scale, scale, cx, cy); mainPaint.setColor(ColorUtils.blendARGB(WHITE, RED, isVideo)); float acx = lerp(cx, recordCx.set(cx + dp(4) * touchCenterT16), touchIsCenterT); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java new file mode 100644 index 0000000000..5269263266 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java @@ -0,0 +1,323 @@ +package org.telegram.ui.Stories.recorder; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ViewAnimator; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.camera.CameraController; +import org.telegram.messenger.camera.CameraView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Views.RoundView; + +import java.io.File; + +public class RoundVideoRecorder extends FrameLayout { + + public final CameraView cameraView; + public final File file; + + private long recordingStarted = -1; + private long recordingStopped = -1; + public final long MAX_DURATION = 59_500L; + + private final Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Runnable stopRunnable = this::stop; + + public RoundVideoRecorder(Context context) { + super(context); + + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setStrokeCap(Paint.Cap.ROUND); + progressPaint.setStrokeJoin(Paint.Join.ROUND); + + file = StoryEntry.makeCacheFile(UserConfig.selectedAccount, true); + + cameraView = new CameraView(context, true, false) { + private final Path circlePath = new Path(); + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + circlePath.rewind(); + circlePath.addCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth() / 2f, getHeight() / 2f), Path.Direction.CW); + canvas.clipPath(circlePath); + super.dispatchDraw(canvas); + canvas.restore(); + } + + @Override + protected boolean square() { + return true; + } + + @Override + protected void receivedAmplitude(double amplitude) { + RoundVideoRecorder.this.receivedAmplitude(amplitude); + } + }; + cameraView.setScaleX(0f); + cameraView.setScaleY(0f); + addView(cameraView); + cameraView.setDelegate(() -> { + if (recordingStarted > 0) return; + CameraController.getInstance().recordVideo(cameraView.getCameraSession(), file, false, (thumbPath, duration) -> { + recordingStopped = System.currentTimeMillis(); + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + if (cancelled) { + return; + } + if (duration > 1000) { + cameraView.destroy(true, null); + if (onDoneCallback != null) { + onDoneCallback.run(file, thumbPath, duration); + } + } else { + destroy(false); + } + }, () -> { + cameraView.animate().scaleX(1f).scaleY(1f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(280).start(); + recordingStarted = System.currentTimeMillis(); + invalidate(); + + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } catch (Exception ignore) {} + + AndroidUtilities.runOnUIThread(stopRunnable, MAX_DURATION); + }, cameraView, true); + }); + cameraView.initTexture(); + + setWillNotDraw(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = MeasureSpec.getSize(widthMeasureSpec); + final int height = MeasureSpec.getSize(heightMeasureSpec); + + final int side = (int) (Math.min(width, height) * .43f); + cameraView.measure( + MeasureSpec.makeMeasureSpec(side, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(side, MeasureSpec.EXACTLY) + ); + + setMeasuredDimension(width, height); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int x = (right - left) - cameraView.getMeasuredWidth() - dp(16); + final int y = dp(72); + cameraView.layout(x, y, x + cameraView.getMeasuredWidth(), y + cameraView.getMeasuredHeight()); + } + + protected void receivedAmplitude(double amplitude) { + + } + + private Utilities.Callback3 onDoneCallback; + public RoundVideoRecorder onDone(Utilities.Callback3 onDoneCallback) { + this.onDoneCallback = onDoneCallback; + return this; + } + + private Runnable onDestroyCallback; + public RoundVideoRecorder onDestroy(Runnable onDestroyCallback) { + this.onDestroyCallback = onDestroyCallback; + return this; + } + + private float alpha = 1f; + private RoundView roundView; + + @Override + protected void dispatchDraw(Canvas canvas) { + AndroidUtilities.rectTmp.set( + cameraView.getX() + cameraView.getWidth() / 2f * (1f - cameraView.getScaleX()), + cameraView.getY() + cameraView.getHeight() / 2f * (1f - cameraView.getScaleY()), + cameraView.getX() + cameraView.getWidth() - cameraView.getWidth() / 2f * (1f - cameraView.getScaleX()), + cameraView.getY() + cameraView.getHeight() - cameraView.getHeight() / 2f * (1f - cameraView.getScaleY()) + ); + + shadowPaint.setShadowLayer(dp(2), 0, dp(.66f), Theme.multAlpha(0x20000000, alpha)); + shadowPaint.setAlpha((int) (0xff * alpha)); + canvas.drawCircle(AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY(), Math.min(AndroidUtilities.rectTmp.width() / 2f, AndroidUtilities.rectTmp.height() / 2f) - 1, shadowPaint); + + super.dispatchDraw(canvas); + if (roundView != null && roundView.getWidth() > 0 && roundView.getHeight() > 0) { + canvas.save(); + canvas.translate(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top); + canvas.scale( + AndroidUtilities.rectTmp.width() / roundView.getWidth(), + AndroidUtilities.rectTmp.height() / roundView.getHeight() + ); + float wasAlpha = roundView.getAlpha(); + roundView.setDraw(true); + roundView.setAlpha(1f - alpha); + roundView.draw(canvas); + roundView.setAlpha(wasAlpha); + roundView.setDraw(false); + canvas.restore(); + } + + if (recordingStarted > 0) { + float t = Utilities.clamp(sinceRecording() / (float) MAX_DURATION, 1, 0); + + progressPaint.setStrokeWidth(dp(3.33f)); + progressPaint.setColor(Theme.multAlpha(0xbeffffff, alpha)); + progressPaint.setShadowLayer(dp(1), 0, dp(.33f), Theme.multAlpha(0x20000000, alpha)); + AndroidUtilities.rectTmp.inset(-dp(3.33f / 2f + 6), -dp(3.33f / 2f + 6)); + canvas.drawArc(AndroidUtilities.rectTmp, -90f, 360f * t, false, progressPaint); + + if (recordingStopped <= 0) + invalidate(); + } + } + + public long sinceRecording() { + return recordingStarted < 0 ? 0 : Math.min(MAX_DURATION, (recordingStopped < 0 ? System.currentTimeMillis() : recordingStopped) - recordingStarted); + } + + public String sinceRecordingText() { + long fullms = sinceRecording(); + int sec = (int) (fullms / 1000); + int ms = (int) ((fullms - sec * 1000) / 100); + int min = (int) (sec / 60); + sec = sec % 60; + return min + ":" + (sec < 10 ? "0" : "") + sec + "." + ms; + } + + private ValueAnimator cameraViewAnimator; + public void hideTo(RoundView roundView) { + if (roundView == null) { + destroy(false); + return; + } + + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + cameraView.destroy(true, null); + if (roundView != null) { + roundView.setDraw(false); + } + post(() -> { + if (roundView.getWidth() <= 0) { + cameraView.animate().scaleX(0).scaleY(1).withEndAction(() -> { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(this); + } + }).start(); + return; + } + + final float scale = (float) roundView.getWidth() / cameraView.getWidth(); + if (cameraViewAnimator != null) { + cameraViewAnimator.cancel(); + } + cameraViewAnimator = ValueAnimator.ofFloat(0, 1); + final float fromScale = cameraView.getScaleX(); + final float toX = (roundView.getX() + roundView.getWidth() / 2f) - (cameraView.getX() + cameraView.getWidth() / 2f); + final float toY = (roundView.getY() + roundView.getHeight() / 2f) - (cameraView.getY() + cameraView.getHeight() / 2f); + cameraViewAnimator.addUpdateListener(anm -> { + final float t = (float) anm.getAnimatedValue(); + cameraView.setScaleX(AndroidUtilities.lerp(fromScale, scale, t)); + cameraView.setScaleY(AndroidUtilities.lerp(fromScale, scale, t)); + cameraView.setTranslationX(toX * t); + cameraView.setTranslationY(toY * t); + cameraView.setAlpha(1f - t); + alpha = 1f - t; + invalidate(); + }); + cameraViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (roundView != null) { + roundView.setDraw(true); + } + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(RoundVideoRecorder.this); + } + } + }); + cameraViewAnimator.setDuration(320); + cameraViewAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + this.roundView = roundView; + cameraViewAnimator.start(); + }); + } + + public void stop() { + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + if (recordingStarted <= 0) { + destroy(true); + } else { + CameraController.getInstance().stopVideoRecording(cameraView.getCameraSessionRecording(), false, false); + } + } + + private boolean cancelled = false; + public void cancel() { + cancelled = true; + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + CameraController.getInstance().stopVideoRecording(cameraView.getCameraSessionRecording(), false, false); + destroy(false); + } + + private ValueAnimator destroyAnimator; + private float destroyT; + public void destroy(boolean instant) { + if (onDestroyCallback != null) { + onDestroyCallback.run(); + onDestroyCallback = null; + } + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + cameraView.destroy(true, null); + try { + file.delete(); + } catch (Exception ignore) {} + if (instant) { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(this); + } + } else { + if (destroyAnimator != null) { + destroyAnimator.cancel(); + } + destroyAnimator = ValueAnimator.ofFloat(destroyT, 1); + destroyAnimator.addUpdateListener(anm -> { + destroyT = (float) anm.getAnimatedValue(); + cameraView.setScaleX(1f - destroyT); + cameraView.setScaleY(1f - destroyT); + invalidate(); + }); + destroyAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(RoundVideoRecorder.this); + } + } + }); + destroyAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + destroyAnimator.setDuration(280); + destroyAnimator.start(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java index ef432b18e4..eaf72d6aa9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java @@ -34,6 +34,7 @@ public class SliderView extends View { public static final int TYPE_VOLUME = 0; public static final int TYPE_WARMTH = 1; public static final int TYPE_INTENSITY = 2; + public static final int TYPE_DIMMING = 3; private final int currentType; @@ -87,6 +88,8 @@ public SliderView(Context context, int type) { text2.setText(LocaleController.getString(R.string.FlashWarmth)); } else if (currentType == TYPE_INTENSITY) { text2.setText(LocaleController.getString(R.string.FlashIntensity)); + } else if (currentType == TYPE_DIMMING) { + text2.setText(LocaleController.getString(R.string.WallpaperDimming)); } } text.setText(""); @@ -103,6 +106,7 @@ public SliderView setMinMax(float min, float max) { public SliderView setValue(float volume) { this.value = (volume - this.minVolume) / (this.maxVolume - this.minVolume); + this.valueAnimated.set(this.value, true); updateText(volume); return this; } @@ -112,6 +116,12 @@ public SliderView setOnValueChange(Utilities.Callback listener) { return this; } + public void animateValueTo(float volume) { + this.valueIsAnimated = true; + this.value = (volume - this.minVolume) / (this.maxVolume - this.minVolume); + updateText(volume); + } + private final Path clipPath = new Path(); private final Path speaker1Path = new Path(); private final Path speaker2Path = new Path(); @@ -246,7 +256,11 @@ private void updateText(float value) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - r = dpf2(6.33f); + if (currentType == TYPE_DIMMING) { + r = dpf2(8); + } else { + r = dpf2(6.33f); + } textPaint.setTextSize(dp(16)); text.setTextSize(dp(15)); if (currentType == TYPE_VOLUME) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java index e46654cb12..a068756144 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java @@ -63,6 +63,13 @@ public class StoryEntry extends IStoryPart { public boolean editedMedia, editedCaption, editedPrivacy; public ArrayList editedMediaAreas; + public boolean isRepost; + public CharSequence repostPeerName; + public TLRPC.Peer repostPeer; + public int repostStoryId; + public String repostCaption; + public TLRPC.MessageMedia repostMedia; + public boolean isError; public TLRPC.TL_error error; @@ -82,6 +89,7 @@ public class StoryEntry extends IStoryPart { public boolean fileDeletable; public String thumbPath; public Bitmap thumbPathBitmap; + public float videoVolume = 1f; public boolean muted; public float left, right = 1; @@ -98,6 +106,13 @@ public class StoryEntry extends IStoryPart { public int partsMaxId = 1; public final ArrayList parts = new ArrayList<>(); + public File round; + public String roundThumb; + public long roundDuration; + public long roundOffset; + public float roundLeft, roundRight = 1; + public float roundVolume = 1; + public TLRPC.InputPeer peer; public static class Part extends IStoryPart { @@ -180,6 +195,9 @@ public boolean wouldBeVideo() { if (audioPath != null) { return true; } + if (round != null) { + return true; + } if (mediaEntities != null && !mediaEntities.isEmpty()) { for (int i = 0; i < mediaEntities.size(); ++i) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(i); @@ -485,7 +503,7 @@ public void destroy(boolean draft) { clearFilter(); if (file != null) { if (fileDeletable && (!isEdit || editedMedia)) { - file.delete(); + file.delete(); } file = null; } @@ -501,6 +519,16 @@ public void destroy(boolean draft) { } part.file = null; } + if (round != null && (!isEdit || editedMedia)) { + round.delete(); + round = null; + } + if (roundThumb != null && (!isEdit || editedMedia)) { + try { + new File(roundThumb).delete(); + } catch (Exception e) {} + roundThumb = null; + } } if (thumbPathBitmap != null) { thumbPathBitmap.recycle(); @@ -509,6 +537,59 @@ public void destroy(boolean draft) { cancelCheckStickers(); } + public static StoryEntry repostStoryItem(File file, TL_stories.StoryItem storyItem) { + StoryEntry entry = new StoryEntry(); + entry.isRepost = true; + entry.repostMedia = storyItem.media; + entry.repostPeer = MessagesController.getInstance(entry.currentAccount).getPeer(storyItem.dialogId); + entry.repostStoryId = storyItem.id; + entry.repostCaption = storyItem.caption; + entry.file = file; + entry.fileDeletable = false; + entry.width = 720; + entry.height = 1280; + if (storyItem.media instanceof TLRPC.TL_messageMediaPhoto) { + entry.isVideo = false; + if (file != null) { + entry.decodeBounds(file.getAbsolutePath()); + } + } else if (storyItem.media instanceof TLRPC.TL_messageMediaDocument) { + entry.isVideo = true; + if (storyItem.media.document != null && storyItem.media.document.attributes != null) { + for (int i = 0; i < storyItem.media.document.attributes.size(); ++i) { + TLRPC.DocumentAttribute attr = storyItem.media.document.attributes.get(i); + if (attr instanceof TLRPC.TL_documentAttributeVideo) { + entry.width = attr.w; + entry.height = attr.h; + entry.fileDuration = attr.duration; + break; + } + } + } + if (storyItem.media.document != null) { + if (storyItem.firstFramePath != null) { + entry.thumbPath = storyItem.firstFramePath; + } else if (storyItem.media.document.thumbs != null) { + for (int i = 0; i < storyItem.media.document.thumbs.size(); ++i) { + TLRPC.PhotoSize photoSize = storyItem.media.document.thumbs.get(i); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + entry.thumbPathBitmap = ImageLoader.getStrippedPhotoBitmap(photoSize.bytes, null); + continue; + } + File path = FileLoader.getInstance(entry.currentAccount).getPathToAttach(photoSize, true); + if (path != null && path.exists()) { + entry.thumbPath = path.getAbsolutePath(); + continue; + } + } + } + } + } + entry.setupMatrix(); + entry.checkStickers(storyItem); + return entry; + } + public static StoryEntry fromStoryItem(File file, TL_stories.StoryItem storyItem) { StoryEntry entry = new StoryEntry(); entry.isEdit = true; @@ -809,7 +890,9 @@ public void getVideoEditedInfo(@NonNull Utilities.Callback when info.originalPath = videoPath; } info.isPhoto = true; - if (audioPath != null) { + if (round != null) { + info.estimatedDuration = info.originalDuration = duration = (long) ((roundRight - roundLeft) * roundDuration); + } else if (audioPath != null) { info.estimatedDuration = info.originalDuration = duration = (long) ((audioRight - audioLeft) * audioDuration); } else { info.estimatedDuration = info.originalDuration = duration = averageDuration; @@ -839,6 +922,18 @@ public void getVideoEditedInfo(@NonNull Utilities.Callback when info.parts = parts; info.mixedSoundInfos.clear(); + if (round != null) { + final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(round.getAbsolutePath()); + soundInfo.volume = roundVolume; + soundInfo.audioOffset = (long) (roundLeft * roundDuration) * 1000L; + if (isVideo) { + soundInfo.startTime = (long) (roundOffset - left * duration) * 1000L; + } else { + soundInfo.startTime = 0; + } + soundInfo.duration = (long) ((roundRight - roundLeft) * roundDuration) * 1000L; + info.mixedSoundInfos.add(soundInfo); + } if (audioPath != null) { final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(audioPath); soundInfo.volume = audioVolume; @@ -1110,6 +1205,14 @@ public StoryEntry copy() { newEntry.thumbBitmap = thumbBitmap; newEntry.fromCamera = fromCamera; newEntry.thumbPathBitmap = thumbPathBitmap; + newEntry.isRepost = isRepost; + newEntry.round = round; + newEntry.roundLeft = roundLeft; + newEntry.roundRight = roundRight; + newEntry.roundDuration = roundDuration; + newEntry.roundThumb = roundThumb; + newEntry.roundOffset = roundOffset; + newEntry.roundVolume = roundVolume; return newEntry; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java index df3a45a14b..574ce11682 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java @@ -50,8 +50,6 @@ import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.exoplayer2.util.Consumer; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -89,13 +87,11 @@ import org.telegram.ui.Components.GroupCreateSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; -import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RadioButton; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.ViewPagerFixed; -import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.StoriesController; import java.util.ArrayList; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java index 538e0c0c9f..d7f2d7507b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java @@ -497,6 +497,9 @@ private static StoryPrivacyBottomSheet.StoryPrivacy getSaved(int currentAccount) } public static void applySaved(int currentAccount, StoryEntry entry) { + if (entry == null) { + return; + } entry.privacy = getSaved(currentAccount); entry.privacyRules.clear(); entry.privacyRules.addAll(entry.privacy.rules); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java index 5b11bd5554..7163aaac32 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java @@ -48,6 +48,7 @@ import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; +import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; @@ -81,6 +82,7 @@ import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -98,6 +100,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; +import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; import org.telegram.tgnet.TLObject; @@ -107,8 +110,10 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.AvatarSpan; import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.BlobDrawable; import org.telegram.ui.Components.BlurringShader; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; @@ -120,6 +125,7 @@ import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Paint.RenderView; +import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.PhotoFilterBlurControl; import org.telegram.ui.Components.PhotoFilterCurvesControl; import org.telegram.ui.Components.PhotoFilterView; @@ -131,6 +137,7 @@ import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.VideoEditTextureView; +import org.telegram.ui.Components.WaveDrawable; import org.telegram.ui.Components.ZoomControlView; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; @@ -154,8 +161,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private final Theme.ResourcesProvider resourcesProvider = new DarkThemeResourceProvider(); - private Activity activity; - private int currentAccount; + private final Activity activity; + private final int currentAccount; private boolean isShown; private boolean prepareClosing; @@ -168,6 +175,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private static StoryRecorder instance; private boolean wasSend; + private long wasSendPeer = 0; private ClosingViewProvider closingSourceProvider; public static StoryRecorder getInstance(Activity activity, int currentAccount) { @@ -222,7 +230,7 @@ public StoryRecorder(Activity activity, int currentAccount) { private ValueAnimator openCloseAnimator; private SourceView fromSourceView; private float fromRounding; - private RectF fromRect = new RectF(); + private final RectF fromRect = new RectF(); private float openProgress; private int openType; private float dismissProgress; @@ -241,7 +249,6 @@ public static class SourceView { int iconSize; View view; - protected void show() {} protected void hide() {} protected void drawAbove(Canvas canvas, float alpha) {} @@ -389,6 +396,20 @@ public StoryRecorder closeToWhenSent(ClosingViewProvider closingSourceProvider) return this; } + public void replaceSourceView(SourceView sourceView) { + if (sourceView != null) { + fromSourceView = sourceView; + openType = sourceView.type; + fromRect.set(sourceView.screenRect); + fromRounding = sourceView.rounding; + } else { + openType = 0; + fromRect.set(0, dp(100), AndroidUtilities.displaySize.x, dp(100) + AndroidUtilities.displaySize.y); + fromRounding = dp(8); + } + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); + } + public void open(SourceView sourceView) { open(sourceView, true); } @@ -428,7 +449,7 @@ public void open(SourceView sourceView, boolean animated) { fromRounding = dp(8); } containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); containerView.setTranslationX(0); containerView.setTranslationY(0); @@ -450,7 +471,6 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean } prepareClosing = false; -// privacySelectorHintOpened = false; forceBackgroundVisible = false; if (windowManager != null && windowView != null && windowView.getParent() == null) { @@ -472,7 +492,60 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean fromRounding = dp(8); } containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); + + containerView.setTranslationX(0); + containerView.setTranslationY(0); + containerView.setTranslationY2(0); + containerView.setScaleX(1f); + containerView.setScaleY(1f); + dismissProgress = 0; + + AndroidUtilities.lockOrientation(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + + if (outputEntry != null) { + captionEdit.setText(outputEntry.caption); + } + + navigateToPreviewWithPlayerAwait(() -> { + animateOpenTo(1, animated, this::onOpenDone); + previewButtons.appear(true, true); + }, time); + navigateTo(PAGE_PREVIEW, false); + switchToEditMode(EDIT_MODE_NONE, false); + + addNotificationObservers(); + } + + public void openForward(SourceView sourceView, StoryEntry entry, long time, boolean animated) { + if (isShown) { + return; + } + + prepareClosing = false; + forceBackgroundVisible = false; + + if (windowManager != null && windowView != null && windowView.getParent() == null) { + windowManager.addView(windowView, windowLayoutParams); + } + + outputEntry = entry; + StoryPrivacySelector.applySaved(currentAccount, outputEntry); + isVideo = outputEntry != null && outputEntry.isVideo; + + if (sourceView != null) { + fromSourceView = sourceView; + openType = sourceView.type; + fromRect.set(sourceView.screenRect); + fromRounding = sourceView.rounding; + fromSourceView.hide(); + } else { + openType = 0; + fromRect.set(0, dp(100), AndroidUtilities.displaySize.x, dp(100) + AndroidUtilities.displaySize.y); + fromRounding = dp(8); + } + containerView.updateBackground(); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); containerView.setTranslationX(0); containerView.setTranslationY(0); @@ -524,7 +597,7 @@ public void close(boolean animated) { onClosePrepareListener = null; prepareClosing = false; close(animated); - }, wasSend); + }, wasSend, wasSendPeer); return; } @@ -533,7 +606,7 @@ public void close(boolean animated) { } animateOpenTo(0, animated, this::onCloseDone); - if (openType == 1) { + if (openType == 1 || openType == 0) { windowView.setBackgroundColor(0x00000000); previewButtons.appear(false, true); } @@ -570,6 +643,7 @@ private void animateOpenTo(final float value, boolean animated, Runnable onDone) public void onAnimationEnd(Animator animation) { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -606,6 +680,7 @@ public void onAnimationEnd(Animator animation) { } else { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -633,6 +708,12 @@ private void onOpenDone() { } else { onResumeInternal(); } + + if (outputEntry != null && outputEntry.isRepost) { + createPhotoPaintView(); + hidePhotoPaintView(); + createFilterPhotoView(); + } } private void onCloseDone() { @@ -694,8 +775,8 @@ public void setOnFullyOpenListener(Runnable listener) { onFullyOpenListener = listener; } - private Utilities.Callback3 onClosePrepareListener; - public void setOnPrepareCloseListener(Utilities.Callback3 listener) { + private Utilities.Callback4 onClosePrepareListener; + public void setOnPrepareCloseListener(Utilities.Callback4 listener) { onClosePrepareListener = listener; } @@ -706,20 +787,39 @@ public void setOnPrepareCloseListener(Utilities.Callback3= Build.VERSION_CODES.LOLLIPOP) { previewContainer.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -1648,6 +1742,9 @@ public void getOutline(View view, Outline outline) { previewView = new PreviewView(context, blurManager) { @Override public boolean additionalTouchEvent(MotionEvent ev) { + if (captionEdit != null && captionEdit.isRecording()) { + return false; + } return photoFilterEnhanceView.onTouch(ev); } @@ -1704,10 +1801,47 @@ protected void onTimeDrag(boolean dragStart, long time, boolean dragEnd) { videoTimeView.setTime(time, !dragStart); videoTimeView.show(!dragEnd, true); } + + @Override + public void onRoundSelectChange(boolean selected) { + if (paintView == null) return; + if (!selected && paintView.getSelectedEntity() instanceof RoundView) { + paintView.selectEntity(null); + } else if (selected && !(paintView.getSelectedEntity() instanceof RoundView) && paintView.findRoundView() != null) { + paintView.selectEntity(paintView.findRoundView()); + } + } + + @Override + public void onRoundRemove() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } }; previewView.invalidateBlur = this::invalidateBlur; previewView.setOnTapListener(() -> { - if (currentEditMode != EDIT_MODE_NONE || currentPage != PAGE_PREVIEW || captionEdit.keyboardShown) { + if (currentEditMode != EDIT_MODE_NONE || currentPage != PAGE_PREVIEW || captionEdit.keyboardShown || captionEdit != null && captionEdit.isRecording()) { return; } if (timelineView.onBackPressed()) { @@ -1779,6 +1913,102 @@ public void onClick(@NonNull View widget) { protected void onCaptionLimitUpdate(boolean overLimit) { previewButtons.setShareEnabled(!videoError && !overLimit && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); } + + @Override + public boolean canRecord() { + return requestAudioPermission(); + } + + @Override + public void putRecorder(RoundVideoRecorder recorder) { + if (currentRoundRecorder != null) { + currentRoundRecorder.destroy(true); + } + if (previewView != null) { + previewView.mute(true); + previewView.seek(0); + } + recorder.onDone((file, thumb, duration) -> { + if (previewView != null) { + previewView.mute(false); + previewView.seek(0); + } + if (outputEntry != null) { + outputEntry.round = file; + outputEntry.roundThumb = thumb; + outputEntry.roundDuration = duration; + outputEntry.roundLeft = 0; + outputEntry.roundRight = 1; + outputEntry.roundOffset = 0; + outputEntry.roundVolume = 1f; + + createPhotoPaintView(); + if (previewView != null && paintView != null) { + RoundView roundView = paintView.createRound(outputEntry.roundThumb, true); + setHasRoundVideo(true); + previewView.setupRound(outputEntry, roundView, true); + + recorder.hideTo(roundView); + } else { + recorder.destroy(false); + } + } + }); + recorder.onDestroy(() -> { + if (previewView != null) { + previewView.mute(false); + previewView.seek(0); + } + }); + previewContainer.addView(currentRoundRecorder = recorder, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + @Override + public void removeRound() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } + + @Override + public void invalidateDrawOver2() { + if (captionEditOverlay != null) { + captionEditOverlay.invalidate(); + } + } + + @Override + public boolean drawOver2FromParent() { + return true; + } + + @Override + public int getTimelineHeight() { + if (videoTimelineContainerView != null && timelineView != null && timelineView.getVisibility() == View.VISIBLE) { + return timelineView.getContentHeight(); + } + return 0; + } }; captionEdit.setAccount(currentAccount); captionEdit.setUiBlurBitmap(this::getUiBlurBitmap); @@ -1817,18 +2047,28 @@ public int getBottomOffset(int tag) { visibleBulletin.updatePosition(); } }); + captionEditOverlay = new View(context) { + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + canvas.translate(captionContainer.getX() + captionEdit.getX(), captionContainer.getY() + captionEdit.getY()); + captionEdit.drawOver2(canvas, captionEdit.getBounds(), captionEdit.getOver2Alpha()); + canvas.restore(); + } + }; + containerView.addView(captionEditOverlay); timelineView = new TimelineView(context, containerView, previewContainer, resourcesProvider, blurManager); previewView.setVideoTimelineView(timelineView); timelineView.setVisibility(View.GONE); timelineView.setAlpha(0f); videoTimelineContainerView = new FrameLayout(context); - videoTimelineContainerView.addView(timelineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 0)); + videoTimelineContainerView.addView(timelineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, TimelineView.heightDp(), Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 0)); videoTimeView = new VideoTimeView(context); videoTimeView.setVisibility(View.GONE); videoTimeView.show(false, false); videoTimelineContainerView.addView(videoTimeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 25, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 0, 0, 0)); - captionContainer.addView(videoTimelineContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80 + 25, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 68)); + captionContainer.addView(videoTimelineContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, TimelineView.heightDp() + 25, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 68)); captionContainer.addView(captionEdit, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 200, 0, 0)); backButton = new FlashViews.ImageViewInvertable(context); @@ -1884,15 +2124,16 @@ public int getBottomOffset(int tag) { } outputEntry.muted = !outputEntry.muted; final boolean hasMusic = !TextUtils.isEmpty(outputEntry.audioPath); + final boolean hasRound = outputEntry.round != null; muteHint.setText( outputEntry.muted ? - LocaleController.getString(hasMusic ? R.string.StoryOriginalSoundMuted : R.string.StorySoundMuted) : - LocaleController.getString(hasMusic ? R.string.StoryOriginalSoundNotMuted : R.string.StorySoundNotMuted), + LocaleController.getString(hasMusic || hasRound ? R.string.StoryOriginalSoundMuted : R.string.StorySoundMuted) : + LocaleController.getString(hasMusic || hasRound ? R.string.StoryOriginalSoundNotMuted : R.string.StorySoundNotMuted), muteHint.shown() ); muteHint.show(); setIconMuted(outputEntry.muted, true); - previewView.mute(outputEntry.muted); + previewView.checkVolumes(); }); muteButton.setVisibility(View.GONE); muteButton.setAlpha(0f); @@ -2058,7 +2299,7 @@ public int getBottomOffset(int tag) { previewButtons = new PreviewButtons(context); previewButtons.setVisibility(View.GONE); previewButtons.setOnClickListener((Integer btn) -> { - if (outputEntry == null) { + if (outputEntry == null || captionEdit.isRecording()) { return; } captionEdit.clearFocus(); @@ -2283,6 +2524,7 @@ private void uploadInternal(boolean asStory) { outputEntry = null; wasSend = true; + wasSendPeer = sendAsDialogId; forceBackgroundVisible = true; checkBackgroundVisibility(); @@ -2297,7 +2539,7 @@ private void uploadInternal(boolean asStory) { if (fromSourceView != null) { openType = fromSourceView.type; containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); fromRect.set(fromSourceView.screenRect); fromRounding = fromSourceView.rounding; fromSourceView.hide(); @@ -2526,19 +2768,22 @@ private void takePicture(Utilities.Callback done) { if (outputFile == null) { return; } + int w = -1, h = -1; + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(outputFile.getAbsolutePath(), opts); + w = opts.outWidth; + h = opts.outHeight; + } catch (Exception ignore) {} + int rotate = orientation == -1 ? 0 : 90; if (orientation == -1) { - int w = -1, h = -1; - try { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeFile(outputFile.getAbsolutePath(), opts); - w = opts.outWidth; - h = opts.outHeight; - } catch (Exception ignore) {} if (w > h) { rotate = 270; } + } else if (h > w && rotate != 0) { + rotate = 0; } outputEntry = StoryEntry.fromPhotoShoot(outputFile, rotate); StoryPrivacySelector.applySaved(currentAccount, outputEntry); @@ -2921,6 +3166,9 @@ public void onAnimationEnd(Animator animation) { } public boolean onBackPressed() { + if (captionEdit != null && captionEdit.stopRecording()) { + return false; + } if (takingVideo) { recordControl.stopRecording(); return false; @@ -2942,10 +3190,10 @@ public boolean onBackPressed() { } else if (currentEditMode > EDIT_MODE_NONE) { switchToEditMode(EDIT_MODE_NONE, true); return false; - } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isEdit || (paintView != null && paintView.hasChanges()) || outputEntry.editedMedia || outputEntry.editedCaption)) { + } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isRepost) && (outputEntry == null || !outputEntry.isEdit || (paintView != null && paintView.hasChanges()) || outputEntry.editedMedia || outputEntry.editedCaption)) { if (paintView != null && paintView.onBackPressed()) { return false; - } else if ((fromGallery && (paintView == null || !paintView.hasChanges()) && (outputEntry == null || outputEntry.filterFile == null) || !previewButtons.isShareEnabled()) && (outputEntry == null || !outputEntry.isEdit)) { + } else if ((fromGallery && (paintView == null || !paintView.hasChanges()) && (outputEntry == null || outputEntry.filterFile == null) || !previewButtons.isShareEnabled()) && (outputEntry == null || !outputEntry.isEdit || !outputEntry.isRepost)) { navigateTo(PAGE_CAMERA, true); } else { showDismissEntry(); @@ -2957,6 +3205,37 @@ public boolean onBackPressed() { } } + private void setReply() { + if (captionEdit == null) return; + if (outputEntry == null || !outputEntry.isRepost) { + captionEdit.setReply(null, null); + } else { + TLRPC.Peer peer = outputEntry.repostPeer; + CharSequence peerName; + if (peer instanceof TLRPC.TL_peerUser) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(peer.user_id); + String name = UserObject.getUserName(user); + peerName = outputEntry.repostPeerName = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(name); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(peer)); + String name = chat == null ? "" : chat.title; + peerName = outputEntry.repostPeerName = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(name); + } + CharSequence repostCaption = outputEntry.repostCaption; + if (TextUtils.isEmpty(repostCaption)) { + SpannableString s = new SpannableString(LocaleController.getString(R.string.Story)); + s.setSpan(new CharacterStyle() { + @Override + public void updateDrawState(TextPaint tp) { + tp.setAlpha(0x80); + } + }, 0, s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + repostCaption = s; + } + captionEdit.setReply(peerName, repostCaption); + } + } + private Runnable afterPlayerAwait; private boolean previewAlreadySet; public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo) { @@ -2979,7 +3258,7 @@ public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo) { previewView.setVisibility(View.VISIBLE); previewView.set(outputEntry, afterPlayerAwait, seekTo); previewView.setupAudio(outputEntry, false); - AndroidUtilities.runOnUIThread(afterPlayerAwait, 400); + AndroidUtilities.runOnUIThread(afterPlayerAwait, 800); } private AnimatorSet pageAnimator; @@ -3402,6 +3681,8 @@ private void onNavigateStart(int fromPage, int toPage) { // privacySelector.setStoryPeriod(outputEntry == null || !UserConfig.getInstance(currentAccount).isPremium() ? 86400 : outputEntry.period); captionEdit.setPeriod(outputEntry == null ? 86400 : outputEntry.period, false); captionEdit.setPeriodVisible(!MessagesController.getInstance(currentAccount).premiumLocked && (outputEntry == null || !outputEntry.isEdit)); + captionEdit.setHasRoundVideo(outputEntry != null && outputEntry.round != null); + setReply(); } if (toPage == PAGE_PREVIEW) { videoError = false; @@ -3444,7 +3725,31 @@ private void onNavigateStart(int fromPage, int toPage) { previewView.setVisibility(View.VISIBLE); timelineView.setVisibility(View.VISIBLE); titleTextView.setVisibility(View.VISIBLE); - titleTextView.setText(outputEntry != null && outputEntry.isEdit ? LocaleController.getString(R.string.RecorderEditStory) : LocaleController.getString(R.string.RecorderNewStory)); + titleTextView.setTranslationX(0); + if (outputEntry != null && outputEntry.isEdit) { + titleTextView.setText(LocaleController.getString(R.string.RecorderEditStory)); + } else if (outputEntry != null && outputEntry.isRepost) { + SpannableStringBuilder title = new SpannableStringBuilder(); + AvatarSpan span = new AvatarSpan(titleTextView, currentAccount, 32); + titleTextView.setTranslationX(-dp(6)); + SpannableString avatar = new SpannableString("a"); + avatar.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (outputEntry.repostPeer instanceof TLRPC.TL_peerUser) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(outputEntry.repostPeer.user_id); + span.setUser(user); + title.append(avatar).append(" "); + title.append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(outputEntry.repostPeer)); + span.setChat(chat); + title.append(avatar).append(" "); + title.append(chat != null ? chat.title : ""); + } + titleTextView.setText(title); + } else { + titleTextView.setText(LocaleController.getString(R.string.RecorderNewStory)); + } + // MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); // MediaDataController.getInstance(currentAccount).checkFeaturedEmoji(); } @@ -3501,9 +3806,11 @@ private void onNavigateEnd(int fromPage, int toPage) { videoTimeView.setVisibility(View.GONE); } if (toPage == PAGE_PREVIEW) { - createPhotoPaintView(); - hidePhotoPaintView(); - createFilterPhotoView(); + if (outputEntry == null || !outputEntry.isRepost) { + createPhotoPaintView(); + hidePhotoPaintView(); + createFilterPhotoView(); + } if (photoFilterEnhanceView != null) { photoFilterEnhanceView.setAllowTouch(false); } @@ -3548,6 +3855,9 @@ public void switchToEditMode(int editMode, boolean animated) { if (currentEditMode == editMode) { return; } + if (editMode != EDIT_MODE_NONE && (captionEdit != null && captionEdit.isRecording())) { + return; + } final int oldEditMode = currentEditMode; currentEditMode = editMode; @@ -3717,6 +4027,7 @@ private void createPhotoPaintView() { null, previewView.getOrientation(), outputEntry == null ? null : outputEntry.mediaEntities, + outputEntry, w, h, new MediaController.CropState(), null, @@ -3865,6 +4176,64 @@ protected boolean checkAudioPermission(Runnable granted) { } return true; } + + @Override + public void onCreateRound(RoundView roundView) { + if (previewView != null) { + previewView.attachRoundView(roundView); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(true); + } + } + + @Override + public void onTryDeleteRound() { + if (captionEdit != null) { + captionEdit.showRemoveRoundAlert(); + } + } + + @Override + public void onDeleteRound() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } + + @Override + public void onSelectRound(RoundView roundView) { + if (timelineView != null) { + timelineView.selectRound(true); + } + } + + @Override + public void onDeselectRound(RoundView roundView) { + if (timelineView != null) { + timelineView.selectRound(false); + } + } }; paintView.setBlurManager(blurManager); containerView.addView(paintView); @@ -3930,6 +4299,9 @@ private void orderPreviewViews() { if (previewHighlight != null) { previewHighlight.bringToFront(); } + if (currentRoundRecorder != null) { + currentRoundRecorder.bringToFront(); + } } private void destroyPhotoPaintView() { @@ -4042,7 +4414,7 @@ private void applyPaint() { } else { outputEntry.mediaEntities.clear(); } - paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false); + paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false, outputEntry); if (!outputEntry.isVideo) { outputEntry.averageDuration = Utilities.clamp(paintView.getLcm(), 7500L, 5000L); } @@ -4052,7 +4424,7 @@ private void applyPaint() { final boolean wouldBeVideo = outputEntry.wouldBeVideo(); outputEntry.mediaEntities = new ArrayList<>(); - Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, !isVideo); + Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, !isVideo, outputEntry); if (outputEntry.mediaEntities.isEmpty()) { outputEntry.mediaEntities = null; } @@ -4083,7 +4455,7 @@ private void applyPaint() { bitmap = null; if (!wouldBeVideo) { - bitmap = paintView.getBitmap(new ArrayList<>(), outputEntry.resultWidth, outputEntry.resultHeight, false, true, false); + bitmap = paintView.getBitmap(new ArrayList<>(), outputEntry.resultWidth, outputEntry.resultHeight, false, true, false, outputEntry); outputEntry.paintEntitiesFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101), true); if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); @@ -4280,7 +4652,17 @@ protected void onSavedDualCameraSuccess() { } dualButton.setValue(isDual()); } + + @Override + protected void receivedAmplitude(double amplitude) { + if (recordControl != null) { + recordControl.setAmplitude(Utilities.clamp((float) (amplitude / WaveDrawable.MAX_AMPLITUDE), 1, 0), true); + } + } }; + if (recordControl != null) { + recordControl.setAmplitude(0, false); + } cameraView.isStory = true; cameraView.setThumbDrawable(getCameraThumb()); cameraView.initTexture(); @@ -4443,11 +4825,11 @@ private void showDismissEntry() { }); } builder.setPositiveButton(outputEntry != null && outputEntry.isDraft && !outputEntry.isEdit ? LocaleController.getString("StoryDeleteDraft") : LocaleController.getString("Discard", R.string.Discard), (dialogInterface, i) -> { - if (outputEntry != null && !outputEntry.isEdit && outputEntry.isDraft) { + if (outputEntry != null && !(outputEntry.isEdit || outputEntry.isRepost) && outputEntry.isDraft) { MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().delete(outputEntry); outputEntry = null; } - if (outputEntry != null && outputEntry.isEdit) { + if (outputEntry != null && (outputEntry.isEdit || outputEntry.isRepost)) { close(true); } else { navigateTo(PAGE_CAMERA, true); @@ -4644,6 +5026,22 @@ private void onRequestPermissionsResultInternal(int requestCode, String[] permis if (granted) { MediaController.loadGalleryPhotosAlbums(0); animateGalleryListView(true); + } else { + new AlertDialog.Builder(getContext(), resourcesProvider) + .setTopAnimation(R.raw.permission_request_folder, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PermissionStorageWithHint))) + .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + activity.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + }) + .setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), null) + .create() + .show(); } } else if (requestCode == 112) { if (!granted) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java index e80473070b..8c138ccce6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java @@ -66,13 +66,21 @@ interface TimelineDelegate { void onVideoLeftChange(float left); void onVideoRightChange(float right); + void onVideoVolumeChange(float volume); void onAudioOffsetChange(long offset); void onAudioLeftChange(float left); void onAudioRightChange(float right); - void onAudioVolumeChange(float volume); void onAudioRemove(); + + void onRoundOffsetChange(long offset); + void onRoundLeftChange(float left); + void onRoundRightChange(float right); + void onRoundVolumeChange(float volume); + void onRoundRemove(); + + void onRoundSelectChange(boolean selected); } private TimelineDelegate delegate; @@ -85,8 +93,19 @@ interface TimelineDelegate { private long videoDuration; private float videoLeft; private float videoRight; + private float videoVolume; private VideoThumbsLoader thumbs; + private boolean hasRound; + private String roundPath; + private boolean roundSelected; + private long roundDuration; + private long roundOffset; + private float roundLeft; + private float roundRight; + private float roundVolume; + private VideoThumbsLoader roundThumbs; + private boolean hasAudio; private String audioPath; private boolean audioSelected; @@ -96,21 +115,30 @@ interface TimelineDelegate { private float audioRight; private boolean waveformIsLoaded; private float audioVolume; + private boolean resetWaveform; private AudioWaveformLoader waveform; private long getBaseDuration() { if (hasVideo) { return videoDuration; } + if (hasRound) { + return roundDuration; + } if (hasAudio) { return audioDuration; } return Math.max(1, audioDuration); } + private final AnimatedFloat roundT = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat roundSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat audioT = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); private final AnimatedFloat audioSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat videoSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat waveformLoaded = new AnimatedFloat(this, 0, 600, CubicBezierInterpolator.EASE_OUT_QUINT); private final AnimatedFloat waveformMax = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -124,6 +152,9 @@ private long getBaseDuration() { private final Path videoClipPath = new Path(); private final Path selectedVideoClipPath = new Path(); + private final RectF roundBounds = new RectF(); + private final Path roundClipPath = new Path(); + private final Paint regionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint regionCutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint regionHandlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -190,11 +221,11 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, audioWaveformBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_AUDIO_WAVEFORM_BACKGROUND); onLongPress = () -> { - if (!pressVideo && hasAudio) { + if (pressType == 2 && hasAudio) { SliderView slider = new SliderView(getContext(), SliderView.TYPE_VOLUME) - .setValue(audioVolume) .setMinMax(0, 1.5f) + .setValue(audioVolume) .setOnValueChange(volume -> { audioVolume = volume; if (delegate != null) { @@ -202,7 +233,8 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, } }); final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); - float uiRight = Math.min(w - px - ph, px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelectedT.get()) * audioDuration) / (float) videoScrollDuration * sw); + final float uiRight = Math.min(w - px - ph, px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelectedT.get()) * audioDuration) / (float) videoScrollDuration * sw); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0) - (hasAudio ? getAudioHeight() + dp(4) : 0); ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) .addView(slider) .addSpaceGap() @@ -213,10 +245,63 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, }) .setGravity(Gravity.RIGHT) .forceTop(true) - .translate(-(w - uiRight) + dp(18), dp(4) + (!hasVideo ? dp(audioSelected ? 35 : 40) : 0)) + .translate(-(w - uiRight) + dp(18), y) .show(); itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception e) {} + } else if (pressType == 1 && hasRound) { + SliderView slider = + new SliderView(getContext(), SliderView.TYPE_VOLUME) + .setMinMax(0, 1.5f) + .setValue(roundVolume) + .setOnValueChange(volume -> { + roundVolume = volume; + if (delegate != null) { + delegate.onRoundVolumeChange(volume); + } + }); + final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); + final float uiRight = Math.min(w - px - ph, px + ph + (roundOffset - scroll + lerp(roundRight, 1, roundSelectedT.get()) * roundDuration) / (float) videoScrollDuration * sw); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0); + ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) + .addView(slider) + .addSpaceGap() + .add(R.drawable.msg_delete, LocaleController.getString(R.string.StoryRoundRemove), () -> { + if (delegate != null) { + delegate.onRoundRemove(); + } + }) + .setGravity(Gravity.RIGHT) + .forceTop(true) + .translate(-(w - uiRight) + dp(18), y) + .show(); + itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); + + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception e) {} + } else if (pressType == 0 && hasVideo) { + SliderView slider = + new SliderView(getContext(), SliderView.TYPE_VOLUME) + .setMinMax(0, 1.5f) + .setValue(videoVolume) + .setOnValueChange(volume -> { + videoVolume = volume; + if (delegate != null) { + delegate.onVideoVolumeChange(volume); + } + }); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0); + ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) + .addView(slider) + .setGravity(Gravity.RIGHT) + .forceTop(true) + .translate(dp(18), y) + .show(); + itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); try { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception e) {} @@ -228,7 +313,7 @@ public void setDelegate(TimelineDelegate delegate) { this.delegate = delegate; } - public void setVideo(String videoPath, long videoDuration) { + public void setVideo(String videoPath, long videoDuration, float videoVolume) { if (TextUtils.equals(this.videoPath, videoPath)) { return; } @@ -240,25 +325,98 @@ public void setVideo(String videoPath, long videoDuration) { scroll = 0; this.videoPath = videoPath; this.videoDuration = videoDuration; + this.videoVolume = videoVolume; setupVideoThumbs(); } else { this.videoPath = null; this.videoDuration = 1; scroll = 0; } + if (!hasRound) { + roundSelected = false; + } hasVideo = this.videoPath != null; progress = 0; invalidate(); } + public void setRoundNull(boolean animated) { + setRound(null, 0, 0, 0, 0, 0, animated); + } + + public void setRound(String roundPath, long roundDuration, long offset, float left, float right, float volume, boolean animated) { + if (TextUtils.equals(this.roundPath, roundPath)) { + return; + } + if (roundThumbs != null) { + roundThumbs.destroy(); + roundThumbs = null; + } + final long hadRoundDuration = this.roundDuration; + if (roundPath != null) { + this.roundPath = roundPath; + this.roundDuration = roundDuration; + this.roundOffset = offset - (long) (left * roundDuration); + this.roundLeft = left; + this.roundRight = right; + this.roundVolume = volume; + setupRoundThumbs(); + if (!hasVideo) { + audioSelected = false; + roundSelected = true; + } + } else { + this.roundPath = null; + this.roundDuration = 1; + roundSelected = false; + } + hasRound = this.roundPath != null; + if (hadRoundDuration != roundDuration && !hasVideo && waveform != null) { + resetWaveform = true; + setupAudioWaveform(); + } + if (hasAudio && hasRound && !hasVideo) { + audioLeft = 0; + audioRight = Utilities.clamp((float) roundDuration / audioDuration, 1, 0); + } + if (!animated) { + roundSelectedT.set(roundSelected, true); + audioSelectedT.set(audioSelected, true); + roundT.set(hasRound, true); + } + invalidate(); + } + + public void selectRound(boolean select) { + if (select && hasRound) { + roundSelected = true; + audioSelected = false; + } else { + roundSelected = false; + audioSelected = hasAudio && !hasVideo; + } + invalidate(); + } + private void setupVideoThumbs() { if (getMeasuredWidth() <= 0 || this.thumbs != null) { return; } - this.thumbs = new VideoThumbsLoader(videoPath, getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), dp(38)); + this.thumbs = new VideoThumbsLoader(videoPath, w - px - px, dp(38), videoDuration > 2 ? videoDuration : null); if (this.thumbs.getDuration() > 0) { videoDuration = this.thumbs.getDuration(); } + setupRoundThumbs(); + } + + private void setupRoundThumbs() { + if (getMeasuredWidth() <= 0 || this.roundThumbs != null || hasVideo && videoDuration < 1) { + return; + } + this.roundThumbs = new VideoThumbsLoader(roundPath, w - px - px, dp(38), roundDuration > 2 ? roundDuration : null, hasVideo ? videoDuration : MAX_SCROLL_DURATION); + if (this.roundThumbs.getDuration() > 0) { + roundDuration = this.roundThumbs.getDuration(); + } } private final AnimatedFloat loopProgress = new AnimatedFloat(0, this, 0, 340, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -266,7 +424,8 @@ private void setupVideoThumbs() { public void setProgress(long progress) { if ( hasVideo && progress < this.progress && progress <= videoDuration * videoLeft + 240 && this.progress + 240 >= videoDuration * videoRight || - hasAudio && progress < this.progress && progress <= audioDuration * audioLeft + 240 && this.progress + 240 >= audioDuration * audioRight + hasAudio && !hasRound && !hasVideo && progress < this.progress && progress <= audioDuration * audioLeft + 240 && this.progress + 240 >= audioDuration * audioRight || + hasRound && !hasVideo && progress < this.progress && progress <= roundDuration * audioLeft + 240 && this.progress + 240 >= roundDuration * audioRight ) { loopProgressFrom = -1; loopProgress.set(1, true); @@ -339,7 +498,7 @@ public void setAudio(String audioPath, String audioAuthorText, String audioTitle } private void setupAudioWaveform() { - if (getMeasuredWidth() <= 0 || this.waveform != null) { + if (getMeasuredWidth() <= 0 || this.waveform != null && !resetWaveform) { return; } this.waveform = new AudioWaveformLoader(audioPath, getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); @@ -349,15 +508,22 @@ private void setupAudioWaveform() { } private static final int HANDLE_PROGRESS = 0; + private static final int HANDLE_VIDEO_SCROLL = 1; private static final int HANDLE_VIDEO_LEFT = 2; private static final int HANDLE_VIDEO_RIGHT = 3; private static final int HANDLE_VIDEO_REGION = 4; + private static final int HANDLE_AUDIO_SCROLL = 5; private static final int HANDLE_AUDIO_LEFT = 6; private static final int HANDLE_AUDIO_RIGHT = 7; private static final int HANDLE_AUDIO_REGION = 8; + private static final int HANDLE_ROUND_SCROLL = 9; + private static final int HANDLE_ROUND_LEFT = 10; + private static final int HANDLE_ROUND_RIGHT = 11; + private static final int HANDLE_ROUND_REGION = 12; + private int detectHandle(MotionEvent event) { float x = event.getX(); float y = event.getY(); @@ -369,7 +535,8 @@ private int detectHandle(MotionEvent event) { return HANDLE_PROGRESS; } - final boolean isInVideo = y > h - py - getVideoHeight() - dp(2); + final boolean isInVideo = hasVideo && y > h - py - getVideoHeight() - dp(2); + final boolean isInRound = hasRound && y > h - py - getVideoHeight() - dp(4) - getRoundHeight() - dp(4) - dp(2) && y < h - py - getVideoHeight() - dp(2); if (isInVideo) { final float leftX = px + ph + (videoLeft * videoDuration - scroll) / (float) scrollWidth * sw; @@ -382,19 +549,36 @@ private int detectHandle(MotionEvent event) { } else if (x >= leftX && x <= rightX && (videoLeft > 0.01f || videoRight < .99f)) { return HANDLE_VIDEO_REGION; } + } else if (isInRound) { + float leftX = px + ph + (roundOffset + roundLeft * roundDuration - scroll) / (float) scrollWidth * sw; + float rightX = px + ph + (roundOffset + roundRight * roundDuration - scroll) / (float) scrollWidth * sw; + if (roundSelected || !hasVideo) { + if (x >= leftX - dp(10 + 5) && x <= leftX + dp(5)) { + return HANDLE_ROUND_LEFT; + } else if (x >= rightX - dp(5) && x <= rightX + dp(10 + 5)) { + return HANDLE_ROUND_RIGHT; + } else if (x >= leftX && x <= rightX) { + if (!hasVideo) { + return HANDLE_ROUND_REGION; + } else { + return HANDLE_ROUND_SCROLL; + } + } + leftX = px + ph + (roundOffset - scroll) / (float) scrollWidth * sw; + rightX = px + ph + (roundOffset + roundDuration - scroll) / (float) scrollWidth * sw; + } + if (x >= leftX && x <= rightX) { + return HANDLE_ROUND_SCROLL; + } } else if (hasAudio) { float leftX = px + ph + (audioOffset + audioLeft * audioDuration - scroll) / (float) scrollWidth * sw; float rightX = px + ph + (audioOffset + audioRight * audioDuration - scroll) / (float) scrollWidth * sw; - - if (audioSelected || !hasVideo) { + if (audioSelected || !hasVideo && !hasRound) { if (x >= leftX - dp(10 + 5) && x <= leftX + dp(5)) { return HANDLE_AUDIO_LEFT; } else if (x >= rightX - dp(5) && x <= rightX + dp(10 + 5)) { return HANDLE_AUDIO_RIGHT; } else if (x >= leftX && x <= rightX) { - final float maxDuration = Math.min(MAX_SCROLL_DURATION, getBaseDuration()); - final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; - final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + maxDuration) / (float) audioDuration); if (!hasVideo) { return HANDLE_AUDIO_REGION; } else { @@ -419,6 +603,12 @@ private int detectHandle(MotionEvent event) { public boolean onBackPressed() { if (audioSelected) { audioSelected = false; + if (hasRound && !hasVideo) { + roundSelected = true; + if (delegate != null) { + delegate.onRoundSelectChange(true); + } + } return true; } return false; @@ -465,8 +655,8 @@ private boolean setProgressAt(float x, boolean fast) { private float getVideoHeight() { if (!hasVideo) return 0; - float audioSelected = this.audioSelectedT.set(this.audioSelected); - return lerp(dp(28), dp(38), 1f - audioSelected); + float videoSelected = this.videoSelectedT.set(!this.audioSelected && !this.roundSelected); + return lerp(dp(28), dp(38), videoSelected); } private float getAudioHeight() { @@ -474,11 +664,18 @@ private float getAudioHeight() { return lerp(dp(28), dp(38), audioSelected); } + private float getRoundHeight() { + if (!hasRound) + return 0; + float roundSelected = this.roundSelectedT.set(this.roundSelected); + return lerp(dp(28), dp(38), roundSelected); + } + private long lastTime; private long pressTime; private float lastX; private int pressHandle = -1; - private boolean pressVideo = true; + private int pressType = -1; private boolean draggingProgress, dragged; private boolean hadDragChange; private VelocityTracker velocityTracker; @@ -487,15 +684,12 @@ private float getAudioHeight() { @Override public boolean onTouchEvent(MotionEvent event) { - if (!hasVideo && !hasAudio) { - return false; - } - - if (hasVideo && !hasAudio && event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < h - py - getVideoHeight() - py) { + if (!hasVideo && !hasAudio && !hasRound) { return false; } - if (hasAudio && !hasVideo && event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < h - py - getAudioHeight() - py) { + final float top = h - py - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasAudio ? getAudioHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0); + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < top) { return false; } @@ -507,7 +701,26 @@ public boolean onTouchEvent(MotionEvent event) { } scroller.abortAnimation(); pressHandle = detectHandle(event); - pressVideo = !hasAudio || event.getY() > h - py - getVideoHeight() - (hasVideo ? dp(4) : 0); + pressType = -1; + int y = h - py; + if (pressType == -1 && hasVideo) { + if (event.getY() < y && event.getY() > y - getVideoHeight() - dp(2)) { + pressType = 0; + } + y -= getVideoHeight() + dp(4); + } + if (pressType == -1 && hasRound) { + if (event.getY() < y && event.getY() > y - getRoundHeight() - dp(2)) { + pressType = 1; + } + y -= getRoundHeight() + dp(4); + } + if (pressType == -1 && hasAudio) { + if (event.getY() < y && event.getY() > y - getAudioHeight() - dp(2)) { + pressType = 2; + } + y -= getAudioHeight() + dp(4); + } pressTime = System.currentTimeMillis(); draggingProgress = pressHandle == HANDLE_PROGRESS || pressHandle == -1 || pressHandle == HANDLE_VIDEO_SCROLL; hadDragChange = false; @@ -582,13 +795,15 @@ public boolean onTouchEvent(MotionEvent event) { if (pressHandle == HANDLE_AUDIO_LEFT) { float maxValue = audioRight - minAudioSelect() / (float) audioDuration; float minValue = Math.max(0, scroll - audioOffset) / (float) audioDuration; - if (!hasVideo) { + if (!hasVideo && !hasRound) { minValue = Math.max(minValue, audioRight - MAX_SELECT_DURATION / (float) audioDuration); if (!hadDragChange && d < 0 && audioLeft <= (audioRight - MAX_SELECT_DURATION / (float) audioDuration)) { pressHandle = HANDLE_AUDIO_REGION; } - } else { + } else if (hasVideo) { minValue = Math.max(minValue, (videoLeft * videoDuration + scroll - audioOffset) / (float) audioDuration); + } else if (hasRound) { + minValue = Math.max(minValue, (roundLeft * roundDuration + scroll - audioOffset) / (float) audioDuration); } float wasAudioLeft = audioLeft; audioLeft = Utilities.clamp(audioLeft + d, maxValue, minValue); @@ -604,13 +819,15 @@ public boolean onTouchEvent(MotionEvent event) { } else if (pressHandle == HANDLE_AUDIO_RIGHT) { float maxValue = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); float minValue = audioLeft + minAudioSelect() / (float) audioDuration; - if (!hasVideo) { + if (!hasVideo && !hasRound) { maxValue = Math.min(maxValue, audioLeft + MAX_SELECT_DURATION / (float) audioDuration); if (!hadDragChange && d > 0 && audioRight >= (audioLeft + MAX_SELECT_DURATION / (float) audioDuration)) { pressHandle = HANDLE_AUDIO_REGION; } - } else { + } else if (hasVideo) { maxValue = Math.min(maxValue, (videoRight * videoDuration + scroll - audioOffset) / (float) audioDuration); + } else if (hasRound) { + maxValue = Math.min(maxValue, (roundRight * roundDuration + scroll - audioOffset) / (float) audioDuration); } float wasAudioRight = audioRight; audioRight = Utilities.clamp(audioRight + d, maxValue, minValue); @@ -625,9 +842,9 @@ public boolean onTouchEvent(MotionEvent event) { float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); if (d > 0) { - d = Math.min(maxRight - audioRight, d); + d = Math.min(Math.max(0, maxRight - audioRight), d); } else { - d = Math.max(minLeft - audioLeft, d); + d = Math.max(Math.min(0, minLeft - audioLeft), d); } audioLeft += d; audioRight += d; @@ -641,7 +858,7 @@ public boolean onTouchEvent(MotionEvent event) { delegate.onProgressDragChange(true); } } - if (!hasVideo) { + if (!hasVideo && !hasRound) { progress = (long) (audioLeft * audioDuration); if (delegate != null) { delegate.onProgressDragChange(true); @@ -651,11 +868,90 @@ public boolean onTouchEvent(MotionEvent event) { invalidate(); dragged = true; draggingProgress = false; + } else if (pressHandle == HANDLE_ROUND_LEFT || pressHandle == HANDLE_ROUND_RIGHT || pressHandle == HANDLE_ROUND_REGION) { + float d = Δx / sw * (videoScrollDuration / (float) roundDuration); + if (pressHandle == HANDLE_ROUND_LEFT) { + float maxValue = roundRight - minAudioSelect() / (float) roundDuration; + float minValue = Math.max(0, scroll - roundOffset) / (float) roundDuration; + if (!hasVideo) { + minValue = Math.max(minValue, roundRight - MAX_SELECT_DURATION / (float) roundDuration); + if (!hadDragChange && d < 0 && roundLeft <= (roundRight - MAX_SELECT_DURATION / (float) roundDuration)) { + pressHandle = HANDLE_AUDIO_REGION; + } + } else { + minValue = Math.max(minValue, (videoLeft * videoDuration + scroll - roundOffset) / (float) roundDuration); + } + float wasAudioLeft = roundLeft; + roundLeft = Utilities.clamp(roundLeft + d, maxValue, minValue); + if (Math.abs(wasAudioLeft - roundLeft) > 0.01f) { + hadDragChange = true; + } + if (delegate != null) { + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + } + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + } + } else if (pressHandle == HANDLE_ROUND_RIGHT) { + float maxValue = Math.min(1, Math.max(0, scroll - roundOffset + videoScrollDuration) / (float) roundDuration); + float minValue = roundLeft + minAudioSelect() / (float) roundDuration; + if (!hasVideo) { + maxValue = Math.min(maxValue, roundLeft + MAX_SELECT_DURATION / (float) roundDuration); + if (!hadDragChange && d > 0 && roundRight >= (roundLeft + MAX_SELECT_DURATION / (float) roundDuration)) { + pressHandle = HANDLE_AUDIO_REGION; + } + } else { + maxValue = Math.min(maxValue, (videoRight * videoDuration + scroll - roundOffset) / (float) roundDuration); + } + float wasAudioRight = roundRight; + roundRight = Utilities.clamp(roundRight + d, maxValue, minValue); + if (Math.abs(wasAudioRight - roundRight) > 0.01f) { + hadDragChange = true; + } + if (delegate != null) { + delegate.onRoundRightChange(roundRight); + } + } + if (pressHandle == HANDLE_ROUND_REGION) { + float minLeft = Math.max(0, scroll - roundOffset) / (float) roundDuration; + float maxRight = Math.min(1, Math.max(0, scroll - roundOffset + videoScrollDuration) / (float) roundDuration); + if (d > 0) { + d = Math.min(maxRight - roundRight, d); + } else { + d = Math.max(minLeft - roundLeft, d); + } + roundLeft += d; + roundRight += d; + + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + delegate.onRoundRightChange(roundRight); + } + if (delegate != null) { + delegate.onProgressDragChange(true); + } + } + if (!hasVideo) { + progress = (long) (roundLeft * roundDuration); + if (delegate != null) { + delegate.onProgressDragChange(true); + delegate.onProgressChange(progress, false); + } + } + invalidate(); + dragged = true; + draggingProgress = false; } else if (pressHandle == HANDLE_AUDIO_SCROLL) { float d = Δx / sw * videoScrollDuration; moveAudioOffset(d); dragged = true; draggingProgress = false; + } else if (pressHandle == HANDLE_ROUND_SCROLL) { + float d = Δx / sw * videoScrollDuration; + moveRoundOffset(d); + dragged = true; + draggingProgress = false; } else if (draggingProgress) { setProgressAt(event.getX(), now - lastTime < 350); if (!dragged && delegate != null) { @@ -677,11 +973,33 @@ public boolean onTouchEvent(MotionEvent event) { boolean scrollStopped = true; if (event.getAction() == MotionEvent.ACTION_UP) { if (System.currentTimeMillis() - pressTime <= ViewConfiguration.getTapTimeout() && !dragged) { - if (!pressVideo && !audioSelected) { + if (pressType == 2 && !audioSelected) { audioSelected = true; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } invalidate(); - } else if (pressVideo && audioSelected) { + } else if (pressType == 1 && !roundSelected) { audioSelected = false; + roundSelected = true; + if (delegate != null) { + delegate.onRoundSelectChange(true); + } + invalidate(); + } else if (pressType != 2 && audioSelected) { + audioSelected = false; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } + invalidate(); + } else if (pressType != 1 && roundSelected) { + audioSelected = false; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } invalidate(); } else { long wasProgress = progress; @@ -714,6 +1032,9 @@ public boolean onTouchEvent(MotionEvent event) { if (hasVideo) { mx = (long) ((videoRight * videoDuration) - (0 * audioDuration)); mn = (long) ((videoLeft * videoDuration) - (1 * audioDuration)); + } else if (hasRound) { + mx = (long) ((roundRight * roundDuration) - (0 * audioDuration)); + mn = (long) ((roundLeft * roundDuration) - (1 * audioDuration)); } else { mx = 0; mn = (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION)); @@ -722,6 +1043,25 @@ public boolean onTouchEvent(MotionEvent event) { scroller.fling(wasScrollX = scrollX, 0, velocity, 0, (int) (px + ph + mn / (float) videoScrollDuration * sw), (int) (px + ph + mx / (float) videoScrollDuration * sw), 0, 0); scrollStopped = false; } + } else if ((pressHandle == HANDLE_ROUND_SCROLL || pressHandle == HANDLE_ROUND_REGION && !dragged) && roundSelected && velocityTracker != null) { + velocityTracker.computeCurrentVelocity(hasVideo ? 1000 : 1500); + final int velocity = (int) velocityTracker.getXVelocity(); + scrollingVideo = false; + if (Math.abs(velocity) > dp(100)) { + final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); + final int scrollX = (int) (px + ph + roundOffset / (float) videoScrollDuration * sw); + final long mx, mn; + if (hasVideo) { + mx = (long) ((videoRight * videoDuration) - (0 * roundDuration)); + mn = (long) ((videoLeft * videoDuration) - (1 * roundDuration)); + } else { + mx = 0; + mn = (long) -(roundDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION)); + } + scrolling = true; + scroller.fling(wasScrollX = scrollX, 0, velocity, 0, (int) (px + ph + mn / (float) videoScrollDuration * sw), (int) (px + ph + mx / (float) videoScrollDuration * sw), 0, 0); + scrollStopped = false; + } } } if (askExactSeek != null) { @@ -745,12 +1085,11 @@ public boolean onTouchEvent(MotionEvent event) { } private long minAudioSelect() { - return (long) Math.max(MIN_SELECT_DURATION, Math.min(hasVideo ? videoDuration : audioDuration, MAX_SELECT_DURATION) * 0.15f); + return (long) Math.max(MIN_SELECT_DURATION, Math.min(hasVideo ? videoDuration : (hasRound ? roundDuration : audioDuration), MAX_SELECT_DURATION) * 0.15f); } private void moveAudioOffset(final float d) { - final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); - if (!hasVideo) { + if (!hasVideo && !hasRound) { long wasAudioOffset = audioOffset; audioOffset = Utilities.clamp(audioOffset + (long) d, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); long rd = audioOffset - wasAudioOffset; @@ -761,14 +1100,17 @@ private void moveAudioOffset(final float d) { delegate.onAudioRightChange(audioRight); } } else if (audioSelected) { - long mx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); - final float wasDuration = Math.min(audioRight - audioLeft, (videoRight - videoLeft) * videoDuration / (float) audioDuration); + final float L = hasVideo ? videoLeft * videoDuration : roundLeft * roundDuration; + final float R = hasVideo ? videoRight * videoDuration : roundRight * roundDuration; + final float D = hasVideo ? (videoRight - videoLeft) * videoDuration : (roundRight - roundLeft) * roundDuration; + long mx = (long) (R - (audioRight * audioDuration)); + long mn = (long) (L - (audioLeft * audioDuration)); + final float wasDuration = Math.min(audioRight - audioLeft, D / (float) audioDuration); if (audioOffset + (long) d > mx) { - audioRight = Utilities.clamp((videoRight * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1, wasDuration); + audioRight = Utilities.clamp((R - audioOffset - (long) d) / (float) audioDuration, 1, wasDuration); audioLeft = Utilities.clamp(audioRight - wasDuration, 1, 0); - long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + long mmx = (long) (R - (audioRight * audioDuration)); + long mmn = (long) (L - (audioLeft * audioDuration)); if (mmx < mmn) { long t = mmx; mmx = mmn; @@ -780,10 +1122,10 @@ private void moveAudioOffset(final float d) { delegate.onAudioRightChange(audioRight); } } else if (audioOffset + (long) d < mn) { - audioLeft = Utilities.clamp((videoLeft * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1 - wasDuration, 0); + audioLeft = Utilities.clamp((L - audioOffset - (long) d) / (float) audioDuration, 1 - wasDuration, 0); audioRight = Utilities.clamp(audioLeft + wasDuration, 1, 0); - long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + long mmx = (long) (R - (audioRight * audioDuration)); + long mmn = (long) (L - (audioLeft * audioDuration)); if (mmx < mmn) { long t = mmx; mmx = mmn; @@ -810,6 +1152,8 @@ private void moveAudioOffset(final float d) { long progressToStart; if (hasVideo) { progressToStart = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else if (hasRound) { + progressToStart = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (roundRight * roundDuration), (long) (roundLeft * roundDuration)); } else { progressToStart = Utilities.clamp((long) (audioLeft * audioDuration), audioDuration, 0); } @@ -821,6 +1165,8 @@ private void moveAudioOffset(final float d) { } else if (dragged || scrolling) { if (hasVideo) { progress = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else if (hasRound) { + progress = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (roundRight * videoDuration), (long) (roundLeft * videoDuration)); } else { progress = Utilities.clamp((long) (audioLeft * audioDuration), audioDuration, 0); } @@ -830,6 +1176,87 @@ private void moveAudioOffset(final float d) { } } + private void moveRoundOffset(final float d) { + if (!hasVideo) { + long wasAudioOffset = roundOffset; + roundOffset = Utilities.clamp(roundOffset + (long) d, 0, (long) -(roundDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); + long rd = roundOffset - wasAudioOffset; + roundLeft = Utilities.clamp(roundLeft - (float) rd / roundDuration, 1, 0); + roundRight = Utilities.clamp(roundRight - (float) rd / roundDuration, 1, 0); + if (delegate != null) { + delegate.onAudioLeftChange(roundLeft); + delegate.onAudioRightChange(roundRight); + } + } else if (roundSelected) { + long mx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + final float wasDuration = Math.min(roundRight - roundLeft, (videoRight - videoLeft) * videoDuration / (float) roundDuration); + if (roundOffset + (long) d > mx) { + roundRight = Utilities.clamp((videoRight * videoDuration - roundOffset - (long) d) / (float) roundDuration, 1, wasDuration); + roundLeft = Utilities.clamp(roundRight - wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + roundOffset = Utilities.clamp(roundOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundRightChange(roundRight); + } + } else if (roundOffset + (long) d < mn) { + roundLeft = Utilities.clamp((videoLeft * videoDuration - roundOffset - (long) d) / (float) roundDuration, 1 - wasDuration, 0); + roundRight = Utilities.clamp(roundLeft + wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + roundOffset = Utilities.clamp(roundOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundRightChange(roundRight); + } + } else { + roundOffset += (long) d; + } + } else { + roundOffset = Utilities.clamp(roundOffset + (long) d, (long) (getBaseDuration() - roundDuration * roundRight), (long) (-roundLeft * roundDuration)); + } + invalidate(); + if (delegate != null) { + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + } + if (!dragged && delegate != null) { + delegate.onProgressDragChange(true); + + long progressToStart; + if (hasVideo) { + progressToStart = Utilities.clamp(roundOffset + (long) (roundLeft * roundDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else { + progressToStart = Utilities.clamp((long) (roundLeft * roundDuration), roundDuration, 0); + } + if (hasVideo && Math.abs(progress - progressToStart) > 400) { + loopProgressFrom = progress; + loopProgress.set(1, true); + } + delegate.onProgressChange(progress = progressToStart, false); + } else if (dragged || scrolling) { + if (hasVideo) { + progress = Utilities.clamp(roundOffset + (long) (roundLeft * roundDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else { + progress = Utilities.clamp((long) (roundLeft * roundDuration), roundDuration, 0); + } + if (delegate != null) { + delegate.onProgressChange(progress, false); + } + } + } + private int wasScrollX; @Override public void computeScroll() { @@ -837,15 +1264,12 @@ public void computeScroll() { int scrollX = scroller.getCurrX(); final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); if (scrollingVideo) { - long wasScroll = scroll; scroll = (long) Math.max(0, ((scrollX - px - ph) / (float) sw * videoScrollDuration)); -// videoLeft = Utilities.clamp(videoLeft + (scroll - wasScroll) / (float) videoDuration, 1, 0); -// videoRight = Utilities.clamp(videoRight + (scroll - wasScroll) / (float) videoDuration, 1, 0); -// if (delegate != null) { -// delegate.onVideoLeftChange(videoLeft); -// delegate.onVideoRightChange(videoRight); -// } } else { + if (!audioSelected) { + scroller.abortAnimation(); + return; + } final float d = ((scrollX - px - ph) / (float) sw * videoScrollDuration) - ((wasScrollX - px - ph) / (float) sw * videoScrollDuration); moveAudioOffset(d); } @@ -958,6 +1382,7 @@ protected void dispatchDraw(Canvas canvas) { final long scrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); float videoHeight = 0; float videoT = hasVideo ? 1 : 0; + float videoSelected = videoSelectedT.set(!audioSelected && !roundSelected); // draw video thumbs if (hasVideo) { @@ -975,7 +1400,7 @@ protected void dispatchDraw(Canvas canvas) { final int fromFrame = (int) Math.max(0, Math.floor((videoStartX - px) / frameWidth)); final int toFrame = (int) Math.min(thumbs.count, Math.ceil(((videoEndX - videoStartX) - px) / frameWidth) + 1); - final int y = (int) (h - py - videoHeight); + final int y = (int) videoBounds.top; boolean allLoaded = thumbs.frames.size() >= toFrame; boolean fullyCovered = allLoaded; @@ -1029,16 +1454,103 @@ protected void dispatchDraw(Canvas canvas) { canvas.restore(); } + final float p = dp(4); + float roundT = this.roundT.set(hasRound); + float roundSelected = this.roundSelectedT.set(hasRound && this.roundSelected); + final float roundHeight = getRoundHeight() * roundT; + if (roundT > 0) { + float left, right; + if (hasVideo) { + left = px + ph + (roundOffset - scroll + lerp(roundLeft, 0, roundSelected) * roundDuration) / (float) scrollDuration * sw; + right = px + ph + (roundOffset - scroll + lerp(roundRight, 1, roundSelected) * roundDuration) / (float) scrollDuration * sw; + } else { + left = px + ph + (roundOffset - scroll) / (float) scrollDuration * sw; + right = px + ph + (roundOffset - scroll + roundDuration) / (float) scrollDuration * sw; + } + + final float bottom = h - py - videoHeight - p * videoT; + roundBounds.set(left - ph, bottom - roundHeight, right + ph, bottom); + roundClipPath.rewind(); + roundClipPath.addRoundRect(roundBounds, dp(8), dp(8), Path.Direction.CW); + canvas.save(); + canvas.clipPath(roundClipPath); + if (roundThumbs != null) { + final float roundStartX = (roundDuration <= 0 ? 0 : px + ph + (roundOffset - scroll) / (float) scrollDuration * sw) - ph; + final float roundEndX = (roundDuration <= 0 ? 0 : px + ph + (roundOffset + roundDuration - scroll) / (float) scrollDuration * sw) + ph; + + float x = roundStartX; + final int frameWidth = roundThumbs.getFrameWidth(); + final float L; + if (hasVideo) { + L = px + ph + (roundOffset - scroll) / (float) scrollDuration * sw; + } else { + L = px; + } + final int fromFrame = (int) Math.max(0, Math.floor((roundStartX - L) / frameWidth)); + final int toFrame = (int) Math.min(roundThumbs.count, Math.ceil((roundEndX - roundStartX) / frameWidth) + 1); + + final int y = (int) roundBounds.top; + + boolean allLoaded = roundThumbs.frames.size() >= toFrame; + boolean fullyCovered = allLoaded; + if (fullyCovered) { + for (int i = fromFrame; i < Math.min(roundThumbs.frames.size(), toFrame); ++i) { + VideoThumbsLoader.BitmapFrame frame = roundThumbs.frames.get(i); + if (frame.bitmap == null) { + fullyCovered = false; + break; + } + } + } + + if (!fullyCovered) { + if (blurPaint == null) { + canvas.drawColor(0x40000000); + } else { + canvas.drawRect(roundBounds, blurPaint); + canvas.drawColor(0x33000000); + } + } + + for (int i = fromFrame; i < Math.min(roundThumbs.frames.size(), toFrame); ++i) { + VideoThumbsLoader.BitmapFrame frame = roundThumbs.frames.get(i); + if (frame.bitmap != null) { + videoFramePaint.setAlpha((int) (0xFF * frame.getAlpha())); + canvas.drawBitmap(frame.bitmap, x, y - (int) ((frame.bitmap.getHeight() - roundHeight) / 2f), videoFramePaint); + } + x += frameWidth; + } + + if (!allLoaded) { + roundThumbs.load(); + } + } + selectedVideoClipPath.rewind(); + AndroidUtilities.rectTmp.set( + px + ph + (roundLeft * roundDuration - scroll + roundOffset) / (float) scrollDuration * sw - (roundLeft <= 0 ? ph : 0) - ph * (1f - roundSelected), + roundBounds.top, + px + ph + (roundRight * roundDuration - scroll + roundOffset) / (float) scrollDuration * sw + (roundRight >= 1 ? ph : 0) + ph * (1f - roundSelected), + roundBounds.bottom + ); + selectedVideoClipPath.addRoundRect( + AndroidUtilities.rectTmp, + selectedVideoRadii, + Path.Direction.CW + ); + canvas.clipPath(selectedVideoClipPath, Region.Op.DIFFERENCE); + canvas.drawColor(0x50000000); + canvas.restore(); + } + // draw audio float audioT = this.audioT.set(hasAudio); float audioSelected = this.audioSelectedT.set(hasAudio && this.audioSelected); - final float p = dp(4); final float audioHeight = getAudioHeight() * audioT; if (audioT > 0) { final Paint audioBlurPaint = audioBlur.getPaint(audioT); canvas.save(); float left, right; - if (hasVideo) { + if (hasVideo || hasRound) { left = px + ph + (audioOffset - scroll + lerp(audioLeft, 0, audioSelected) * audioDuration) / (float) scrollDuration * sw; right = px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelected) * audioDuration) / (float) scrollDuration * sw; } else { @@ -1046,7 +1558,7 @@ protected void dispatchDraw(Canvas canvas) { right = px + ph + (audioOffset - scroll + audioDuration) / (float) scrollDuration * sw; } - final float bottom = h - py - videoHeight - p * videoT; + final float bottom = h - py - videoHeight - p * videoT - roundHeight - p * roundT; audioBounds.set(left - ph, bottom - audioHeight, right + ph, bottom); audioClipPath.rewind(); audioClipPath.addRoundRect(audioBounds, dp(8), dp(8), Path.Direction.CW); @@ -1128,16 +1640,31 @@ protected void dispatchDraw(Canvas canvas) { } // draw region - final float regionTop = lerp(h - py - videoHeight, h - py - videoHeight - p * videoT - audioHeight, hasVideo ? audioSelected : 1); - final float regionBottom = lerp(h - py, h - py - videoHeight - p * videoT, audioSelected); - final float left = lerp(videoLeft * videoDuration, audioOffset + audioLeft * audioDuration, hasVideo ? audioSelected : 1); - final float right = lerp(videoRight * videoDuration, audioOffset + audioRight * audioDuration, hasVideo ? audioSelected : 1); + final float audio = audioT * (hasVideo || hasRound ? audioSelected : 1); + final float round = roundT * (hasVideo || hasAudio ? roundSelected : 1); + final float video = videoSelected; + float regionTop = 0; + regionTop += (h - py - videoHeight - p * videoT - roundHeight - p * roundT - audioHeight) * audio; + regionTop += (h - py - videoHeight - p * videoT - roundHeight) * round; + regionTop += (h - py - videoHeight) * video; + float regionBottom = 0; + regionBottom += (h - py - videoHeight - p * videoT - roundHeight - p * roundT) * audio; + regionBottom += (h - py - videoHeight - p * videoT) * round; + regionBottom += (h - py) * video; + float left = 0; + left += (audioOffset + audioLeft * audioDuration) * audio; + left += (roundOffset + roundLeft * roundDuration) * round; + left += (videoLeft * videoDuration) * video; + float right = 0; + right += (audioOffset + audioRight * audioDuration) * audio; + right += (roundOffset + roundRight * roundDuration) * round; + right += (videoRight * videoDuration) * video; float leftX = px + ph + (left - scroll) / (float) scrollDuration * sw; float rightX = px + ph + (right - scroll) / (float) scrollDuration * sw; - float progressAlpha = (hasAudio && !hasVideo ? audioT : videoT); - if (audioT > 0. || videoT > 0.) { - drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, (hasVideo ? 1 : lerp(.6f, 1f, audioSelected) * audioT) * progressAlpha); - if (hasVideo && hasAudio && audioSelected > 0) { + float progressAlpha = (hasAudio && !hasVideo ? audioT : Math.max(videoT, roundT)); + if (audioT > 0. || roundT > 0. || videoT > 0.) { + drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, (hasVideo || hasRound ? 1 : lerp(.6f, 1f, audioSelected) * audioT) * progressAlpha); + if (hasVideo && (hasAudio || hasRound) && (audioSelected > 0 || roundSelected > 0)) { drawRegion( canvas, blurPaint, @@ -1151,10 +1678,20 @@ protected void dispatchDraw(Canvas canvas) { // draw progress float loopT = loopProgress.set(0); - final float y1 = h - py - videoHeight - (audioHeight + p * videoT) * audioT - dpf2(4.3f); + final float y1 = h - py - videoHeight - (audioHeight + p * Math.max(roundT, videoT)) * audioT - (roundHeight + p * videoT) * roundT - dpf2(4.3f); final float y2 = h - py + dpf2(4.3f); if (loopT > 0) { - drawProgress(canvas, y1, y2, loopProgressFrom != -1 ? loopProgressFrom : (long) (hasVideo ? videoDuration * videoRight : audioDuration * audioRight), loopT * progressAlpha); + final long end; + if (loopProgressFrom != -1) { + end = loopProgressFrom; + } else if (hasVideo) { + end = (long) (videoDuration * videoRight); + } else if (hasRound) { + end = (long) (roundDuration * roundRight); + } else { + end = (long) (audioDuration * audioRight); + } + drawProgress(canvas, y1, y2, end, loopT * progressAlpha); } drawProgress(canvas, y1, y2, progress, (1f - loopT) * progressAlpha); } @@ -1195,7 +1732,9 @@ protected void dispatchDraw(Canvas canvas) { long wasOffset = audioOffset; if (this.audioSelected && hasVideo) { audioOffset = Utilities.clamp(audioOffset - direction * Δd, (long) ((videoRight * videoDuration) - (audioLeft * audioDuration)), (long) ((videoLeft * videoDuration) - (audioRight * audioDuration))); - } else { + } else if (this.roundSelected && hasRound) { + audioOffset = Utilities.clamp(audioOffset - direction * Δd, (long) ((roundRight * roundDuration) - (audioLeft * audioDuration)), (long) ((roundLeft * roundDuration) - (audioRight * audioDuration))); + } else{ audioOffset = Utilities.clamp(audioOffset - direction * Δd, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); } float d = -(audioOffset - wasOffset) / (float) audioDuration; @@ -1284,6 +1823,10 @@ private void drawProgress(Canvas canvas, float y1, float y2, long progress, floa private int sw; private int w, h, ph, px, py; + public static int heightDp() { + return 5 + 38 + 4 + 28 + 4 + 28 + 5; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { audioAuthorPaint.setTextSize(dp(12)); @@ -1291,7 +1834,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { waveformRadii[0] = waveformRadii[1] = waveformRadii[2] = waveformRadii[3] = dp(2); waveformRadii[4] = waveformRadii[5] = waveformRadii[6] = waveformRadii[7] = 0; setPadding(px = dp(12), py = dp(5), dp(12), dp(5)); - setMeasuredDimension(w = MeasureSpec.getSize(widthMeasureSpec), h = dp(80)); + setMeasuredDimension(w = MeasureSpec.getSize(widthMeasureSpec), h = dp(heightDp())); ph = dp(10); sw = w - 2 * ph - 2 * px; if (videoPath != null && this.thumbs == null) { @@ -1316,7 +1859,11 @@ private class VideoThumbsLoader { private boolean destroyed; - public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { + public VideoThumbsLoader(String path, int uiWidth, int uiHeight, Long overrideDuration) { + this(path, uiWidth, uiHeight, overrideDuration, MAX_SCROLL_DURATION); + } + + public VideoThumbsLoader(String path, int uiWidth, int uiHeight, Long overrideDuration, long maxDuration) { metadataRetriever = new MediaMetadataRetriever(); long duration = MAX_SCROLL_DURATION; int width = 0; @@ -1349,6 +1896,9 @@ public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { metadataRetriever = null; FileLog.e(e); } + if (overrideDuration != null) { + this.duration = duration = overrideDuration; + } float aspectRatio = 1; if (width != 0 && height != 0) { aspectRatio = width / (float) height; @@ -1356,7 +1906,7 @@ public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { aspectRatio = Utilities.clamp(aspectRatio, 4 / 3f, 9f / 16f); frameHeight = Math.max(1, uiHeight); frameWidth = Math.max(1, (int) Math.ceil(uiHeight * aspectRatio)); - final float uiScrollWidth = Math.max(duration, MAX_SCROLL_DURATION) / (float) MAX_SCROLL_DURATION * uiWidth; + final float uiScrollWidth = Math.max(duration, maxDuration) / (float) maxDuration * uiWidth; count = (int) Math.ceil(uiScrollWidth / frameWidth); frameIterator = (long) (duration / (float) count); nextFrame = -frameIterator; @@ -1516,7 +2066,7 @@ public AudioWaveformLoader(String path, int uiWidth) { FileLog.e(e); } - final float videoScrollWidth = Math.min(hasVideo ? videoDuration : duration * 1000, MAX_SCROLL_DURATION); + final float videoScrollWidth = Math.min(hasVideo ? videoDuration : (hasRound ? roundDuration : duration * 1000), MAX_SCROLL_DURATION); final float uiScrollWidth = (duration * 1000) / videoScrollWidth * uiWidth; final int sampleWidth = Math.round(dpf2(3.3333f)); count = Math.round(uiScrollWidth / sampleWidth); @@ -1697,4 +2247,8 @@ public int getCount() { return count; } } + + public int getContentHeight() { + return (int) (py + (hasVideo ? getVideoHeight() + dp(4) : 0) + (hasRound ? getRoundHeight() + dp(4) : 0) + (hasAudio ? getAudioHeight() + dp(4) : 0) + py); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java b/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java index 9fa7630ba5..b1f5f1190a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java @@ -28,7 +28,7 @@ public class SuggestUserPhotoView extends View { public SuggestUserPhotoView(Context context) { super(context); - avatarDrawable.setInfo(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser()); + avatarDrawable.setInfo(UserConfig.selectedAccount, UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser()); currentPhoto.setForUserOrChat(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(), avatarDrawable); newPhoto.setForUserOrChat(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(), avatarDrawable); arrowDrawable = ContextCompat.getDrawable(context, R.drawable.msg_arrow_avatar); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index 717b8cacf3..cf2a6679c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -2206,7 +2206,7 @@ public boolean onInterceptTouchEvent(MotionEvent e) { view = new AppIconsSelectorCell(mContext, ThemeActivity.this, currentAccount); break; case TYPE_CHOOSE_COLOR: - view = new PeerColorActivity.ChangeNameColorCell(false, mContext, getResourceProvider()); + view = new PeerColorActivity.ChangeNameColorCell(currentAccount, false, mContext, getResourceProvider()); break; } return new RecyclerListView.Holder(view); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index d6b06b8437..6b22f3633a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -8,6 +8,9 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -16,20 +19,28 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Configuration; import android.database.DataSetObserver; import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -39,9 +50,14 @@ import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.os.SystemClock; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; +import android.util.StateSet; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; @@ -70,11 +86,13 @@ import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.DownloadController; +import org.telegram.messenger.Emoji; 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.LiteMode; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; @@ -87,6 +105,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.tgnet.ConnectionsManager; @@ -97,6 +116,7 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.MenuDrawable; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; @@ -110,37 +130,56 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.ColorPicker; +import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.GestureDetector2; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MotionBackgroundDrawable; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SeekBarView; import org.telegram.ui.Components.ShareAlert; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.UndoView; import org.telegram.ui.Components.WallpaperCheckBoxView; import org.telegram.ui.Components.WallpaperParallaxEffect; +import org.telegram.ui.Stories.recorder.SliderView; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class ThemePreviewActivity extends BaseFragment implements DownloadController.FileDownloadProgressListener, NotificationCenter.NotificationCenterDelegate { + public final ThemeDelegate themeDelegate = new ThemeDelegate(); + + @Override + public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + themeDelegate.parentProvider = resourceProvider; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return themeDelegate; + } + public static final int SCREEN_TYPE_PREVIEW = 0; public static final int SCREEN_TYPE_ACCENT_COLOR = 1; public static final int SCREEN_TYPE_CHANGE_BACKGROUND = 2; private static final int OPTION_DAY_NIGHT = 6; private static final int OPTION_PHOTO_EDIT = 7; - private static final int BRIGHTNESS_CONTROL_HEIGHT = 88; private final int screenType; private Scroller scroller; @@ -276,8 +315,8 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private Bitmap originalBitmap; private float parallaxScale = 1.0f; - private TextView bottomOverlayChatText; - private RadialProgressView buttonProgressView; + private BlurButton applyButton1; + private BlurButton applyButton2; private String loadingFile = null; private File loadingFileObject = null; @@ -299,16 +338,17 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private WallpaperActivityDelegate delegate; long dialogId; + boolean self = true; private boolean shouldShowDayNightIcon; private boolean shouldShowBrightnessControll; private RLottieDrawable sunDrawable; private ActionBarMenuItem dayNightItem; private float changeDayNightViewProgress; private ValueAnimator changeDayNightViewAnimator; - private HeaderCell dimmingHeaderCell; - private BrightnessControlCell brightnessControlCell; + private FrameLayout dimmingSliderContainer; + private SliderView dimmingSlider; - GestureDetector2 gestureDetector2 = new GestureDetector2(new GestureDetector2.OnGestureListener() { + GestureDetector2 gestureDetector2 = new GestureDetector2(getContext(), new GestureDetector2.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { if (scroller != null) { @@ -338,6 +378,7 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d scroller.abortAnimation(); } currentScrollOffset = Utilities.clamp(currentScrollOffset + distanceX, maxScrollOffset, 0); + invalidateBlur(); backgroundImage.invalidate(); return true; } @@ -425,9 +466,9 @@ public boolean isDark() { } @Override - public void switchDayNight() { + public void switchDayNight(boolean animated) { forceDark = !forceDark; - chatActivity.themeDelegate.setCurrentTheme(chatActivity.themeDelegate.getCurrentTheme(), chatActivity.themeDelegate.getCurrentWallpaper(), true, forceDark); + chatActivity.themeDelegate.setCurrentTheme(chatActivity.themeDelegate.getCurrentTheme(), chatActivity.themeDelegate.getCurrentWallpaper(), animated, forceDark); } }); chatActivity.presentFragment(wallpaperActivity); @@ -441,6 +482,7 @@ private void setCurrentServerWallpaper(MessageObject messageObject) { public void setDialogId(long dialogId) { this.dialogId = dialogId; + this.self = dialogId == 0 || dialogId == getUserConfig().getClientUserId(); } public void setOnSwitchDayNightDelegate(DayNightSwitchDelegate delegate) { @@ -576,7 +618,7 @@ public View createView(Context context) { } hintView.setBackgroundColor(0xea272f38, 0xffffffff); hintView.showForView(dayNightItem, true); - hintView.setExtraTranslationY(-AndroidUtilities.dp(14)); + hintView.setExtraTranslationY(-dp(14)); }, 2000); } @@ -647,7 +689,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { listView.setLayoutAnimation(null); listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); - listView.setPadding(0, 0, 0, AndroidUtilities.dp(screenType != SCREEN_TYPE_PREVIEW ? 12 : 0)); + listView.setPadding(0, 0, 0, dp(screenType != SCREEN_TYPE_PREVIEW ? 12 : 0)); listView.setOnItemClickListener((view, position) -> { }); @@ -656,12 +698,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { floatingButton = new ImageView(context); floatingButton.setScaleType(ImageView.ScaleType.CENTER); - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_chats_actionBackground), getThemedColor(Theme.key_chats_actionPressedBackground)); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(dp(56), getThemedColor(Theme.key_chats_actionBackground), getThemedColor(Theme.key_chats_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.SRC_IN)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + combinedDrawable.setIconSize(dp(56), dp(56)); drawable = combinedDrawable; } floatingButton.setBackgroundDrawable(drawable); @@ -669,14 +711,14 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { floatingButton.setImageResource(R.drawable.floating_pencil); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); - animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); - animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, dp(2), dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, dp(4), dp(2)).setDuration(200)); floatingButton.setStateListAnimator(animator); floatingButton.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + outline.setOval(0, 0, dp(56), dp(56)); } }); } @@ -718,17 +760,44 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView2.getLayoutParams(); layoutParams.topMargin = actionBarHeight; + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + } listView2.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize - layoutParams.bottomMargin, MeasureSpec.EXACTLY)); layoutParams = (FrameLayout.LayoutParams) backgroundImage.getLayoutParams(); layoutParams.topMargin = actionBarHeight; backgroundImage.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)); + if (dimmingSliderContainer != null) { + layoutParams = (FrameLayout.LayoutParams) dimmingSliderContainer.getLayoutParams(); + layoutParams.topMargin = actionBarHeight; + dimmingSliderContainer.measure( + MeasureSpec.makeMeasureSpec(dp(190 + 32), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(44 + 32), MeasureSpec.EXACTLY) + ); + } + if (bottomOverlayChat != null) { + bottomOverlayChat.setPadding(dp(12), dp(12), dp(12), dp(12) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + layoutParams = (FrameLayout.LayoutParams) bottomOverlayChat.getLayoutParams(); + layoutParams.height = dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); measureChildWithMargins(bottomOverlayChat, widthMeasureSpec, 0, heightMeasureSpec, 0); } + if (sheetDrawable != null) { + sheetDrawable.getPadding(AndroidUtilities.rectTmp2); + } for (int a = 0; a < patternLayout.length; a++) { if (patternLayout[a] != null) { + layoutParams = (FrameLayout.LayoutParams) patternLayout[a].getLayoutParams(); + layoutParams.height = dp(a == 0 ? (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 321 : 273) : 316); + if (insideBottomSheet()) { + layoutParams.height += AndroidUtilities.navigationBarHeight; + } + if (a == 0) { + layoutParams.height += dp(12) + AndroidUtilities.rectTmp2.top; + } + patternLayout[a].setPadding(0, a == 0 ? dp(12) + AndroidUtilities.rectTmp2.top : 0, 0, insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); measureChildWithMargins(patternLayout[a], widthMeasureSpec, 0, heightMeasureSpec, 0); } } @@ -868,14 +937,15 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } sunDrawable.start(); if (onSwitchDayNightDelegate != null) { - onSwitchDayNightDelegate.switchDayNight(); - - if (onSwitchDayNightDelegate.isDark() && shouldShowBrightnessControll) { - dimmingHeaderCell.setVisibility(View.VISIBLE); - brightnessControlCell.setVisibility(View.VISIBLE); - } + onSwitchDayNightDelegate.switchDayNight(true); } if (shouldShowBrightnessControll) { + if (onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { + dimmingSlider.setVisibility(View.VISIBLE); + dimmingSlider.animateValueTo(dimAmount); + } else { + dimmingSlider.animateValueTo(0); + } if (changeDayNightViewAnimator != null) { changeDayNightViewAnimator.removeAllListeners(); changeDayNightViewAnimator.cancel(); @@ -885,16 +955,15 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo progressToDarkTheme = (float) animation.getAnimatedValue(); backgroundImage.invalidate(); bottomOverlayChat.invalidate(); - dimmingHeaderCell.setAlpha(progressToDarkTheme); - brightnessControlCell.setAlpha(progressToDarkTheme); - listView2.setTranslationY(-AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * progressToDarkTheme); + dimmingSlider.setAlpha(progressToDarkTheme); + dimmingSliderContainer.invalidate(); + invalidateBlur(); }); changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (!onSwitchDayNightDelegate.isDark()) { - dimmingHeaderCell.setVisibility(View.GONE); - brightnessControlCell.setVisibility(View.GONE); + dimmingSlider.setVisibility(View.GONE); } } }); @@ -913,6 +982,7 @@ public void onAnimationEnd(Animator animation) { photoEntry.thumbPath = null; ArrayList arrayList = new ArrayList<>(); arrayList.add(photoEntry); + PhotoViewer.getInstance().setParentActivity(getParentActivity()); PhotoViewer.getInstance().openPhotoForSelect(arrayList, 0, PhotoViewer.SELECT_TYPE_WALLPAPER, false, new PhotoViewer.EmptyPhotoViewerProvider() { @Override public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, boolean forceDocument) { @@ -939,6 +1009,11 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea updateBlurred(); } } + + @Override + public boolean allowCaption() { + return false; + } }, null); // AndroidUtilities.runOnUIThread(() -> { // PhotoViewer.getInstance().switchToEditMode(PhotoViewer.EDIT_MODE_FILTER); @@ -959,31 +1034,18 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea backgroundImage.setVisibility(View.VISIBLE); backgroundImages[1].setVisibility(View.GONE); - if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { backgroundImage.getImageReceiver().setDelegate((imageReceiver, set, thumb, memCache) -> { if (!(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper)) { Drawable dr = imageReceiver.getDrawable(); if (set && dr != null) { - // if (!Theme.hasThemeKey(Theme.key_chat_serviceBackground) || backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { - Theme.applyChatServiceMessageColor(AndroidUtilities.calcDrawableColor(dr), dr); - // } - listView2.invalidateViews(); - if (backgroundButtonsContainer != null) { - for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { - backgroundButtonsContainer.getChildAt(a).invalidate(); - } - } - if (messagesButtonsContainer != null) { - for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { - messagesButtonsContainer.getChildAt(a).invalidate(); - } - } + themeDelegate.applyChatServiceMessageColor(AndroidUtilities.calcDrawableColor(dr), checkBlur(dr), dr, currentIntensity); if (!thumb && isBlurred && blurredBitmap == null) { backgroundImage.getImageReceiver().setCrossfadeWithOldImage(false); updateBlurred(); backgroundImage.getImageReceiver().setCrossfadeWithOldImage(true); } + invalidateBlur(); } } }); @@ -1007,10 +1069,10 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea } } if (dialogId == 0 && (BuildVars.DEBUG_PRIVATE_VERSION && Theme.getActiveTheme().getAccent(false) != null || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper && !Theme.DEFAULT_BACKGROUND_SLUG.equals(((WallpapersListActivity.ColorWallpaper) currentWallpaper).slug) || currentWallpaper instanceof TLRPC.TL_wallPaper)) { - menu2.addItem(5, R.drawable.msg_share_filled); + menu2.addItem(5, R.drawable.msg_header_share); } if (dialogId != 0 && shouldShowDayNightIcon) { - sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, AndroidUtilities.dp(28), AndroidUtilities.dp(28), true, null); + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); dayNightItem = menu2.addItem(OPTION_DAY_NIGHT, sunDrawable); sunDrawable.setPlayInDirectionOfCustomEndFrame(true); @@ -1062,8 +1124,8 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { Drawable dropDownDrawable = context.getResources().getDrawable(R.drawable.ic_arrow_drop_down).mutate(); dropDownDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultTitle), PorterDuff.Mode.MULTIPLY)); dropDown.setCompoundDrawablesWithIntrinsicBounds(null, null, dropDownDrawable, null); - dropDown.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - dropDown.setPadding(0, 0, AndroidUtilities.dp(10), 0); + dropDown.setCompoundDrawablePadding(dp(4)); + dropDown.setPadding(0, 0, dp(10), 0); dropDownContainer.addView(dropDown, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 0, 0, 1)); } else { String name = applyingTheme.info != null ? applyingTheme.info.title : applyingTheme.getName(); @@ -1098,7 +1160,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { nextPosition = p - 1; holder = listView2.findViewHolderForAdapterPosition(nextPosition); if (holder != null) { - imageReceiver.setImageY(-AndroidUtilities.dp(1000)); + imageReceiver.setImageY(-dp(1000)); imageReceiver.draw(canvas); return result; } @@ -1124,7 +1186,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { holder = listView2.findViewHolderForAdapterPosition(prevPosition); if (holder != null) { top = holder.itemView.getTop(); - if (y - AndroidUtilities.dp(48) < holder.itemView.getBottom()) { + if (y - dp(48) < holder.itemView.getBottom()) { tx = Math.min(holder.itemView.getTranslationX(), tx); } if (holder.itemView instanceof ChatMessageCell) { @@ -1141,14 +1203,14 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { } } } - if (y - AndroidUtilities.dp(48) < top) { - y = top + AndroidUtilities.dp(48); + if (y - dp(48) < top) { + y = top + dp(48); } if (tx != 0) { canvas.save(); canvas.translate(tx, 0); } - imageReceiver.setImageY(y - AndroidUtilities.dp(44)); + imageReceiver.setImageY(y - dp(44)); imageReceiver.draw(canvas); if (tx != 0) { canvas.restore(); @@ -1209,14 +1271,22 @@ public boolean onTouchEvent(MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { lastX = startX = e.getX(); lastY = startY = e.getY(); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + scrollingBackground = true; } else if (e.getAction() == MotionEvent.ACTION_MOVE) { if (!scrollingBackground && Math.abs(startX - e.getX()) > AndroidUtilities.touchSlop) { - getParent().requestDisallowInterceptTouchEvent(true); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } scrollingBackground = true; } } else if (e.getAction() == MotionEvent.ACTION_CANCEL || e.getAction() == MotionEvent.ACTION_UP) { scrollingBackground = false; - getParent().requestDisallowInterceptTouchEvent(false); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(false); + } } gestureDetector2.onTouchEvent(e); } @@ -1231,6 +1301,12 @@ private void checkMotionEvent(MotionEvent e) { wasScroll = false; } } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + invalidateBlur(); + } }; DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { @Override @@ -1243,11 +1319,11 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { listView2.setVerticalScrollBarEnabled(true); listView2.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4 + 48)); + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); } else if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(16)); + listView2.setPadding(0, dp(4), 0, dp(16)); } else { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4)); + listView2.setPadding(0, dp(4), 0, dp(4)); } listView2.setClipToPadding(false); listView2.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)); @@ -1305,376 +1381,163 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (screenType == SCREEN_TYPE_ACCENT_COLOR || screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { + final boolean drawShadow = insideBottomSheet(); bottomOverlayChat = new FrameLayout(context) { - final Paint dividerPaint = new Paint(); - final Paint backgroundPaint = new Paint(); - + + private LinearGradient gradient; + private int gradientHeight; + private final Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + { gradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + + private final ColorFilter colorFilter; + { + ColorMatrix colorMatrix = new ColorMatrix(); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.4f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.65f); + colorFilter = new ColorMatrixColorFilter(colorMatrix); + } + @Override protected void dispatchDraw(Canvas canvas) { - int offset = (int) (AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * (1f - progressToDarkTheme)); - int bottom = Theme.chat_composeShadowDrawable.getIntrinsicHeight(); - Theme.chat_composeShadowDrawable.setBounds(0, offset, getMeasuredWidth(), offset + bottom); - Theme.chat_composeShadowDrawable.draw(canvas); - backgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelBackground)); - canvas.drawRect(0, offset + bottom, getMeasuredWidth(), getMeasuredHeight(), backgroundPaint); - if (shouldShowBrightnessControll) { - dividerPaint.setColor(getThemedColor(Theme.key_divider)); - dividerPaint.setAlpha((int) (dividerPaint.getAlpha() * progressToDarkTheme)); - int y = getMeasuredHeight() - AndroidUtilities.dp(53); - canvas.drawRect(0, y, getMeasuredWidth(), y + 1, dividerPaint); - } - canvas.save(); - canvas.clipRect(0, offset, getMeasuredWidth(), getMeasuredHeight()); - super.dispatchDraw(canvas); - canvas.restore(); - } - }; - bottomOverlayChat.setWillNotDraw(false); - bottomOverlayChat.setPadding(0, AndroidUtilities.dp(3), 0, 0); - page2.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51 + BRIGHTNESS_CONTROL_HEIGHT, Gravity.BOTTOM)); - - - bottomOverlayChatText = new TextView(context); - bottomOverlayChatText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - bottomOverlayChatText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - bottomOverlayChatText.setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); - if (dialogId != 0) { - bottomOverlayChatText.setText(LocaleController.getString("ApplyBackgroundForThisChat", R.string.ApplyBackgroundForThisChat)); - } else { - bottomOverlayChatText.setText(LocaleController.getString("SetBackground", R.string.SetBackground)); - } - FrameLayout textContainer = new FrameLayout(getContext()); - - buttonProgressView = new RadialProgressView(getContext()); - buttonProgressView.setSize(AndroidUtilities.dp(18)); - textContainer.addView(buttonProgressView, LayoutHelper.createFrame(28, 28, Gravity.CENTER)); - textContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(0, Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_fieldOverlayText), (int) (0.3f * 255)))); - textContainer.addView(bottomOverlayChatText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); - bottomOverlayChat.addView(textContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.BOTTOM)); - textContainer.setOnClickListener(view -> { - boolean done; - boolean sameFile = false; - Theme.ThemeInfo theme = Theme.getActiveTheme(); - String originalFileName = theme.generateWallpaperName(null, isBlurred); - String fileName = isBlurred ? theme.generateWallpaperName(null, false) : originalFileName; - File toFile = new File(ApplicationLoader.getFilesDirFixed(), originalFileName); - if (currentWallpaper instanceof TLRPC.TL_wallPaper) { - if (originalBitmap != null) { - try { - FileOutputStream stream = new FileOutputStream(toFile); - originalBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Exception e) { - done = false; - FileLog.e(e); + if (drawShadow) { + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + final ColorFilter wasColorFilter = paint.getColorFilter(); + paint.setColorFilter(colorFilter); + float intensityDim = 1f; + if (backgroundImage != null && backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { + intensityDim = currentIntensity >= 0 ? 1f : .33f; } - } else { - ImageReceiver imageReceiver = backgroundImage.getImageReceiver(); - if (imageReceiver.hasNotThumb() || imageReceiver.hasStaticThumb()) { - Bitmap bitmap = imageReceiver.getBitmap(); - try { - FileOutputStream stream = new FileOutputStream(toFile); - bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } else { - done = false; + final int wasAlpha = paint.getAlpha(); + paint.setAlpha((int) (wasAlpha * intensityDim)); + canvas.drawRect(AndroidUtilities.rectTmp, paint); + paint.setAlpha(wasAlpha); + paint.setColorFilter(wasColorFilter); + + if (shouldShowBrightnessControll && dimAmount > 0) { + canvas.drawColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); } - } - if (!done) { - TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; - File f = FileLoader.getInstance(currentAccount).getPathToAttach(wallPaper.document, true); - try { - done = AndroidUtilities.copyFile(f, toFile); - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } - } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - if (selectedPattern != null) { - try { - WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - Bitmap bitmap = backgroundImage.getImageReceiver().getBitmap(); - @SuppressLint("DrawAllocation") - Bitmap dst = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(dst); - if (backgroundGradientColor2 != 0) { - - } else if (backgroundGradientColor1 != 0) { - GradientDrawable gradientDrawable = new GradientDrawable(BackgroundGradientDrawable.getGradientOrientation(backgroundRotation), new int[]{backgroundColor, backgroundGradientColor1}); - gradientDrawable.setBounds(0, 0, dst.getWidth(), dst.getHeight()); - gradientDrawable.draw(canvas); - } else { - canvas.drawColor(backgroundColor); - } - Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); - paint.setColorFilter(new PorterDuffColorFilter(patternColor, blendMode)); - paint.setAlpha((int) (255 * Math.abs(currentIntensity))); - canvas.drawBitmap(bitmap, 0, 0, paint); - - FileOutputStream stream = new FileOutputStream(toFile); - if (backgroundGradientColor2 != 0) { - dst.compress(Bitmap.CompressFormat.PNG, 100, stream); - } else { - dst.compress(Bitmap.CompressFormat.JPEG, 87, stream); - } - stream.close(); - done = true; - } catch (Throwable e) { - FileLog.e(e); - done = false; - } - } else { - done = true; - } - } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { - WallpapersListActivity.FileWallpaper wallpaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; - if (wallpaper.resId != 0 || Theme.THEME_BACKGROUND_SLUG.equals(wallpaper.slug)) { - done = true; - } else { - try { - File fromFile; - if (hasScrollingBackground && currentScrollOffset != defaultScrollOffset) { - Bitmap bitmap = Bitmap.createBitmap((int) croppedWidth, currentWallpaperBitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - float k = currentScrollOffset / (float) maxScrollOffset * (currentWallpaperBitmap.getWidth() - bitmap.getWidth()); - canvas.translate(-k, 0); - canvas.drawBitmap(currentWallpaperBitmap, 0, 0, null); - - wallpaper.path = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.random.nextInt() + ".jpg"); - FileOutputStream stream = new FileOutputStream(wallpaper.path); - bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - - stream.close(); - bitmap.recycle(); - - fromFile = wallpaper.path; - } else { - fromFile = wallpaper.originalPath != null ? wallpaper.originalPath : wallpaper.path; - } - if (sameFile = fromFile.equals(toFile)) { - done = true; - } else { - done = AndroidUtilities.copyFile(fromFile, toFile); - } - } catch (Exception e) { - done = false; - FileLog.e(e); + canvas.save(); + if (gradient == null || gradientHeight != getHeight()) { + gradient = new LinearGradient(0, 0, 0, gradientHeight = getHeight(), new int[]{0xffffffff, 0}, new float[]{0, 1f}, Shader.TileMode.CLAMP); + gradientPaint.setShader(gradient); } + canvas.drawRect(AndroidUtilities.rectTmp, gradientPaint); + canvas.restore(); + canvas.restore(); } - } else if (currentWallpaper instanceof MediaController.SearchImage) { - MediaController.SearchImage wallpaper = (MediaController.SearchImage) currentWallpaper; - File f; - if (wallpaper.photo != null) { - TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallpaper.photo.sizes, maxWallpaperSize, true); - f = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); - } else { - f = ImageLoader.getHttpFilePath(wallpaper.imageUrl, "jpg"); - } - try { - done = AndroidUtilities.copyFile(f, toFile); - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } else { - done = false; - } - if (isBlurred) { - try { - File blurredFile = new File(ApplicationLoader.getFilesDirFixed(), fileName); - FileOutputStream stream = new FileOutputStream(blurredFile); - blurredBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Throwable e) { - FileLog.e(e); - done = false; - } + + super.dispatchDraw(canvas); } - String slug; - int rotation = 45; - int color = 0; - int gradientColor1 = 0; - int gradientColor2 = 0; - int gradientColor3 = 0; - File path = null; - if (currentWallpaper instanceof TLRPC.TL_wallPaper) { - TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; - slug = wallPaper.slug; - } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - if (Theme.DEFAULT_BACKGROUND_SLUG.equals(wallPaper.slug)) { - slug = Theme.DEFAULT_BACKGROUND_SLUG; - color = 0; - } else { - if (selectedPattern != null) { - slug = selectedPattern.slug; - } else { - slug = Theme.COLOR_BACKGROUND_SLUG; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child.getMeasuredWidth() > dp(420)) { + child.measure(MeasureSpec.makeMeasureSpec(dp(420), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY)); } - color = backgroundColor; - gradientColor1 = backgroundGradientColor1; - gradientColor2 = backgroundGradientColor2; - gradientColor3 = backgroundGradientColor3; - rotation = backgroundRotation; - } - } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { - WallpapersListActivity.FileWallpaper wallPaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; - slug = wallPaper.slug; - path = wallPaper.path; - } else if (currentWallpaper instanceof MediaController.SearchImage) { - MediaController.SearchImage wallPaper = (MediaController.SearchImage) currentWallpaper; - if (wallPaper.photo != null) { - TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallPaper.photo.sizes, maxWallpaperSize, true); - path = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); - } else { - path = ImageLoader.getHttpFilePath(wallPaper.imageUrl, "jpg"); } - slug = ""; - } else { - color = 0; - slug = Theme.DEFAULT_BACKGROUND_SLUG; } + }; + bottomOverlayChat.setWillNotDraw(false); + bottomOverlayChat.setPadding(dp(12), dp(12), dp(12), dp(12) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + page2.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 0, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL)); - Theme.OverrideWallpaperInfo wallpaperInfo = new Theme.OverrideWallpaperInfo(); - wallpaperInfo.fileName = fileName; - wallpaperInfo.originalFileName = originalFileName; - wallpaperInfo.slug = slug; - wallpaperInfo.isBlurred = isBlurred; - wallpaperInfo.isMotion = isMotion; - wallpaperInfo.color = color; - wallpaperInfo.gradientColor1 = gradientColor1; - wallpaperInfo.gradientColor2 = gradientColor2; - wallpaperInfo.gradientColor3 = gradientColor3; - wallpaperInfo.rotation = rotation; - if (shouldShowBrightnessControll && dimAmount >= 0) { - wallpaperInfo.intensity = dimAmount; - } else { - wallpaperInfo.intensity = currentIntensity; - } - if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - WallpapersListActivity.ColorWallpaper colorWallpaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - String slugStr; - if (!Theme.COLOR_BACKGROUND_SLUG.equals(slug) && !Theme.THEME_BACKGROUND_SLUG.equals(slug) && !Theme.DEFAULT_BACKGROUND_SLUG.equals(slug)) { - slugStr = slug; - } else { - slugStr = null; - } - float intensity = colorWallpaper.intensity; - if (intensity < 0 && !Theme.getActiveTheme().isDark()) { - intensity *= -1; - } - if (colorWallpaper.parentWallpaper != null && colorWallpaper.color == color && - colorWallpaper.gradientColor1 == gradientColor1 && colorWallpaper.gradientColor2 == gradientColor2 && colorWallpaper.gradientColor3 == gradientColor3 && TextUtils.equals(colorWallpaper.slug, slugStr) && - colorWallpaper.gradientRotation == rotation && (selectedPattern == null || Math.abs(intensity - currentIntensity) < 0.001f)) { - wallpaperInfo.wallpaperId = colorWallpaper.parentWallpaper.id; - wallpaperInfo.accessHash = colorWallpaper.parentWallpaper.access_hash; - } - } - wallpaperInfo.dialogId = dialogId; - if (dialogId != 0) { - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); - if (userFull != null) { - wallpaperInfo.prevUserWallpaper = userFull.wallpaper; - } + applyButton1 = new BlurButton(context); + ScaleStateListAnimator.apply(applyButton1, 0.033f, 1.2f); + if (dialogId != 0) { + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaperForMe)); + } else { + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaper)); + } + applyButton1.setOnClickListener(view -> applyWallpaperBackground(false)); + + if (dialogId != 0 && !self && serverWallpaper == null) { + applyButton2 = new BlurButton(context); + ScaleStateListAnimator.apply(applyButton2, 0.033f, 1.2f); + TLRPC.User user = getMessagesController().getUser(dialogId); + SpannableStringBuilder text = new SpannableStringBuilder(""); + if (!getUserConfig().isPremium()) { + text.append("l "); + text.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock3), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - MessagesController.getInstance(currentAccount).saveWallpaperToServer(path, wallpaperInfo, slug != null && dialogId == 0, 0); - - boolean needFinishFragment = true; - if (done) { - if (dialogId != 0) { - needFinishFragment = false; - - if (path != null && getMessagesController().uploadingWallpaperInfo == wallpaperInfo) { - TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); - wallPaper.settings = new TLRPC.TL_wallPaperSettings(); - wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); - wallPaper.settings.blur = wallpaperInfo.isBlurred; - wallPaper.settings.motion = wallpaperInfo.isMotion; - wallPaper.uploadingImage = path.getAbsolutePath(); - Bitmap bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - float s = Math.max(50 / (float) backgroundImage.getMeasuredWidth(), 50 / (float) backgroundImage.getMeasuredHeight()); - canvas.scale(s, s); - if (backgroundImage.getMeasuredHeight() > backgroundImage.getMeasuredWidth()) { - canvas.translate(0, -(backgroundImage.getMeasuredHeight() - backgroundImage.getMeasuredWidth()) / 2f); - } else { - canvas.translate(-(backgroundImage.getMeasuredWidth() - backgroundImage.getMeasuredHeight()) / 2f, 0); - } - float currentDim = dimAmount; - dimAmount = 0; - backgroundImage.draw(canvas); - dimAmount = currentDim; - Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); - wallPaper.stripedThumb = bitmap; - - createServiceMessageLocal(wallPaper); - - TLRPC.UserFull fullUser = getMessagesController().getUserFull(dialogId); - if (fullUser != null) { - fullUser.wallpaper = wallPaper; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, fullUser); - } - } else { - ChatThemeController.getInstance(currentAccount).setWallpaperToUser(dialogId, null, wallpaperInfo, serverWallpaper, () -> { + text.append(LocaleController.formatString(R.string.ApplyWallpaperForMeAndPeer, UserObject.getUserName(user))); + applyButton2.setText(text); + try { + applyButton2.setText(Emoji.replaceEmoji(applyButton2.getText(), applyButton2.text.getFontMetricsInt(), false)); + } catch (Exception ignore) {} + applyButton2.setOnClickListener(view -> applyWallpaperBackground(true)); + bottomOverlayChat.addView(applyButton1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 48 + 10)); + bottomOverlayChat.addView(applyButton2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + } else { + bottomOverlayChat.addView(applyButton1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + } - }); - } - setupFinished = true; - if (delegate != null) { - delegate.didSetNewBackground(); - } - finishFragment(); - } else { - Theme.serviceMessageColorBackup = getThemedColor(Theme.key_chat_serviceBackground); - if (Theme.THEME_BACKGROUND_SLUG.equals(wallpaperInfo.slug)) { - wallpaperInfo = null; - } - Theme.getActiveTheme().setOverrideWallpaper(wallpaperInfo); - Theme.reloadWallpaper(true); - if (!sameFile) { - ImageLoader.getInstance().removeImage(ImageLoader.getHttpFileName(toFile.getAbsolutePath()) + "@100_100"); + if (shouldShowBrightnessControll) { + dimmingSliderContainer = new FrameLayout(getContext()) { + private final Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + @Override + protected void dispatchDraw(Canvas canvas) { + AndroidUtilities.rectTmp.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + final float r = dp(8); + + shadowPaint.setColor(0); + shadowPaint.setShadowLayer(dpf2(1), 0, dpf2(.33f), ColorUtils.setAlphaComponent(0xff000000, (int) (27 * dimmingSlider.getAlpha()))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, shadowPaint); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + final int wasAlpha1 = paint.getAlpha(); + paint.setAlpha((int) (wasAlpha1 * dimmingSlider.getAlpha())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, paint); + paint.setAlpha(wasAlpha1); + + if (shouldShowBrightnessControll && dimAmount > 0) { + dimPaint2.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint2); } - } - } - if (needFinishFragment) { - if (delegate != null) { - delegate.didSetNewBackground(); - } - finishFragment(); - } - }); - AndroidUtilities.updateViewVisibilityAnimated(buttonProgressView, false, 0.5f, false); - AndroidUtilities.updateViewVisibilityAnimated(bottomOverlayChatText, true, 0.8f, false); + dimPaint.setColor(0x1effffff); + dimPaint.setAlpha((int) (0x1e * dimmingSlider.getAlpha())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); - if (shouldShowBrightnessControll) { - dimmingHeaderCell = new HeaderCell(getContext(), getResourceProvider()); - dimmingHeaderCell.setText(LocaleController.getString("BackgroundDimming", R.string.BackgroundDimming)); - brightnessControlCell = new BrightnessControlCell(getContext(), BrightnessControlCell.TYPE_WALLPAPER_DIM, getResourceProvider()) { + super.dispatchDraw(canvas); + } + }; + dimmingSliderContainer.setPadding(dp(16), dp(16), dp(16), dp(16)); + page2.addView(dimmingSliderContainer, LayoutHelper.createFrame(190 + 32, 44 + 32, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); + + dimmingSlider = new SliderView(getContext(), SliderView.TYPE_DIMMING) { @Override - protected void didChangedValue(float value) { - dimAmount = value; - backgroundImage.invalidate(); + public boolean dispatchTouchEvent(MotionEvent event) { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return super.dispatchTouchEvent(event); } }; - brightnessControlCell.setProgress(dimAmount); - bottomOverlayChat.addView(dimmingHeaderCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); - bottomOverlayChat.addView(brightnessControlCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, BRIGHTNESS_CONTROL_HEIGHT, Gravity.BOTTOM, 0, 0, 0, 56)); + dimmingSlider.setValue(dimAmount); + dimmingSlider.setMinMax(0, .90f); + dimmingSlider.setOnValueChange(value -> { + dimAmount = value; + backgroundImage.invalidate(); + invalidateBlur(); + }); + dimmingSliderContainer.addView(dimmingSlider); if (onSwitchDayNightDelegate != null) { - dimmingHeaderCell.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); - brightnessControlCell.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); - listView2.setTranslationY(-AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * progressToDarkTheme); + dimmingSlider.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); + dimmingSlider.setAlpha(onSwitchDayNightDelegate.isDark() ? 1f : 0f); + dimmingSlider.setValue(onSwitchDayNightDelegate.isDark() ? dimAmount : 0); } } } @@ -1685,7 +1548,7 @@ protected void didChangedValue(float value) { sheetDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhite), PorterDuff.Mode.MULTIPLY)); TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - textPaint.setTextSize(AndroidUtilities.dp(14)); + textPaint.setTextSize(dp(14)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); { int textsCount; @@ -1730,10 +1593,10 @@ protected void didChangedValue(float value) { @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - Theme.applyServiceShaderMatrixForView(backgroundPlayAnimationView, backgroundImage); - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundPaint); + Theme.applyServiceShaderMatrixForView(backgroundPlayAnimationView, backgroundImage, themeDelegate); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackground)); if (Theme.hasGradientService()) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackgroundDarken)); } } }; @@ -1750,15 +1613,24 @@ protected void onDraw(Canvas canvas) { @Override public void onClick(View v) { - Drawable background = backgroundImage.getBackground(); backgroundPlayAnimationImageView.setRotation(rotation); rotation -= 45; backgroundPlayAnimationImageView.animate().rotationBy(-45).setDuration(300).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); - if (background instanceof MotionBackgroundDrawable) { - MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; - motionBackgroundDrawable.switchToNextPosition(); - } else { - onColorsRotate(); + if (backgroundImages[0] != null) { + Drawable background = backgroundImages[0].getBackground(); + if (background instanceof MotionBackgroundDrawable) { + MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; + motionBackgroundDrawable.switchToNextPosition(); + } else { + onColorsRotate(); + } + } + if (backgroundImages[1] != null) { + Drawable background = backgroundImages[1].getBackground(); + if (background instanceof MotionBackgroundDrawable) { + MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; + motionBackgroundDrawable.switchToNextPosition(); + } } } }); @@ -1771,7 +1643,7 @@ public void onClick(View v) { for (int a = 0; a < textsCount; a++) { final int num = a; - backgroundCheckBoxView[a] = new WallpaperCheckBoxView(context, screenType != SCREEN_TYPE_ACCENT_COLOR && !(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) || a != 0, backgroundImage, getResourceProvider()); + backgroundCheckBoxView[a] = new WallpaperCheckBoxView(context, screenType != SCREEN_TYPE_ACCENT_COLOR && !(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) || a != 0, backgroundImage, themeDelegate); backgroundCheckBoxView[a].setBackgroundColor(backgroundColor); backgroundCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); @@ -1784,20 +1656,20 @@ public void onClick(View v) { } else { backgroundCheckBoxView[a].setChecked(a == 0 ? isBlurred : isMotion, false); } - int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); + int width = maxTextSize + dp(14 * 2 + 28); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.gravity = Gravity.CENTER; if (textsCount == 3) { if (a == 0 || a == 2) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } } else { if (a == 1) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } } backgroundButtonsContainer.addView(backgroundCheckBoxView[a], layoutParams); @@ -1886,10 +1758,10 @@ public void onClick(View v) { @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - Theme.applyServiceShaderMatrixForView(messagesPlayAnimationView, backgroundImage); - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundPaint); + Theme.applyServiceShaderMatrixForView(messagesPlayAnimationView, backgroundImage, themeDelegate); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackground)); if (Theme.hasGradientService()) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackgroundDarken)); } } }; @@ -1948,19 +1820,19 @@ public void onClick(View v) { for (int a = 0; a < 2; a++) { final int num = a; - messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage, getResourceProvider()); + messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage, themeDelegate); messagesCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); if (a == 0) { messagesCheckBoxView[a].setChecked(accent.myMessagesAnimated, false); } - int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); + int width = maxTextSize + dp(14 * 2 + 28); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.gravity = Gravity.CENTER; if (a == 1) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); WallpaperCheckBoxView view = messagesCheckBoxView[a]; @@ -2007,10 +1879,15 @@ public void onDraw(Canvas canvas) { } else { layoutParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? 273 : 316, Gravity.LEFT | Gravity.BOTTOM); } + layoutParams.height = dp(a == 0 ? (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 321 : 273) : 316); + if (insideBottomSheet()) { + layoutParams.height += AndroidUtilities.navigationBarHeight; + } if (a == 0) { - layoutParams.height += AndroidUtilities.dp(12) + paddings.top; - patternLayout[a].setPadding(0, AndroidUtilities.dp(12) + paddings.top, 0, 0); + sheetDrawable.getPadding(AndroidUtilities.rectTmp2); + layoutParams.height += dp(12) + AndroidUtilities.rectTmp2.top; } + patternLayout[a].setPadding(0, a == 0 ? dp(12) + paddings.top : 0, 0, insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); page2.addView(patternLayout[a], layoutParams); if (a == 1 || screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { @@ -2027,7 +1904,7 @@ public void onDraw(Canvas canvas) { } }; patternsButtonsContainer[a].setWillNotDraw(false); - patternsButtonsContainer[a].setPadding(0, AndroidUtilities.dp(3), 0, 0); + patternsButtonsContainer[a].setPadding(0, dp(3), 0, 0); patternsButtonsContainer[a].setClickable(true); patternLayout[a].addView(patternsButtonsContainer[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); @@ -2037,7 +1914,7 @@ public void onDraw(Canvas canvas) { patternsCancelButton[a].setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); patternsCancelButton[a].setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); patternsCancelButton[a].setGravity(Gravity.CENTER); - patternsCancelButton[a].setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + patternsCancelButton[a].setPadding(dp(21), 0, dp(21), 0); patternsCancelButton[a].setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 0)); patternsButtonsContainer[a].addView(patternsCancelButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); patternsCancelButton[a].setOnClickListener(v -> { @@ -2086,7 +1963,7 @@ public void onDraw(Canvas canvas) { patternsSaveButton[a].setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); patternsSaveButton[a].setText(LocaleController.getString("ApplyTheme", R.string.ApplyTheme).toUpperCase()); patternsSaveButton[a].setGravity(Gravity.CENTER); - patternsSaveButton[a].setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + patternsSaveButton[a].setPadding(dp(21), 0, dp(21), 0); patternsSaveButton[a].setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 0)); patternsButtonsContainer[a].addView(patternsSaveButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.TOP)); patternsSaveButton[a].setOnClickListener(v -> { @@ -2110,7 +1987,7 @@ public void onDraw(Canvas canvas) { patternTitleView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); patternTitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); patternTitleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - patternTitleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(6), AndroidUtilities.dp(21), AndroidUtilities.dp(8)); + patternTitleView.setPadding(dp(21), dp(6), dp(21), dp(8)); patternTitleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); patternTitleView.setGravity(Gravity.CENTER_VERTICAL); @@ -2131,10 +2008,10 @@ public boolean onTouchEvent(MotionEvent event) { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); - outRect.left = AndroidUtilities.dp(12); + outRect.left = dp(12); outRect.bottom = outRect.top = 0; if (position == state.getItemCount() - 1) { - outRect.right = AndroidUtilities.dp(12); + outRect.right = dp(12); } } }); @@ -2152,7 +2029,7 @@ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, Recycle int left = view.getLeft(); int right = view.getRight(); - int extra = AndroidUtilities.dp(52); + int extra = dp(52); if (left - extra < 0) { patternsListView.smoothScrollBy(left - extra, 0); } else if (right + extra > patternsListView.getMeasuredWidth()) { @@ -2387,14 +2264,14 @@ public void unregisterDataSetObserver(DataSetObserver observer) { frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, screenType == SCREEN_TYPE_PREVIEW ? 48 : 0)); undoView = new UndoView(context, this); - undoView.setAdditionalTranslationY(AndroidUtilities.dp(51)); + undoView.setAdditionalTranslationY(dp(51)); frameLayout.addView(undoView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 8, 0, 8, 8)); if (screenType == SCREEN_TYPE_PREVIEW) { View shadow = new View(context); shadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM); - layoutParams.bottomMargin = AndroidUtilities.dp(48); + layoutParams.bottomMargin = dp(48); frameLayout.addView(shadow, layoutParams); saveButtonsContainer = new FrameLayout(context); @@ -2411,7 +2288,7 @@ protected void onDraw(Canvas canvas) { paint.setColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); for (int a = 0; a < 2; a++) { paint.setAlpha(a == selected ? 255 : 127); - canvas.drawCircle(AndroidUtilities.dp(3 + 15 * a), AndroidUtilities.dp(4), AndroidUtilities.dp(3), paint); + canvas.drawCircle(dp(3 + 15 * a), dp(4), dp(3), paint); } } }; @@ -2422,7 +2299,7 @@ protected void onDraw(Canvas canvas) { cancelButton.setTextColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); cancelButton.setGravity(Gravity.CENTER); cancelButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); - cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + cancelButton.setPadding(dp(29), 0, dp(29), 0); cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); saveButtonsContainer.addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); @@ -2433,7 +2310,7 @@ protected void onDraw(Canvas canvas) { doneButton.setTextColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); doneButton.setGravity(Gravity.CENTER); doneButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); - doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + doneButton.setPadding(dp(29), 0, dp(29), 0); doneButton.setText(LocaleController.getString("ApplyTheme", R.string.ApplyTheme).toUpperCase()); doneButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); saveButtonsContainer.addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); @@ -2487,11 +2364,18 @@ protected void onDraw(Canvas canvas) { if (parentLayout != null && parentLayout.getBottomSheet() != null) { parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } } return fragmentView; } + public boolean insideBottomSheet() { + return parentLayout != null && parentLayout.getBottomSheet() != null; + } + private void updateIntensity() { backgroundImage.getImageReceiver().setAlpha(Math.abs(currentIntensity)); backgroundImage.invalidate(); @@ -2510,11 +2394,317 @@ private void updateIntensity() { backgroundImage.getImageReceiver().setGradientBitmap(motionBackgroundDrawable.getBitmap()); } } + themeDelegate.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); + invalidateBlur(); } - private void showProgress() { - AndroidUtilities.updateViewVisibilityAnimated(buttonProgressView, true, 0.5f, true); - AndroidUtilities.updateViewVisibilityAnimated(bottomOverlayChatText, false, 0.8f, true); + private void applyWallpaperBackground(boolean forBoth) { + if (!getUserConfig().isPremium() && forBoth) { + showDialog(new PremiumFeatureBottomSheet(this, PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER, true)); + return; + } + + boolean done; + boolean sameFile = false; + Theme.ThemeInfo theme = Theme.getActiveTheme(); + String originalFileName = theme.generateWallpaperName(null, isBlurred); + String fileName = isBlurred ? theme.generateWallpaperName(null, false) : originalFileName; + File toFile = new File(ApplicationLoader.getFilesDirFixed(), originalFileName); + if (currentWallpaper instanceof TLRPC.TL_wallPaper) { + if (originalBitmap != null) { + try { + FileOutputStream stream = new FileOutputStream(toFile); + originalBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + ImageReceiver imageReceiver = backgroundImage.getImageReceiver(); + if (imageReceiver.hasNotThumb() || imageReceiver.hasStaticThumb()) { + Bitmap bitmap = imageReceiver.getBitmap(); + try { + FileOutputStream stream = new FileOutputStream(toFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + done = false; + } + } + + if (!done) { + TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; + File f = FileLoader.getInstance(currentAccount).getPathToAttach(wallPaper.document, true); + try { + done = AndroidUtilities.copyFile(f, toFile); + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } + } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + if (selectedPattern != null) { + try { + WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; + Bitmap bitmap = backgroundImage.getImageReceiver().getBitmap(); + @SuppressLint("DrawAllocation") + Bitmap dst = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(dst); + if (backgroundGradientColor2 != 0) { + + } else if (backgroundGradientColor1 != 0) { + GradientDrawable gradientDrawable = new GradientDrawable(BackgroundGradientDrawable.getGradientOrientation(backgroundRotation), new int[]{backgroundColor, backgroundGradientColor1}); + gradientDrawable.setBounds(0, 0, dst.getWidth(), dst.getHeight()); + gradientDrawable.draw(canvas); + } else { + canvas.drawColor(backgroundColor); + } + Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); + paint.setColorFilter(new PorterDuffColorFilter(patternColor, blendMode)); + paint.setAlpha((int) (255 * Math.abs(currentIntensity))); + canvas.drawBitmap(bitmap, 0, 0, paint); + + FileOutputStream stream = new FileOutputStream(toFile); + if (backgroundGradientColor2 != 0) { + dst.compress(Bitmap.CompressFormat.PNG, 100, stream); + } else { + dst.compress(Bitmap.CompressFormat.JPEG, 87, stream); + } + stream.close(); + done = true; + } catch (Throwable e) { + FileLog.e(e); + done = false; + } + } else { + done = true; + } + } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { + WallpapersListActivity.FileWallpaper wallpaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; + if (wallpaper.resId != 0 || Theme.THEME_BACKGROUND_SLUG.equals(wallpaper.slug)) { + done = true; + } else { + try { + File fromFile; + if (hasScrollingBackground && currentScrollOffset != defaultScrollOffset) { + Bitmap bitmap = Bitmap.createBitmap((int) croppedWidth, currentWallpaperBitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + float k = currentScrollOffset / (float) maxScrollOffset * (currentWallpaperBitmap.getWidth() - bitmap.getWidth()); + canvas.translate(-k, 0); + canvas.drawBitmap(currentWallpaperBitmap, 0, 0, null); + + wallpaper.path = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.random.nextInt() + ".jpg"); + FileOutputStream stream = new FileOutputStream(wallpaper.path); + bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + + stream.close(); + bitmap.recycle(); + + fromFile = wallpaper.path; + } else { + fromFile = wallpaper.originalPath != null ? wallpaper.originalPath : wallpaper.path; + } + if (sameFile = fromFile.equals(toFile)) { + done = true; + } else { + done = AndroidUtilities.copyFile(fromFile, toFile); + } + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } + } else if (currentWallpaper instanceof MediaController.SearchImage) { + MediaController.SearchImage wallpaper = (MediaController.SearchImage) currentWallpaper; + File f; + if (wallpaper.photo != null) { + TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallpaper.photo.sizes, maxWallpaperSize, true); + f = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); + } else { + f = ImageLoader.getHttpFilePath(wallpaper.imageUrl, "jpg"); + } + try { + done = AndroidUtilities.copyFile(f, toFile); + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + done = false; + } + if (isBlurred) { + try { + File blurredFile = new File(ApplicationLoader.getFilesDirFixed(), fileName); + FileOutputStream stream = new FileOutputStream(blurredFile); + blurredBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Throwable e) { + FileLog.e(e); + done = false; + } + } + String slug; + int rotation = 45; + int color = 0; + int gradientColor1 = 0; + int gradientColor2 = 0; + int gradientColor3 = 0; + File path = null; + + if (currentWallpaper instanceof TLRPC.TL_wallPaper) { + TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; + slug = wallPaper.slug; + } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; + if (Theme.DEFAULT_BACKGROUND_SLUG.equals(wallPaper.slug)) { + slug = Theme.DEFAULT_BACKGROUND_SLUG; + color = 0; + } else { + if (selectedPattern != null) { + slug = selectedPattern.slug; + } else { + slug = Theme.COLOR_BACKGROUND_SLUG; + } + color = backgroundColor; + gradientColor1 = backgroundGradientColor1; + gradientColor2 = backgroundGradientColor2; + gradientColor3 = backgroundGradientColor3; + rotation = backgroundRotation; + } + } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { + WallpapersListActivity.FileWallpaper wallPaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; + slug = wallPaper.slug; + path = wallPaper.path; + } else if (currentWallpaper instanceof MediaController.SearchImage) { + MediaController.SearchImage wallPaper = (MediaController.SearchImage) currentWallpaper; + if (wallPaper.photo != null) { + TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallPaper.photo.sizes, maxWallpaperSize, true); + path = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); + } else { + path = ImageLoader.getHttpFilePath(wallPaper.imageUrl, "jpg"); + } + slug = ""; + } else { + color = 0; + slug = Theme.DEFAULT_BACKGROUND_SLUG; + } + + Theme.OverrideWallpaperInfo wallpaperInfo = new Theme.OverrideWallpaperInfo(); + wallpaperInfo.fileName = fileName; + wallpaperInfo.originalFileName = originalFileName; + wallpaperInfo.slug = slug; + wallpaperInfo.isBlurred = isBlurred; + wallpaperInfo.isMotion = isMotion; + wallpaperInfo.color = color; + wallpaperInfo.gradientColor1 = gradientColor1; + wallpaperInfo.gradientColor2 = gradientColor2; + wallpaperInfo.gradientColor3 = gradientColor3; + wallpaperInfo.rotation = rotation; + if (shouldShowBrightnessControll && dimAmount >= 0) { + wallpaperInfo.intensity = dimAmount; + } else { + wallpaperInfo.intensity = currentIntensity; + } + if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + WallpapersListActivity.ColorWallpaper colorWallpaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; + String slugStr; + if (!Theme.COLOR_BACKGROUND_SLUG.equals(slug) && !Theme.THEME_BACKGROUND_SLUG.equals(slug) && !Theme.DEFAULT_BACKGROUND_SLUG.equals(slug)) { + slugStr = slug; + } else { + slugStr = null; + } + float intensity = colorWallpaper.intensity; + if (intensity < 0 && !Theme.getActiveTheme().isDark()) { + intensity *= -1; + } + if (colorWallpaper.parentWallpaper != null && colorWallpaper.color == color && + colorWallpaper.gradientColor1 == gradientColor1 && colorWallpaper.gradientColor2 == gradientColor2 && colorWallpaper.gradientColor3 == gradientColor3 && TextUtils.equals(colorWallpaper.slug, slugStr) && + colorWallpaper.gradientRotation == rotation && (selectedPattern == null || Math.abs(intensity - currentIntensity) < 0.001f)) { + wallpaperInfo.wallpaperId = colorWallpaper.parentWallpaper.id; + wallpaperInfo.accessHash = colorWallpaper.parentWallpaper.access_hash; + } + } + wallpaperInfo.dialogId = dialogId; + if (dialogId != 0) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + wallpaperInfo.prevUserWallpaper = userFull.wallpaper; + } + } + wallpaperInfo.forBoth = forBoth; + MessagesController.getInstance(currentAccount).saveWallpaperToServer(path, wallpaperInfo, slug != null && dialogId == 0, 0); + + boolean needFinishFragment = true; + if (done) { + if (dialogId != 0) { + needFinishFragment = false; + + if (path != null && getMessagesController().uploadingWallpaperInfo == wallpaperInfo) { + TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); + wallPaper.settings = new TLRPC.TL_wallPaperSettings(); + wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); + wallPaper.settings.blur = wallpaperInfo.isBlurred; + wallPaper.settings.motion = wallpaperInfo.isMotion; + wallPaper.uploadingImage = path.getAbsolutePath(); + Bitmap bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + float s = Math.max(50 / (float) backgroundImage.getMeasuredWidth(), 50 / (float) backgroundImage.getMeasuredHeight()); + canvas.scale(s, s); + if (backgroundImage.getMeasuredHeight() > backgroundImage.getMeasuredWidth()) { + canvas.translate(0, -(backgroundImage.getMeasuredHeight() - backgroundImage.getMeasuredWidth()) / 2f); + } else { + canvas.translate(-(backgroundImage.getMeasuredWidth() - backgroundImage.getMeasuredHeight()) / 2f, 0); + } + float currentDim = dimAmount; + dimAmount = 0; + backgroundImage.draw(canvas); + dimAmount = currentDim; + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + wallPaper.stripedThumb = bitmap; + + createServiceMessageLocal(wallPaper, forBoth); + + TLRPC.UserFull fullUser = getMessagesController().getUserFull(dialogId); + if (fullUser != null) { + fullUser.wallpaper = wallPaper; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, fullUser); + } + } else { + ChatThemeController.getInstance(currentAccount).setWallpaperToUser(dialogId, null, wallpaperInfo, serverWallpaper, () -> { + + }); + } + setupFinished = true; + if (delegate != null) { + delegate.didSetNewBackground(); + } + finishFragment(); + } else { + Theme.serviceMessageColorBackup = getThemedColor(Theme.key_chat_serviceBackground); + if (Theme.THEME_BACKGROUND_SLUG.equals(wallpaperInfo.slug)) { + wallpaperInfo = null; + } + Theme.getActiveTheme().setOverrideWallpaper(wallpaperInfo); + Theme.reloadWallpaper(true); + if (!sameFile) { + ImageLoader.getInstance().removeImage(ImageLoader.getHttpFileName(toFile.getAbsolutePath()) + "@100_100"); + } + } + } + if (needFinishFragment) { + if (delegate != null) { + delegate.didSetNewBackground(); + } + finishFragment(); + } } private void onColorsRotate() { @@ -2685,7 +2875,7 @@ private void selectColorType(int id, boolean ask) { } else { messagesAdapter.notifyItemChanged(0); } - listView2.smoothScrollBy(0, AndroidUtilities.dp(60)); + listView2.smoothScrollBy(0, dp(60)); break; } case 3: { @@ -2720,7 +2910,7 @@ private void selectColorType(int id, boolean ask) { } else if (prevType == 2) { messagesAdapter.notifyItemRemoved(0); } - listView2.smoothScrollBy(0, AndroidUtilities.dp(60)); + listView2.smoothScrollBy(0, dp(60)); showAnimationHint(); break; } @@ -3019,7 +3209,7 @@ public void onFragmentDestroy() { blurredBitmap.recycle(); blurredBitmap = null; } - Theme.applyChatServiceMessageColor(); + themeDelegate.applyChatServiceMessageColor(); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); } else if (screenType == SCREEN_TYPE_ACCENT_COLOR || screenType == SCREEN_TYPE_PREVIEW) { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); @@ -3030,6 +3220,115 @@ public void onFragmentDestroy() { } super.onFragmentDestroy(); + checkBlur(null); + } + + private WeakReference lastDrawableToBlur; + private BitmapDrawable blurredDrawable; + private BitmapDrawable checkBlur(Drawable d) { + if (lastDrawableToBlur != null && lastDrawableToBlur.get() == d) { + return blurredDrawable; + } + if (lastDrawableToBlur != null) { + lastDrawableToBlur.clear(); + } + lastDrawableToBlur = null; + if (d == null || d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) { + return blurredDrawable = null; + } + lastDrawableToBlur = new WeakReference<>(d); + + final int h = 24; + final int w = (int) ((float) d.getIntrinsicWidth() / d.getIntrinsicHeight() * h); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + d.setBounds(0, 0, w, h); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + final ColorFilter wasColorFilter = d.getColorFilter(); + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(1.3f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .94f); + d.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + d.draw(new Canvas(bitmap)); + d.setColorFilter(wasColorFilter); + } else { + d.draw(new Canvas(bitmap)); + } + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + blurredDrawable = new BitmapDrawable(getContext().getResources(), bitmap); + blurredDrawable.setFilterBitmap(true); + return blurredDrawable; + } + + private void invalidateBlur() { + if (dimmingSliderContainer != null) { + dimmingSliderContainer.invalidate(); + } + if (backgroundButtonsContainer != null) { + for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { + backgroundButtonsContainer.getChildAt(a).invalidate(); + } + } + if (messagesButtonsContainer != null) { + for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { + messagesButtonsContainer.getChildAt(a).invalidate(); + } + } + if (backgroundCheckBoxView != null) { + for (int i = 0; i < backgroundCheckBoxView.length; ++i) { + if (backgroundCheckBoxView[i] != null) { + backgroundCheckBoxView[i].setDimAmount(shouldShowBrightnessControll ? dimAmount * progressToDarkTheme : 0); + backgroundCheckBoxView[i].invalidate(); + } + } + } + if (listView != null) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child instanceof ChatActionCell) { + setVisiblePart((ChatActionCell) child); + child.invalidate(); + } + } + } + if (listView2 != null) { + for (int i = 0; i < listView2.getChildCount(); ++i) { + View child = listView2.getChildAt(i); + if (child instanceof ChatActionCell) { + setVisiblePart((ChatActionCell) child); + child.invalidate(); + } + } + } + if (applyButton1 != null) { + applyButton1.invalidate(); + } + if (applyButton2 != null) { + applyButton2.invalidate(); + } + if (bottomOverlayChat != null) { + bottomOverlayChat.invalidate(); + } + } + + private void setVisiblePart(ChatActionCell cell) { + if (backgroundImage == null) { + return; + } + float tx = 0; + float ty = 0; + if (backgroundImage != null) { + if (themeDelegate.serviceBitmap != null) { + float bitmapWidth = themeDelegate.serviceBitmap.getWidth(); + float bitmapHeight = themeDelegate.serviceBitmap.getHeight(); + float maxScale = Math.max(backgroundImage.getMeasuredWidth() / bitmapWidth, backgroundImage.getMeasuredHeight() / bitmapHeight); + float width = bitmapWidth * maxScale; + tx += ((backgroundImage.getMeasuredWidth() - width) / 2) + currentScrollOffset; + } else { + tx += currentScrollOffset; + } + ty += -backgroundImage.ty; + } + cell.setVisiblePart(cell.getY() - ty, tx, backgroundImage.getMeasuredHeight(), shouldShowBrightnessControll ? dimAmount * progressToDarkTheme : 0); } @Override @@ -3037,12 +3336,23 @@ public void onTransitionAnimationStart(boolean isOpen, boolean backward) { super.onTransitionAnimationStart(isOpen, backward); if (!isOpen) { if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - Theme.applyChatServiceMessageColor(); + themeDelegate.applyChatServiceMessageColor(); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); } } } + @Override + public void onBottomSheetCreated() { + super.onBottomSheetCreated(); + if (parentLayout != null && parentLayout.getBottomSheet() != null) { + parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } + } + } + @Override public void onResume() { super.onResume(); @@ -3069,7 +3379,13 @@ public void onPause() { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - return false; + if (screenType != SCREEN_TYPE_CHANGE_BACKGROUND) { + return false; + } + if (hasScrollingBackground && event != null && event.getY() > AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight()) { + return false; + } + return true; } @Override @@ -3171,12 +3487,12 @@ public void didReceivedNotification(int id, int account, Object... args) { patterns.add(wallPaper); patternsDict.put(wallPaper.document.id, wallPaper); } - if (accent != null && accent.patternSlug.equals(wallPaper.slug)) { + if (accent != null && accent.patternSlug != null && accent.patternSlug.equals(wallPaper.slug)) { selectedPattern = (TLRPC.TL_wallPaper) wallPaper; added = true; setCurrentImage(false); updateButtonState(false, false); - } else if (accent == null && selectedPattern != null && selectedPattern.slug.equals(wallPaper.slug)) { + } else if (accent == null && selectedPattern != null && selectedPattern.slug != null && selectedPattern.slug.equals(wallPaper.slug)) { added = true; } } @@ -3212,12 +3528,12 @@ public void didReceivedNotification(int id, int account, Object... args) { patterns.add(wallPaper); patternsDict.put(wallPaper.document.id, wallPaper); } - if (accent != null && accent.patternSlug.equals(wallPaper.slug)) { + if (accent != null && accent.patternSlug != null && accent.patternSlug.equals(wallPaper.slug)) { selectedPattern = wallPaper; added2 = true; setCurrentImage(false); updateButtonState(false, false); - } else if (accent == null && selectedPattern != null && selectedPattern.slug.equals(wallPaper.slug)) { + } else if (accent == null && selectedPattern != null && selectedPattern.slug != null && selectedPattern.slug.equals(wallPaper.slug)) { added2 = true; } } @@ -3535,7 +3851,12 @@ private void updateButtonState(boolean ifSame, boolean animated) { doneButton.setAlpha(fileExists ? 1.0f : 0.5f); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { bottomOverlayChat.setEnabled(fileExists); - bottomOverlayChatText.setAlpha(fileExists ? 1.0f : 0.5f); + if (applyButton1 != null) { + applyButton1.setAlpha(fileExists ? 1.0f : 0.5f); + } + if (applyButton2 != null) { + applyButton2.setAlpha(fileExists ? 1.0f : 0.5f); + } } else { saveItem.setEnabled(fileExists); saveItem.setAlpha(fileExists ? 1.0f : 0.5f); @@ -3578,7 +3899,7 @@ private void showAnimationHint() { animationHint.setAlpha(0); animationHint.setVisibility(View.INVISIBLE); animationHint.setText(LocaleController.getString("BackgroundAnimateInfo", R.string.BackgroundAnimateInfo)); - animationHint.setExtraTranslationY(AndroidUtilities.dp(6)); + animationHint.setExtraTranslationY(dp(6)); frameLayout.addView(animationHint, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); } AndroidUtilities.runOnUIThread(() -> { @@ -3633,7 +3954,7 @@ public void onAnimationEnd(Animator animation) { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) backgroundCheckBoxView[1].getLayoutParams(); AnimatorSet animatorSet = new AnimatorSet(); - int offset = (layoutParams.width + AndroidUtilities.dp(9)) / 2; + int offset = (layoutParams.width + dp(9)) / 2; animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, selectedPattern != null ? 1.0f : 0.0f)); animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, selectedPattern != null ? 0.0f : offset)); animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, selectedPattern != null ? 0.0f : -offset)); @@ -3688,7 +4009,7 @@ private void showPatternsView(int num, boolean show, boolean animated) { } else { index = patterns.indexOf(selectedPattern) + (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 1 : 0); } - patternsLayoutManager.scrollToPositionWithOffset(index, (patternsListView.getMeasuredWidth() - AndroidUtilities.dp(100 + 24)) / 2); + patternsLayoutManager.scrollToPositionWithOffset(index, (patternsListView.getMeasuredWidth() - dp(100 + 24)) / 2); } } } @@ -3706,7 +4027,7 @@ private void showPatternsView(int num, boolean show, boolean animated) { if (show) { patternLayout[num].setVisibility(View.VISIBLE); if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, num == 1 ? -AndroidUtilities.dp(21) : 0)); + animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, num == 1 ? -dp(21) : 0)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.ALPHA, showMotion ? 1.0f : 0.0f)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, showMotion ? 0.0f : 1.0f)); if (num == 1) { @@ -3717,10 +4038,10 @@ private void showPatternsView(int num, boolean show, boolean animated) { } colorPicker.hideKeyboard(); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, -patternLayout[num].getMeasuredHeight() + AndroidUtilities.dp(48))); + animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, -patternLayout[num].getMeasuredHeight() + dp(12 + 48 + 12 + (applyButton2 != null ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0))); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.ALPHA, showMotion ? 1.0f : 0.0f)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, showMotion ? 0.0f : 1.0f)); - animators.add(ObjectAnimator.ofFloat(backgroundImage, View.ALPHA, 0.0f)); +// animators.add(ObjectAnimator.ofFloat(backgroundImage, View.ALPHA, 0.0f)); if (patternLayout[otherNum].getVisibility() == View.VISIBLE) { animators.add(ObjectAnimator.ofFloat(patternLayout[otherNum], View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(patternLayout[num], View.ALPHA, 0.0f, 1.0f)); @@ -3772,7 +4093,7 @@ public void onAnimationEnd(Animator animation) { if (show) { patternLayout[num].setVisibility(View.VISIBLE); if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - listView2.setTranslationY(num == 1 ? -AndroidUtilities.dp(21) : 0); + listView2.setTranslationY(num == 1 ? -dp(21) : 0); backgroundCheckBoxView[2].setAlpha(showMotion ? 1.0f : 0.0f); backgroundCheckBoxView[0].setAlpha(showMotion ? 0.0f : 1.0f); if (num == 1) { @@ -3783,10 +4104,10 @@ public void onAnimationEnd(Animator animation) { } colorPicker.hideKeyboard(); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setTranslationY(-AndroidUtilities.dp(num == 0 ? 343 : 316) + AndroidUtilities.dp(48)); + listView2.setTranslationY(-dp(num == 0 ? 343 : 316) + dp(48 + 12 + 12 + (applyButton2 != null ? 10 + 48 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); backgroundCheckBoxView[2].setAlpha(showMotion ? 1.0f : 0.0f); backgroundCheckBoxView[0].setAlpha(showMotion ? 0.0f : 1.0f); - backgroundImage.setAlpha(0.0f); +// backgroundImage.setAlpha(0.0f); if (patternLayout[otherNum].getVisibility() == View.VISIBLE) { patternLayout[otherNum].setAlpha(0.0f); patternLayout[num].setAlpha(1.0f); @@ -3914,9 +4235,9 @@ private void updatePlayAnimationView(boolean animated) { ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.ALPHA, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.SCALE_X, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.SCALE_Y, visible ? 1.0f : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, visible ? -AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f)); + ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, visible ? dp(34) : 0.0f), + ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, visible ? -dp(34) : 0.0f), + ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.TRANSLATION_X, visible ? dp(34) : 0.0f)); backgroundPlayViewAnimator.setDuration(180); backgroundPlayViewAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -3933,9 +4254,9 @@ public void onAnimationEnd(Animator animation) { backgroundPlayAnimationView.setAlpha(visible ? 1.0f : 0.0f); backgroundPlayAnimationView.setScaleX(visible ? 1.0f : 0.0f); backgroundPlayAnimationView.setScaleY(visible ? 1.0f : 0.0f); - backgroundCheckBoxView[0].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); - backgroundCheckBoxView[1].setTranslationX(visible ? -AndroidUtilities.dp(34) : 0.0f); - backgroundCheckBoxView[2].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); + backgroundCheckBoxView[0].setTranslationX(visible ? dp(34) : 0.0f); + backgroundCheckBoxView[1].setTranslationX(visible ? -dp(34) : 0.0f); + backgroundCheckBoxView[2].setTranslationX(visible ? dp(34) : 0.0f); } } } @@ -3956,8 +4277,8 @@ public void onAnimationEnd(Animator animation) { ObjectAnimator.ofFloat(messagesPlayAnimationView, View.ALPHA, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(messagesPlayAnimationView, View.SCALE_X, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(messagesPlayAnimationView, View.SCALE_Y, visible ? 1.0f : 0.0f), - ObjectAnimator.ofFloat(messagesCheckBoxView[0], View.TRANSLATION_X, visible ? -AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(messagesCheckBoxView[1], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f)); + ObjectAnimator.ofFloat(messagesCheckBoxView[0], View.TRANSLATION_X, visible ? -dp(34) : 0.0f), + ObjectAnimator.ofFloat(messagesCheckBoxView[1], View.TRANSLATION_X, visible ? dp(34) : 0.0f)); messagesPlayViewAnimator.setDuration(180); messagesPlayViewAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -3974,8 +4295,8 @@ public void onAnimationEnd(Animator animation) { messagesPlayAnimationView.setAlpha(visible ? 1.0f : 0.0f); messagesPlayAnimationView.setScaleX(visible ? 1.0f : 0.0f); messagesPlayAnimationView.setScaleY(visible ? 1.0f : 0.0f); - messagesCheckBoxView[0].setTranslationX(visible ? -AndroidUtilities.dp(34) : 0.0f); - messagesCheckBoxView[1].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); + messagesCheckBoxView[0].setTranslationX(visible ? -dp(34) : 0.0f); + messagesCheckBoxView[1].setTranslationX(visible ? dp(34) : 0.0f); } } } @@ -4027,10 +4348,10 @@ private void setBackgroundColor(int color, int num, boolean applyNow, boolean an patternColor = checkColor = AndroidUtilities.getPatternColor(backgroundColor); } if (!Theme.hasThemeKey(Theme.key_chat_serviceBackground) || backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { - Theme.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground()); + themeDelegate.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); } else if (Theme.getCachedWallpaperNonBlocking() instanceof MotionBackgroundDrawable) { int c = getThemedColor(Theme.key_chat_serviceBackground); - Theme.applyChatServiceMessageColor(new int[]{c, c, c, c}, backgroundImage.getBackground()); + themeDelegate.applyChatServiceMessageColor(new int[]{c, c, c, c}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); } if (backgroundPlayAnimationImageView != null) { backgroundPlayAnimationImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_serviceText), PorterDuff.Mode.MULTIPLY)); @@ -4081,7 +4402,11 @@ private void setCurrentImage(boolean setThumb) { if (currentWallpaper instanceof TLRPC.TL_wallPaper) { TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; TLRPC.PhotoSize thumb = setThumb ? FileLoader.getClosestPhotoSizeWithSize(wallPaper.document.thumbs, 100) : null; - backgroundImage.setImage(ImageLocation.getForDocument(wallPaper.document), imageFilter, ImageLocation.getForDocument(thumb, wallPaper.document), "100_100_b", "jpg", wallPaper.document.size, 1, wallPaper); + Drawable thumbDrawable = null; + if (thumb instanceof TLRPC.TL_photoStrippedSize) { + thumbDrawable = new BitmapDrawable(ImageLoader.getStrippedPhotoBitmap(thumb.bytes, "b")); + } + backgroundImage.setImage(ImageLocation.getForDocument(wallPaper.document), imageFilter, ImageLocation.getForDocument(thumb, wallPaper.document), "100_100_b", thumbDrawable, "jpg", wallPaper.document.size, 1, wallPaper); } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; backgroundRotation = wallPaper.gradientRotation; @@ -4258,16 +4583,7 @@ public void onSizeReady(int width, int height) { if (messagesPlayAnimationImageView != null) { messagesPlayAnimationImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_serviceText), PorterDuff.Mode.MULTIPLY)); } - if (backgroundButtonsContainer != null) { - for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { - backgroundButtonsContainer.getChildAt(a).invalidate(); - } - } - if (messagesButtonsContainer != null) { - for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { - messagesButtonsContainer.getChildAt(a).invalidate(); - } - } + invalidateBlur(); } rotatePreview = false; } @@ -4902,7 +5218,7 @@ public void applyServiceShaderMatrix(int w, int h, float translationX, float tra }); } else if (viewType == 1) { - view = new ChatActionCell(mContext); + view = new ChatActionCell(mContext, false, themeDelegate); ((ChatActionCell) view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { }); @@ -4913,7 +5229,7 @@ public void applyServiceShaderMatrix(int w, int h, float translationX, float tra FrameLayout frameLayout = new FrameLayout(mContext) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(60), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(60), MeasureSpec.EXACTLY)); } }; frameLayout.addView(backgroundButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 76, Gravity.CENTER)); @@ -4922,7 +5238,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(4), MeasureSpec.EXACTLY)); } }; } else { @@ -4932,7 +5248,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { FrameLayout frameLayout = new FrameLayout(mContext) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(60), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(60), MeasureSpec.EXACTLY)); } }; frameLayout.addView(messagesButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 76, Gravity.CENTER)); @@ -4978,6 +5294,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ChatActionCell actionCell = (ChatActionCell) view; actionCell.setMessageObject(message); actionCell.setAlpha(1.0f); + invalidateBlur(); } } } @@ -5138,13 +5455,12 @@ public ArrayList getThemeDescriptionsInternal() { if (bottomOverlayChat != null) { bottomOverlayChat.invalidate(); } - if (brightnessControlCell != null) { - brightnessControlCell.invalidate(); - brightnessControlCell.seekBarView.invalidate(); - } if (onSwitchDayNightDelegate != null) { if (parentLayout != null && parentLayout.getBottomSheet() != null) { parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } } else { setNavigationBarColor(getThemedColor(Theme.key_dialogBackground)); } @@ -5219,7 +5535,6 @@ public ArrayList getThemeDescriptionsInternal() { items.add(new ThemeDescription(bottomOverlayChat, 0, null, null, new Drawable[]{Theme.chat_composeShadowDrawable}, null, Theme.key_chat_messagePanelShadow)); items.add(new ThemeDescription(bottomOverlayChat, 0, null, Theme.chat_composeBackgroundPaint, null, null, Theme.key_chat_messagePanelBackground)); - items.add(new ThemeDescription(bottomOverlayChatText, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_fieldOverlayText)); for (int a = 0; a < patternsSaveButton.length; a++) { items.add(new ThemeDescription(patternsSaveButton[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_fieldOverlayText)); @@ -5264,7 +5579,6 @@ public ArrayList getThemeDescriptionsInternal() { items.add(new ThemeDescription(listView2, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inTimeSelectedText)); items.add(new ThemeDescription(listView2, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outTimeSelectedText)); } - items.add(new ThemeDescription(dimmingHeaderCell, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_divider)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_dialogBackground)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_windowBackgroundWhiteBlackText)); @@ -5287,7 +5601,7 @@ public ArrayList getThemeDescriptions() { } } - private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { + private void createServiceMessageLocal(TLRPC.WallPaper wallPaper, boolean forBoth) { TLRPC.TL_messageService message = new TLRPC.TL_messageService(); message.random_id = SendMessagesHelper.getInstance(currentAccount).getNextRandomId(); @@ -5304,6 +5618,7 @@ private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { TLRPC.TL_messageActionSetChatWallPaper setChatWallPaper = new TLRPC.TL_messageActionSetChatWallPaper(); message.action = setChatWallPaper; setChatWallPaper.wallpaper = wallPaper; + setChatWallPaper.for_both = forBoth; ArrayList objArr = new ArrayList<>(); objArr.add(new MessageObject(currentAccount, message, false, false)); @@ -5316,12 +5631,12 @@ private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { public interface DayNightSwitchDelegate { boolean isDark(); - void switchDayNight(); + void switchDayNight(boolean animated); } - private class BackgroundView extends BackupImageView { + public class BackgroundView extends BackupImageView { - private Drawable background; + public Drawable background; boolean drawBackground = true; public BackgroundView(Context context) { @@ -5351,6 +5666,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { maxScrollOffset = currentScrollOffset * 2f; setSize(scaledWidth, getMeasuredHeight()); drawFromStart = true; + invalidateBlur(); } } if (!hasScrollingBackground) { @@ -5361,8 +5677,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { lastSizeHash = sizeHash; } + public float tx, ty; + @Override protected void onDraw(Canvas canvas) { + tx = 0; + ty = 0; if (drawBackground) { if (background instanceof ColorDrawable || background instanceof GradientDrawable || background instanceof MotionBackgroundDrawable) { background.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -5385,6 +5705,7 @@ protected void onDraw(Canvas canvas) { int height = (int) Math.ceil(background.getIntrinsicHeight() * scale * parallaxScale); int x = (getMeasuredWidth() - width) / 2; int y = (viewHeight - height) / 2; + ty = y; background.setBounds(x, y, x + width, y + height); background.draw(canvas); } @@ -5396,17 +5717,19 @@ protected void onDraw(Canvas canvas) { if (scroller.getStartX() < maxScrollOffset && scroller.getStartX() > 0) { currentScrollOffset = scroller.getCurrX(); } + invalidateBlur(); invalidate(); } } canvas.save(); + tx = -currentScrollOffset; canvas.translate(-currentScrollOffset, 0); super.onDraw(canvas); canvas.restore(); } else { super.onDraw(canvas); } - if (shouldShowBrightnessControll && dimAmount > 0 && onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { + if (shouldShowBrightnessControll && dimAmount > 0) { canvas.drawColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); } } @@ -5443,4 +5766,290 @@ public void setTop(int top, int backgroundWidth, int backgroundHeight, int heigh super.setTop(top, backgroundWidth, backgroundHeight, heightOffset, blurredViewTopOffset, blurredViewBottomOffset, topNear, bottomNear); } } + + private class BlurButton extends View { + + private Text text; + private final Drawable rippleDrawable = Theme.createRadSelectorDrawable(0x10ffffff, 8, 8); + private final ColorFilter colorFilter; + + public BlurButton(Context context) { + super(context); + rippleDrawable.setCallback(this); + + ColorMatrix colorMatrix = new ColorMatrix(); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.35f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.75f); + colorFilter = new ColorMatrixColorFilter(colorMatrix); + } + + public void setText(CharSequence text) { + this.text = new Text(text, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + + public CharSequence getText() { + return this.text != null ? this.text.getText() : null; + } + + private CircularProgressDrawable loadingDrawable; + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void onDraw(Canvas canvas) { + final float r = dp(8); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + + final ColorFilter wasColorFilter = paint.getColorFilter(); + paint.setColorFilter(colorFilter); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, paint); + paint.setColorFilter(wasColorFilter); + + if (shouldShowBrightnessControll && dimAmount > 0) { + dimPaint2.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint2); + } + + dimPaint.setColor(0x1effffff); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + + final int textColor = Color.WHITE; + + if (loadingT > 0) { + if (loadingDrawable == null) { + loadingDrawable = new CircularProgressDrawable(textColor); + } + int y = (int) ((1f - loadingT) * dp(-24)); + loadingDrawable.setBounds(0, y, getWidth(), y + getHeight()); + loadingDrawable.setAlpha((int) (0xFF * loadingT)); + loadingDrawable.draw(canvas); + invalidate(); + } + + if (loadingT < 1 && text != null) { + text + .ellipsize(getWidth() - dp(14)) + .draw(canvas, (getWidth() - text.getWidth()) / 2f, getHeight() / 2f + loadingT * dp(24), textColor, 1f - loadingT); + } + + rippleDrawable.setBounds(0, 0, getWidth(), getHeight()); + rippleDrawable.draw(canvas); + } + + + private float loadingT = 0; + private boolean loading; + private ValueAnimator loadingAnimator; + public void setLoading(boolean loading) { + if (this.loading != loading) { + if (loadingAnimator != null) { + loadingAnimator.cancel(); + loadingAnimator = null; + } + + loadingAnimator = ValueAnimator.ofFloat(loadingT, (this.loading = loading) ? 1 : 0); + loadingAnimator.addUpdateListener(anm -> { + loadingT = (float) anm.getAnimatedValue(); + invalidate(); + }); + loadingAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + loadingT = loading ? 1 : 0; + invalidate(); + } + }); + loadingAnimator.setDuration(320); + loadingAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + loadingAnimator.start(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean r = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + r = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + rippleDrawable.setHotspot(event.getX(), event.getY()); + } + rippleDrawable.setState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}); + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + rippleDrawable.setState(StateSet.NOTHING); + } + return super.onTouchEvent(event) || r; + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == rippleDrawable || super.verifyDrawable(who); + } + } + + public static class ThemeDelegate implements Theme.ResourcesProvider { + + public Theme.ResourcesProvider parentProvider; + + private final SparseIntArray currentColors = new SparseIntArray(); + + public final Paint chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + + public final TextPaint chat_actionTextPaint = new TextPaint(); + public final TextPaint chat_actionTextPaint2 = new TextPaint(); + public final TextPaint chat_botButtonPaint = new TextPaint(); + + private Bitmap serviceBitmap; + public BitmapShader serviceBitmapShader; + private Matrix serviceBitmapMatrix; + public int serviceMessageColorBackup; + public int serviceSelectedMessageColorBackup; + + public ThemeDelegate() { + chat_actionTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_actionTextPaint2.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_botButtonPaint.setTextSize(AndroidUtilities.dp(15)); + chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); + } + + @Override + public int getColor(int key) { + if (parentProvider != null) { + return parentProvider.getColor(key); + } + return Theme.getColor(key); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (parentProvider != null) { + return parentProvider.getDrawable(drawableKey); + } + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public int getCurrentColor(int key) { + if (parentProvider != null) { + return parentProvider.getCurrentColor(key); + } + return Theme.ResourcesProvider.super.getCurrentColor(key); + } + + @Override + public Paint getPaint(String paintKey) { + switch (paintKey) { + case Theme.key_paint_chatActionBackground: return chat_actionBackgroundPaint; + case Theme.key_paint_chatActionBackgroundSelected: return chat_actionBackgroundSelectedPaint; + case Theme.key_paint_chatActionBackgroundDarken: return chat_actionBackgroundGradientDarkenPaint; + case Theme.key_paint_chatActionText: return chat_actionTextPaint; + case Theme.key_paint_chatActionText2: return chat_actionTextPaint2; + case Theme.key_paint_chatBotButton: return chat_botButtonPaint; + } + if (parentProvider != null) { + return parentProvider.getPaint(paintKey); + } + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public boolean hasGradientService() { + if (parentProvider != null) { + return parentProvider.hasGradientService(); + } + return Theme.hasGradientService(); + } + + public void applyChatServiceMessageColor() { + applyChatServiceMessageColor(null, null, null, null); + } + + public void applyChatServiceMessageColor(int[] custom, Drawable wallpaperOverride, Drawable currentWallpaper, Float overrideIntensity) { + int serviceColor = getColor(Theme.key_chat_serviceBackground); + int servicePressedColor = getColor(Theme.key_chat_serviceBackgroundSelected); + Drawable drawable = wallpaperOverride != null ? wallpaperOverride : currentWallpaper; + boolean drawServiceGradient = (drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); + if (drawServiceGradient) { + Bitmap newBitmap = null; + if (drawable instanceof MotionBackgroundDrawable) { + newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + } else if (drawable instanceof BitmapDrawable) { + newBitmap = ((BitmapDrawable) drawable).getBitmap(); + } + if (serviceBitmap != newBitmap) { + serviceBitmap = newBitmap; + serviceBitmapShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (serviceBitmapMatrix == null) { + serviceBitmapMatrix = new Matrix(); + } + } + chat_actionTextPaint.setColor(0xffffffff); + chat_actionTextPaint2.setColor(0xffffffff); + chat_actionTextPaint.linkColor = 0xffffffff; + chat_botButtonPaint.setColor(0xffffffff); + } else { + serviceBitmap = null; + serviceBitmapShader = null; + chat_actionTextPaint.setColor(getColor(Theme.key_chat_serviceText)); + chat_actionTextPaint2.setColor(getColor(Theme.key_chat_serviceText)); + chat_actionTextPaint.linkColor = getColor(Theme.key_chat_serviceLink); + } + + chat_actionBackgroundPaint.setColor(serviceColor); + chat_actionBackgroundSelectedPaint.setColor(servicePressedColor); + + if (serviceBitmapShader != null && (currentColors.indexOfKey(Theme.key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable)) { + ColorMatrix colorMatrix = new ColorMatrix(); + if (drawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); + if (overrideIntensity != null) { + intensity = overrideIntensity; + } + if (intensity >= 0) { + colorMatrix.setSaturation(1.8f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .97f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.03f); + } else { + colorMatrix.setSaturation(0.5f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .35f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.03f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .97f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.06f); + } + + chat_actionBackgroundPaint.setShader(serviceBitmapShader); + chat_actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + chat_actionBackgroundPaint.setAlpha(0xff); + + chat_actionBackgroundSelectedPaint.setShader(serviceBitmapShader); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .85f); + chat_actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + chat_actionBackgroundSelectedPaint.setAlpha(0xff); + } else { + chat_actionBackgroundPaint.setColorFilter(null); + chat_actionBackgroundPaint.setShader(null); + chat_actionBackgroundSelectedPaint.setColorFilter(null); + chat_actionBackgroundSelectedPaint.setShader(null); + } + } + + @Override + public void applyServiceShaderMatrix(int w, int h, float translationX, float translationY) { + if (/*backgroundDrawable == null || */serviceBitmap == null || serviceBitmapShader == null) { + Theme.ResourcesProvider.super.applyServiceShaderMatrix(w, h, translationX, translationY); + } else { + Theme.applyServiceShaderMatrix(serviceBitmap, serviceBitmapShader, serviceBitmapMatrix, w, h, translationX, translationY); + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 0bc4c2fd0a..6d164451fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -52,8 +52,6 @@ import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -132,6 +130,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.concurrent.CountDownLatch; import tw.nekomimi.nekogram.BackButtonMenuRecent; import tw.nekomimi.nekogram.NekoConfig; @@ -196,6 +195,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private static final int show_id = 13; private boolean removeFragmentOnTransitionEnd; + private boolean finishDialogRightSlidingPreviewOnTransitionEnd; TLRPC.ChatFull chatFull; boolean canShowCreateTopic; private UnreadCounterTextView bottomOverlayChatText; @@ -292,6 +292,32 @@ public TopicsFragment(Bundle bundle) { canShowProgress = !getUserConfig().getPreferences().getBoolean("topics_end_reached_" + chatId, false); } + public static BaseFragment getTopicsOrChat(BaseFragment parentFragment, Bundle args) { + return getTopicsOrChat(parentFragment.getMessagesController(), parentFragment.getMessagesStorage(), args); + } + + public static BaseFragment getTopicsOrChat(LaunchActivity launchActivity, Bundle args) { + return getTopicsOrChat(MessagesController.getInstance(launchActivity.currentAccount), MessagesStorage.getInstance(launchActivity.currentAccount), args); + } + + private static BaseFragment getTopicsOrChat(MessagesController messagesController, MessagesStorage messagesStorage, Bundle args) { + long chatId = args.getLong("chat_id"); + if (chatId != 0L) { + TLRPC.Dialog dialog = messagesController.getDialog(-chatId); + if (dialog != null && dialog.view_forum_as_messages) { + return new ChatActivity(args); + } + TLRPC.ChatFull chatFull = messagesController.getChatFull(chatId); + if (chatFull == null) { + chatFull = messagesStorage.loadChatInfo(chatId, true, new CountDownLatch(1), false, false); + } + if (chatFull != null && chatFull.view_forum_as_messages) { + return new ChatActivity(args); + } + } + return new TopicsFragment(args); + } + public static void prepareToSwitchAnimation(ChatActivity chatActivity) { if (chatActivity.getParentLayout() == null) { return; @@ -512,7 +538,13 @@ public void onItemClick(int id) { TLRPC.TL_forumTopic topic; switch (id) { case toggle_id: - switchToChat(false); + getMessagesController().getTopicsController().toggleViewForumAsMessages(chatId, true); + finishDialogRightSlidingPreviewOnTransitionEnd = true; + Bundle bundle = new Bundle(); + bundle.putLong("chat_id", chatId); + ChatActivity chatActivity = new ChatActivity(bundle); + chatActivity.setSwitchFromTopics(true); + presentFragment(chatActivity); break; case add_member_id: TLRPC.ChatFull chatFull = getMessagesController().getChatFull(chatId); @@ -1401,7 +1433,7 @@ private void openParentSearch() { parentAvatarImageView = new BackupImageView(getContext()); parentAvatarDrawable = new AvatarDrawable(); parentAvatarImageView.setRoundRadius(AndroidUtilities.dp(16)); - parentAvatarDrawable.setInfo(getCurrentChat()); + parentAvatarDrawable.setInfo(currentAccount, getCurrentChat()); parentAvatarImageView.setForUserOrChat(getCurrentChat(), parentAvatarDrawable); } parentDialogsActivity.getSearchItem().setSearchPaddingStart(52); @@ -3796,10 +3828,19 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { notificationsLocker.unlock(); - if (!isOpen && (opnendForSelect && removeFragmentOnTransitionEnd)) { - removeSelfFromStack(); - if (dialogsActivity != null) { - dialogsActivity.removeSelfFromStack(); + if (!isOpen) { + if (opnendForSelect && removeFragmentOnTransitionEnd) { + removeSelfFromStack(); + if (dialogsActivity != null) { + dialogsActivity.removeSelfFromStack(); + } + } else if (finishDialogRightSlidingPreviewOnTransitionEnd) { + removeSelfFromStack(); + if (parentDialogsActivity != null && parentDialogsActivity.rightSlidingDialogContainer != null) { + if (parentDialogsActivity.rightSlidingDialogContainer.hasFragment()) { + parentDialogsActivity.rightSlidingDialogContainer.finishPreview(); + } + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java index 4f63455bd6..8d752db4e5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java @@ -141,7 +141,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification private HashMap patternsDict = new HashMap<>(); private boolean loadingWallpapers; - private LongSparseArray selectedWallPapers = new LongSparseArray<>(); + private final LongSparseArray selectedWallPapers = new LongSparseArray<>(); private boolean scrolling; private final static int forward = 3; @@ -963,7 +963,12 @@ private void onItemClick(WallpaperCell view, Object object, int index) { object = colorWallpaper; } } - ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false); + ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; if (currentType == TYPE_COLOR || dialogId != 0) { wallpaperActivity.setDelegate(WallpapersListActivity.this::removeSelfFromStack); } @@ -972,10 +977,22 @@ private void onItemClick(WallpaperCell view, Object object, int index) { } wallpaperActivity.setPatterns(patterns); wallpaperActivity.setDialogId(dialogId); - presentFragment(wallpaperActivity); + showAsSheet(wallpaperActivity); } } + private void showAsSheet(ThemePreviewActivity themePreviewActivity) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + themePreviewActivity.setResourceProvider(resourceProvider); + params.onOpenAnimationFinished = () -> { + PhotoViewer.getInstance().closePhoto(false, false); + }; + params.occupyNavigationBar = true; + showAsSheet(themePreviewActivity, params); + } + private String getWallPaperSlug(Object object) { if (object instanceof TLRPC.TL_wallPaper) { return ((TLRPC.TL_wallPaper) object).slug; diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java index 9110c86a48..ff796e3aa1 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java @@ -146,7 +146,6 @@ public class NekoChatSettingsActivity extends BaseNekoXSettingsActivity implemen private final AbstractConfigCell typeMessageHintUseGroupNameRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getTypeMessageHintUseGroupName())); private final AbstractConfigCell showSendAsUnderMessageHintRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowSendAsUnderMessageHint())); private final AbstractConfigCell hideBotButtonInInputFieldRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getHideBotButtonInInputField())); - private final AbstractConfigCell showForumAsNormalChatRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowForumAsNormalChat())); private final AbstractConfigCell doNotUnarchiveBySwipeRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getDoNotUnarchiveBySwipe())); private final AbstractConfigCell dividerInteractions = cellGroup.appendCell(new ConfigCellDivider()); diff --git a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt index afb2fa2950..02202b02ba 100644 --- a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt +++ b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt @@ -394,12 +394,6 @@ object NaConfig { ConfigItem.configTypeBool, false ) - val showForumAsNormalChat = - addConfig( - "ShowForumAsNormalChat", - ConfigItem.configTypeBool, - false - ) val chatDecoration = addConfig( "ChatDecoration", diff --git a/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png new file mode 100644 index 0000000000..1f844a2736 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png new file mode 100644 index 0000000000..03b2d45ef7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png new file mode 100644 index 0000000000..2245861dc8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png new file mode 100644 index 0000000000..355c4f13f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png new file mode 100644 index 0000000000..808f9ae3ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png new file mode 100644 index 0000000000..709571fa61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story.png new file mode 100644 index 0000000000..c47e4e9e61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png new file mode 100644 index 0000000000..99bccfe6f4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png new file mode 100644 index 0000000000..be789e65a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png new file mode 100644 index 0000000000..6f5e67b253 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png new file mode 100644 index 0000000000..d40990d277 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_colors.png new file mode 100644 index 0000000000..1036f89206 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png new file mode 100644 index 0000000000..e803328fbb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png new file mode 100644 index 0000000000..d4deca8d7b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png new file mode 100644 index 0000000000..de4e490c91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png new file mode 100644 index 0000000000..d64b98a4b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png new file mode 100644 index 0000000000..8dc4d326de Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png new file mode 100644 index 0000000000..07bb83dbb6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png new file mode 100644 index 0000000000..af6140b39a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png new file mode 100644 index 0000000000..73c8be7f13 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story.png new file mode 100644 index 0000000000..14365619c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png new file mode 100644 index 0000000000..df8e932c5e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png new file mode 100644 index 0000000000..29916aec8e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png new file mode 100644 index 0000000000..efa599654f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png new file mode 100644 index 0000000000..dff98af839 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_colors.png new file mode 100644 index 0000000000..a6abb3cc0d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png new file mode 100644 index 0000000000..4b8689ba05 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png new file mode 100644 index 0000000000..035182d87f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png new file mode 100644 index 0000000000..d33496c224 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png new file mode 100644 index 0000000000..2685bf33f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png new file mode 100644 index 0000000000..f80c8f39dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png new file mode 100644 index 0000000000..3b8ad4a6ee Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png new file mode 100644 index 0000000000..8efc78de49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png new file mode 100644 index 0000000000..44e726d83b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story.png new file mode 100644 index 0000000000..bd39b06b3e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png new file mode 100644 index 0000000000..9f47146735 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png new file mode 100644 index 0000000000..f2491c4130 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png new file mode 100644 index 0000000000..7e8c3c573e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png new file mode 100644 index 0000000000..fb85886d39 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_colors.png new file mode 100644 index 0000000000..4c3f94c910 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png new file mode 100644 index 0000000000..b4e6d2248b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png new file mode 100644 index 0000000000..ae3a4f79f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png new file mode 100644 index 0000000000..b19cf84b35 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png new file mode 100644 index 0000000000..f8ddf1bd85 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png new file mode 100644 index 0000000000..d6367f3261 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png new file mode 100644 index 0000000000..7072f83809 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png new file mode 100644 index 0000000000..6f541d8aa1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png new file mode 100644 index 0000000000..9a2a0eebf8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story.png new file mode 100644 index 0000000000..6eff47a6bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png new file mode 100644 index 0000000000..657125f357 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png new file mode 100644 index 0000000000..bdb88fd40e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png new file mode 100644 index 0000000000..76d338c6f6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png new file mode 100644 index 0000000000..ab5f7e90e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_colors.png new file mode 100644 index 0000000000..7b120b70bb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png new file mode 100644 index 0000000000..f5a7aa28d4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png new file mode 100644 index 0000000000..4fa0ca759c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/raw/chat_audio_record_delete_3.json b/TMessagesProj/src/main/res/raw/chat_audio_record_delete_3.json new file mode 100644 index 0000000000..76c7f87e70 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/chat_audio_record_delete_3.json @@ -0,0 +1 @@ +{"v":"5.6.6","fr":60,"ip":0,"op":40,"w":100,"h":100,"nm":"Delete Lottie Red","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 22 Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[71.75,2914,0],"ix":2},"a":{"a":0,"k":[5.75,19,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.418,0],[0,0],[0,-4.418],[0,0]],"o":[[0,0],[0,-4.418],[0,0],[4.418,0],[0,0],[0,0]],"v":[[-12,6],[-12,2],[-4,-6],[4,-6],[12,2],[12,6]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901969433,0.337254911661,0.301960796118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[18,12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":7200,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 20 Outlines 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[52.25,2913,0],"ix":2},"a":{"a":0,"k":[3.25,2.8,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[3,3],[67,3]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901969433,0.337254911661,0.301960796118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":7200,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Cup Red","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":14,"s":[0]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":19,"s":[3]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":23,"s":[-5]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":27,"s":[3]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":31,"s":[-4]},{"t":38,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.714,"y":0.689},"o":{"x":0.413,"y":0},"t":10,"s":[50.168,77.5,0],"to":[0,-0.334,0],"ti":[0,8.637,0]},{"i":{"x":0.519,"y":1},"o":{"x":0.271,"y":0.429},"t":14,"s":[50.168,49.119,0],"to":[0,-12.928,0],"ti":[0,4.396,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":21,"s":[50.168,15,0],"to":[0,0.136,0],"ti":[0,-0.333,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":25,"s":[50.168,23.5,0],"to":[0,0.333,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":29,"s":[50.168,18.5,0],"to":[0,0,0],"ti":[0,-0.5,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.29,"y":0},"t":33,"s":[50.168,22.25,0],"to":[0,0,0],"ti":[0,0,0]},{"t":40,"s":[50.168,21,0]}],"ix":2},"a":{"a":0,"k":[83.918,2911,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":10,"s":[84,31,100]},{"t":14,"s":[100,100,100]}],"ix":6}},"ao":0,"w":1440,"h":3040,"ip":10,"op":52,"st":10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Box 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":1,"s":[50.25,51.938,0],"to":[0,3.344,0],"ti":[0,-3.344,0]},{"t":10,"s":[50.25,72,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.8,"y":0},"t":1,"s":[{"i":[[-3.77,0],[-3.02,1.82],[-1.7,3.1],[0,3.48],[1.64,2.9],[3.29,1.79],[3.46,0],[2.86,-1.57],[1.82,-3.23],[0,-3.58],[-1.57,-2.86],[-3.02,-1.82]],"o":[[3.78,0],[3.01,-1.82],[1.57,-2.85],[0,-3.57],[-1.85,-3.26],[-2.84,-1.54],[-3.5,0],[-3.25,1.79],[-1.65,2.9],[0,3.49],[1.7,3.1],[3.02,1.81]],"v":[[0,20],[10.33,17.13],[17.54,9.61],[20,0],[17.42,-9.83],[9.55,-17.58],[0,-20],[-9.64,-17.53],[-17.41,-9.84],[-20,0],[-17.54,9.62],[-10.32,17.14]],"c":true}]},{"t":10,"s":[{"i":[[-3.77,0],[-3.51,0],[0,6.431],[0,0],[0,0.705],[4.525,0.08],[3.46,0],[3.263,0],[0,-2.973],[0,0],[0,-1.223],[-6.47,0]],"o":[[3.78,0],[6.49,0],[0.002,-0.756],[0,0],[0,-3.045],[-3.23,-0.057],[-3.5,0],[-4.95,0],[0,0.575],[0,0],[0,6.37],[3.015,0]],"v":[[-0.016,20],[17.932,20.02],[30.271,8.762],[30.273,7.421],[30.271,5.555],[24.678,2.42],[-0.172,2.375],[-24.262,2.315],[-30.261,5.581],[-30.248,7.409],[-30.242,8.751],[-17.921,20.057]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901969433,0.337254911661,0.301960796118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":10,"st":-328,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Box","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[50.25,72,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-3.77,0],[-3.51,0],[0,6.431],[0,0],[0,0.705],[4.525,0.08],[3.46,0],[3.263,0],[0,-2.973],[0,0],[0,-1.223],[-6.47,0]],"o":[[3.78,0],[6.49,0],[0.002,-0.756],[0,0],[0,-3.045],[-3.23,-0.057],[-3.5,0],[-4.95,0],[0,0.575],[0,0],[0,6.37],[3.015,0]],"v":[[-0.016,20],[17.932,20.02],[30.271,8.762],[30.273,7.421],[30.271,5.555],[24.678,2.42],[-0.172,2.375],[-24.262,2.315],[-30.261,5.581],[-30.248,7.409],[-30.242,8.751],[-17.921,20.057]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20,"s":[{"i":[[-3.77,0],[-3.51,0],[0,6.431],[0,0],[0,0.705],[4.525,0.08],[3.46,0],[3.263,0],[0,-2.972],[0,0],[0,-8.001],[-6.47,0]],"o":[[3.78,0],[6.49,0],[0,-6.887],[0,0],[0,-3.045],[-3.23,-0.057],[-3.5,0],[-4.95,0],[0,0.575],[0,0],[0,6.37],[3.015,0]],"v":[[-0.016,20],[17.932,20.02],[30.271,8.762],[30.302,-38.829],[30.299,-40.695],[24.706,-43.83],[-0.144,-43.875],[-24.234,-43.935],[-30.232,-40.669],[-30.219,-38.841],[-30.242,8.751],[-17.921,20.057]],"c":true}]},{"t":25,"s":[{"i":[[-3.77,0],[-3.51,0],[0,6.431],[0,0],[0,0.705],[4.525,0.08],[3.46,0],[3.263,0],[0,-2.972],[0,0],[0,-8.001],[-6.47,0]],"o":[[3.78,0],[6.49,0],[0,-6.887],[0,0],[0,-3.045],[-3.23,-0.057],[-3.5,0],[-4.95,0],[0,0.575],[0,0],[0,6.37],[3.015,0]],"v":[[-0.016,20],[17.932,20.02],[30.271,8.762],[30.226,-34.829],[30.223,-36.695],[24.63,-39.83],[-0.22,-39.875],[-24.31,-39.935],[-30.308,-36.669],[-30.295,-34.841],[-30.242,8.751],[-17.921,20.057]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-1.657,0],[0,0],[0,-0.446],[0,0],[1.657,0],[0,0.446],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,0.446],[-1.657,0],[0,0],[0,-0.446]],"v":[[11.875,6.625],[11.875,6.625],[14.875,7.433],[14.875,7.567],[11.875,8.375],[8.875,7.567],[8.875,7.433]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[11.875,1.875],[11.875,1.875],[14.875,4.875],[14.875,5.375],[11.875,8.375],[8.875,5.375],[8.875,4.875]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20,"s":[{"i":[[-1.657,0],[0,0],[0,-1.837],[0,0],[1.657,0],[0,1.837],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.837],[-1.657,0],[0,0],[0,-1.837]],"v":[[11.875,-33.75],[11.875,-33.75],[14.875,-30.424],[14.875,5.049],[11.875,8.375],[8.875,5.049],[8.875,-30.424]],"c":true}]},{"t":25,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[11.875,-29.625],[11.875,-29.625],[14.875,-26.625],[14.875,5.375],[11.875,8.375],[8.875,5.375],[8.875,-26.625]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-1.657,0],[0,0],[0,-0.446],[0,0],[1.657,0],[0,0.446],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,0.446],[-1.657,0],[0,0],[0,-0.446]],"v":[[-0.375,6.625],[-0.375,6.625],[2.625,7.433],[2.625,7.567],[-0.375,8.375],[-3.375,7.567],[-3.375,7.433]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[-0.375,1.875],[-0.375,1.875],[2.625,4.875],[2.625,5.375],[-0.375,8.375],[-3.375,5.375],[-3.375,4.875]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20,"s":[{"i":[[-1.657,0],[0,0],[0,-1.837],[0,0],[1.657,0],[0,1.837],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.837],[-1.657,0],[0,0],[0,-1.837]],"v":[[-0.375,-33.75],[-0.375,-33.75],[2.625,-30.424],[2.625,5.049],[-0.375,8.375],[-3.375,5.049],[-3.375,-30.424]],"c":true}]},{"t":25,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[-0.375,-29.625],[-0.375,-29.625],[2.625,-26.625],[2.625,5.375],[-0.375,8.375],[-3.375,5.375],[-3.375,-26.625]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":9,"s":[{"i":[[-1.657,0],[0,0],[0,-0.446],[0,0],[1.657,0],[0,0.446],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,0.446],[-1.657,0],[0,0],[0,-0.446]],"v":[[-12.125,6.625],[-12.125,6.625],[-9.125,7.433],[-9.125,7.567],[-12.125,8.375],[-15.125,7.567],[-15.125,7.433]],"c":true}]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[-12.125,1.875],[-12.125,1.875],[-9.125,4.875],[-9.125,5.375],[-12.125,8.375],[-15.125,5.375],[-15.125,4.875]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20,"s":[{"i":[[-1.657,0],[0,0],[0,-1.837],[0,0],[1.657,0],[0,1.837],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.837],[-1.657,0],[0,0],[0,-1.837]],"v":[[-12.125,-33.75],[-12.125,-33.75],[-9.125,-30.424],[-9.125,5.049],[-12.125,8.375],[-15.125,5.049],[-15.125,-30.424]],"c":true}]},{"t":25,"s":[{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,1.657],[0,0]],"o":[[0,0],[1.657,0],[0,0],[0,1.657],[-1.657,0],[0,0],[0,-1.657]],"v":[[-12.125,-29.625],[-12.125,-29.625],[-9.125,-26.625],[-9.125,5.375],[-12.125,8.375],[-15.125,5.375],[-15.125,-26.625]],"c":true}]}],"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":11,"s":[-0.125,11.375],"to":[0,0],"ti":[0,0]},{"t":19,"s":[-0.125,5.125]}],"ix":2},"a":{"a":0,"k":[-0.125,5.125],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901969433,0.337254911661,0.301960796118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Oval","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":52,"st":-328,"bm":0}],"markers":[{"tm":0,"cm":"1","dr":0},{"tm":40,"cm":"2","dr":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/stats.json b/TMessagesProj/src/main/res/raw/stats.json index cbba960997..c0ded68271 100644 --- a/TMessagesProj/src/main/res/raw/stats.json +++ b/TMessagesProj/src/main/res/raw/stats.json @@ -1 +1 @@ -{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":32,"w":512,"h":512,"nm":"Stats MAIN","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Column 1","sr":1,"ks":{"p":{"a":0,"k":[106,459.5,0]},"a":{"a":0,"k":[-150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":8,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-164.689,56.609],[-134.689,56.609],[-104.689,86.609],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-194.689,86.609]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":18,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-117.5],[-135,-117.5],[-105,-87.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-87.5]],"c":true}]},{"t":26,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Column 2","sr":1,"ks":{"p":{"a":0,"k":[256,459.5,0]},"a":{"a":0,"k":[0,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":12,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-45.5],[15,-45.5],[45,-15.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-15.5]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":21,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-233.5],[15,-233.5],[45,-203.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-203.5]],"c":true}]},{"t":29,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Column 3","sr":1,"ks":{"p":{"a":0,"k":[406,459.5,0]},"a":{"a":0,"k":[150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":14,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[134.289,-184.658],[164.289,-184.658],[194.289,-154.658],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[104.289,-154.658]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":23,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,29],[165,29],[195,59],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,59]],"c":true}]},{"t":31,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":49,"w":512,"h":512,"nm":"Stats Active 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Columns","sr":1,"ks":{"p":{"a":0,"k":[256,257,0]},"a":{"a":0,"k":[256,257,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106,459.5]},"a":{"a":0,"k":[-150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,459.5]},"a":{"a":0,"k":[0,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406,459.5]},"a":{"a":0,"k":[150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 3","bm":0,"hd":false}],"ip":0,"op":1,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Strokes","sr":1,"ks":{"p":{"a":0,"k":[256,248.776,0]},"a":{"a":0,"k":[256,248.776,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":8,"s":[{"i":[[-0.647,-0.34],[0,0],[0,2.573],[0,0],[0.647,0.34],[0,0],[0,-2.573],[0,0]],"o":[[0,0],[0.647,-0.34],[0,0],[0,-2.573],[0,0],[-0.647,0.34],[0,0],[0,2.573]],"v":[[-177.032,158],[-123.923,158],[-121.811,153.605],[-121.375,-6.535],[-123.487,-10.929],[-176.595,-10.929],[-178.707,-6.535],[-179.143,153.605]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[-0.535,-0.392],[0,0],[0,2.967],[0,0],[0.535,0.392],[0,0],[0,-2.967],[0,0]],"o":[[0,0],[0.535,-0.392],[0,0],[0,-2.967],[0,0],[-0.535,0.392],[0,0],[0,2.967]],"v":[[-172.43,171],[-128.497,171],[-126.75,165.933],[-126.982,-56.863],[-128.729,-61.929],[-172.661,-61.929],[-174.408,-56.863],[-174.176,165.933]],"c":true}]},{"t":23,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.578,0.382],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.578,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-174.176,168.209],[-126.732,168.209],[-124.846,163.264],[-124.846,-48.193],[-126.732,-53.138],[-174.175,-53.138],[-176.062,-48.193],[-176.062,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.5,-24.43],[-169.019,-66.827],[-133.164,-66.827],[-103.683,-24.193],[-103.065,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":8,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.361,-16.193],[-174,-58.827],[-126.128,-58.827],[-86.768,-16.193],[-87.157,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-214,-54.193],[-174.64,-96.827],[-126.768,-96.827],[-87.407,-54.193],[-87.157,163.264]],"c":true}]},{"t":23,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.75,-48.193],[-174.39,-90.827],[-126.518,-90.827],[-87.157,-48.193],[-87.157,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[105.546,313.535]},"a":{"a":0,"k":[-150.454,57.535]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":2,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-0.645,-0.35],[0,0],[0,2.651],[0,0],[0.644,0.35],[0,0],[0,-2.651],[0,0]],"o":[[0,0],[0.644,-0.35],[0,0],[0,-2.651],[0,0],[-0.645,0.35],[0,0],[0,2.651]],"v":[[-26.504,155],[26.459,155],[28.565,150.472],[28.686,-131.919],[26.579,-136.447],[-26.384,-136.447],[-28.489,-131.919],[-28.61,150.472]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":17,"s":[{"i":[[-0.53,-0.391],[0,0],[0,2.957],[0,0],[0.53,0.39],[0,0],[0,-2.957],[0,0]],"o":[[0,0],[0.53,-0.391],[0,0],[0,-2.957],[0,0],[-0.53,0.39],[0,0],[0,2.957]],"v":[[-21.789,172],[21.768,172],[23.5,166.95],[23.271,-187.397],[21.539,-192.447],[-22.018,-192.447],[-23.75,-187.397],[-23.52,166.95]],"c":true}]},{"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.382],[0,0],[0,-2.895],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-23.722,168.209],[23.722,168.209],[25.608,163.264],[25.608,-177.711],[23.722,-182.656],[-23.722,-182.656],[-25.608,-177.711],[-25.608,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":2,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-47,-158.711],[-18.085,-201.344],[17.084,-201.344],[46,-158.711],[46.5,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.221,-144.711],[-23.861,-187.344],[24.011,-187.344],[63.371,-144.711],[63.296,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":17,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.546,-183.711],[-24.186,-226.344],[23.686,-226.344],[63.046,-183.711],[63.296,163.264]],"c":true}]},{"t":24,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.296,-177.711],[-23.936,-220.344],[23.936,-220.344],[63.296,-177.711],[63.296,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,248.776]},"a":{"a":0,"k":[0,-7.224]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":4,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[{"i":[[-0.603,-0.291],[0,0],[0,2.202],[0,0],[0.602,0.291],[0,0],[0,-2.202],[0,0]],"o":[[0,0],[0.602,-0.291],[0,0],[0,-2.202],[0,0],[-0.603,0.291],[0,0],[0,2.201]],"v":[[125.717,154],[175.175,154],[177.142,150.24],[177.548,62.589],[175.581,58.829],[126.123,58.829],[124.156,62.589],[123.75,150.24]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-0.543,-0.402],[0,0],[0,3.042],[0,0],[0.542,0.402],[0,0],[0,-3.042],[0,0]],"o":[[0,0],[0.542,-0.402],[0,0],[0,-3.042],[0,0],[-0.543,0.402],[0,0],[0,3.041]],"v":[[128.165,172.329],[172.728,172.329],[174.5,167.133],[174.265,6.696],[172.493,1.5],[127.93,1.5],[126.158,6.696],[126.393,167.133]],"c":true}]},{"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.383],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.383],[0,0],[0,2.895]],"v":[[126.732,168.209],[174.176,168.209],[176.062,163.264],[176.062,16.565],[174.176,11.62],[126.732,11.62],[124.846,16.565],[124.846,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":4,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.68,38.837],[132.917,0.5],[167.262,0.5],[195.5,38.837],[195.773,166.059]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.548,49.565],[126.907,6.932],[174.779,6.932],[214.14,49.565],[213.75,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[86.908,10.565],[126.268,-32.068],[174.14,-32.068],[213.5,10.565],[213.75,163.264]],"c":true}]},{"t":24,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.158,16.565],[126.518,-26.068],[174.39,-26.068],[213.75,16.565],[213.75,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406.454,345.914]},"a":{"a":0,"k":[150.454,89.914]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 3","bm":0,"hd":false}],"ip":1,"op":24,"st":-4,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Columns 2","sr":1,"ks":{"p":{"a":0,"k":[256,257,0]},"a":{"a":0,"k":[256,257,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[-22.644,0],[0,0],[0,-16.681],[0,0],[22.644,0],[0,0],[0,16.681],[0,0]],"o":[[0,0],[22.644,0],[0,0],[0,16.681],[0,0],[-22.644,0],[0,0],[0,-16.681]],"v":[[-171,-92],[-130,-92],[-89,-51.297],[-89,171.797],[-130,205.5],[-171,205.5],[-212,171.797],[-212,-51.297]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-46.5],[-135,-46.5],[-105,-16.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-16.5]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-72.5],[-135,-72.5],[-105,-42.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-42.5]],"c":true}]},{"t":47,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106,459.5]},"a":{"a":0,"k":[-150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[-22.46,0],[0,0],[0,-16.627],[0,0],[22.46,0],[0,0],[0,16.627],[0,0]],"o":[[0,0],[22.46,0],[0,0],[0,16.627],[0,0],[-22.46,0],[0,0],[0,-16.627]],"v":[[-20.333,-224.5],[20.333,-224.5],[61,-179.895],[61,171.395],[20.333,205],[-20.333,205],[-61,171.395],[-61,-179.895]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-181.5],[15,-181.5],[45,-151.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-151.5]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-207.5],[15,-207.5],[45,-177.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-177.5]],"c":true}]},{"t":48,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,459.5]},"a":{"a":0,"k":[0,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[-23.012,0],[0,0],[0,-16.786],[0,0],[23.012,0],[0,0],[0,16.786],[0,0]],"o":[[0,0],[23.012,0],[0,0],[0,16.786],[0,0],[-23.012,0],[0,0],[0,-16.786]],"v":[[129.167,-25],[170.833,-25],[212.5,12.394],[212.5,172.606],[170.833,206.5],[129.167,206.5],[87.5,172.606],[87.5,12.394]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":37,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,11],[165,11],[195,41],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,41]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,-6],[165,-6],[195,24],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,24]],"c":true}]},{"t":48,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406,459.5]},"a":{"a":0,"k":[150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 3","bm":0,"hd":false}],"ip":35,"op":175,"st":55,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Strokes 2","sr":1,"ks":{"p":{"a":0,"k":[256,248.776,0]},"a":{"a":0,"k":[256,248.776,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.578,0.382],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.578,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-174.176,168.209],[-126.732,168.209],[-124.846,163.264],[-124.846,-48.193],[-126.732,-53.138],[-174.175,-53.138],[-176.062,-48.193],[-176.062,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[-0.003,0],[0,0],[0,0.004],[0,0],[0.003,0],[0,0],[0,-0.004],[0,0]],"o":[[0,0],[0.003,0],[0,0],[0,-0.004],[0,0],[-0.003,0],[0,0],[0,0.004]],"v":[[-151.356,67.674],[-151.074,67.674],[-151.062,67.668],[-151.063,67.403],[-151.075,67.397],[-151.357,67.397],[-151.368,67.403],[-151.368,67.668]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]},{"t":47,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.75,-48.193],[-174.39,-90.827],[-126.518,-90.827],[-87.157,-48.193],[-87.157,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.559,204.146],[-168.414,204.146],[-195.947,169.527],[-196.344,-5.43],[-168.863,-47.827],[-133.008,-47.827],[-103.527,-5.193],[-103.13,169.764]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.416,-36.68],[-168.935,-79.077],[-133.08,-79.077],[-103.599,-36.443],[-103.065,163.264]],"c":true}]},{"t":47,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.5,-24.43],[-169.019,-66.827],[-133.164,-66.827],[-103.683,-24.193],[-103.065,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[105.546,313.535]},"a":{"a":0,"k":[-150.454,57.535]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.382],[0,0],[0,-2.895],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-23.722,168.209],[23.722,168.209],[25.608,163.264],[25.608,-177.711],[23.722,-182.656],[-23.722,-182.656],[-25.608,-177.711],[-25.608,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[0.001,0],[0,0],[0,-0.001],[0,0],[-0.001,0],[0,0],[0,0.001],[0,0]],"o":[[0,0],[-0.001,0],[0,0],[0,0.001],[0,0],[0.001,0],[0,0],[0,-0.001]],"v":[[-0.563,51.745],[-0.623,51.745],[-0.625,51.746],[-0.625,51.807],[-0.623,51.808],[-0.563,51.808],[-0.561,51.807],[-0.561,51.746]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]},{"t":48,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.296,-177.711],[-23.936,-220.344],[23.936,-220.344],[63.296,-177.711],[63.296,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.586,204.021],[-17.582,204.021],[-46.5,166.764],[-46.845,-139.711],[-17.929,-182.344],[17.24,-182.344],[46.156,-139.711],[46.5,166.764]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-46.916,-170.961],[-18,-213.594],[17.168,-213.594],[46.084,-170.961],[46.5,163.264]],"c":true}]},{"t":48,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-47,-158.711],[-18.085,-201.344],[17.084,-201.344],[46,-158.711],[46.5,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,248.776]},"a":{"a":0,"k":[0,-7.224]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.383],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.383],[0,0],[0,2.895]],"v":[[126.732,168.209],[174.176,168.209],[176.062,163.264],[176.062,16.565],[174.176,11.62],[126.732,11.62],[124.846,16.565],[124.846,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":36,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[150.095,92.397],[150.64,92.397],[150.662,92.318],[150.664,90.079],[150.642,90],[150.097,90],[150.075,90.079],[150.073,92.318]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]},{"t":48,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.158,16.565],[126.518,-26.068],[174.39,-26.068],[213.75,16.565],[213.75,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":36,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.836,47.837],[133.073,9.5],[167.418,9.5],[195.656,47.837],[195.773,166.059]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.672,203.896],[133.327,203.896],[104.976,168.309],[104.764,26.587],[133.001,-11.75],[167.346,-11.75],[195.584,26.587],[195.796,168.309]],"c":true}]},{"t":48,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.68,38.837],[132.917,0.5],[167.262,0.5],[195.5,38.837],[195.773,166.059]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406.454,345.914]},"a":{"a":0,"k":[150.454,89.914]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 3","bm":0,"hd":false}],"ip":24,"op":35,"st":20,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/story_repost.json b/TMessagesProj/src/main/res/raw/story_repost.json new file mode 100644 index 0000000000..673fc165dd --- /dev/null +++ b/TMessagesProj/src/main/res/raw/story_repost.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":36,"w":512,"h":512,"nm":"Repost Story 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":14.678,"s":[105,105,100]},{"t":32.7421875,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Big Path 4","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[0.5,0,0]},"a":{"a":0,"k":[0.5,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,27.658],[0,0],[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0]],"o":[[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0],[0,0],[0,27.658],[0,0]],"v":[[-75.799,100.158],[-125.878,50.079],[-125.878,-50.079],[-75.799,-100.158],[76.799,-100.158],[126.878,-50.079],[126.878,50.079],[76.799,100.158]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[13.2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.162,"s":[19]},{"t":20.322265625,"s":[13.2]}]},"e":{"a":0,"k":51.2},"o":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":20.322,"s":[196]},{"t":35,"s":[180]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":35},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-18","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 4","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.9],"y":[1]},"o":{"x":[0.199],"y":[0.138]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.1],"y":[0]},"t":9.033,"s":[115]},{"t":17,"s":[180]}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[94.281,-100.367,0],"to":[23.779,4.847,0],"ti":[0,-27.658,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4.516,"s":[124.378,-55.579,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9.033,"s":[126.878,50.079,0],"to":[0,27.658,0],"ti":[27.658,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11.291,"s":[76.799,100.158,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":16.936,"s":[-96.281,100.367,0],"to":[0.093,-0.023,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20.322,"s":[-126.031,100.617,0],"to":[0,0,0],"ti":[0,0,0]},{"t":35,"s":[-93.281,100.367,0]}]},"a":{"a":0,"k":[94.281,-100.367,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,2.327],[0,0],[-6.02,0],[-1.873,-1.38],[0,0],[3.571,-4.846],[0.881,-0.649],[0,0],[3.571,4.846]],"o":[[0,0],[0,-6.02],[2.327,0],[0,0],[4.846,3.571],[-0.649,0.881],[0,0],[-4.846,3.571],[-1.38,-1.873]],"v":[[49.121,-49.879],[49.121,-150.855],[60.021,-161.755],[66.486,-159.63],[135.006,-109.142],[137.315,-93.901],[135.006,-91.592],[66.486,-41.104],[51.246,-43.413]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-19","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Big Path 3","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[0.5,0,0]},"a":{"a":0,"k":[0.5,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,27.658],[0,0],[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0]],"o":[[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0],[0,0],[0,27.658],[0,0]],"v":[[-75.799,100.158],[-125.878,50.079],[-125.878,-50.079],[-75.799,-100.158],[76.799,-100.158],[126.878,-50.079],[126.878,50.079],[76.799,100.158]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":35},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[13.2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.162,"s":[19]},{"t":20.322265625,"s":[13.2]}]},"e":{"a":0,"k":51.2},"o":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[180]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":20.322,"s":[376]},{"t":35,"s":[360]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-18","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Arrow 3","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.9],"y":[1]},"o":{"x":[0.199],"y":[0.138]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.1],"y":[0]},"t":9.033,"s":[115]},{"t":17,"s":[180]}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-93.281,100.367,0],"to":[0,0,0],"ti":[0,23.658,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4.516,"s":[-124.878,57.079,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9.033,"s":[-125.878,-55.079,0],"to":[0,-27.658,0],"ti":[-27.658,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11.291,"s":[-75.799,-100.158,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":16.936,"s":[94.281,-100.367,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20.322,"s":[128.281,-100.367,0],"to":[0,0,0],"ti":[-0.217,0.091,0]},{"t":35,"s":[94.281,-100.367,0]}]},"a":{"a":0,"k":[-93.281,100.367,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-2.327],[0,0],[6.02,0],[1.873,1.38],[0,0],[-3.571,4.846],[-0.881,0.649],[0,0],[-3.571,-4.846]],"o":[[0,0],[0,6.02],[-2.327,0],[0,0],[-4.846,-3.571],[0.649,-0.881],[0,0],[4.846,-3.571],[1.38,1.873]],"v":[[-48.121,49.879],[-48.121,150.855],[-59.021,161.755],[-65.486,159.63],[-134.006,109.142],[-136.315,93.901],[-134.006,91.592],[-65.486,41.104],[-50.246,43.413]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-19","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/transcribe.json b/TMessagesProj/src/main/res/raw/transcribe.json new file mode 100644 index 0000000000..5065c247dc --- /dev/null +++ b/TMessagesProj/src/main/res/raw/transcribe.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Comp 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Intro Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":4,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":6,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":7,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":8,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":9,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":10,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":12,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":13,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":14,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":16,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":17,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":19,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":20,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":21,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":22,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":25,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":26,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":27,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":29,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":31,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":32,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":34,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":39,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":40,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":41,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":42,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":43,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":45,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":46,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":48,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":49,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":51,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":53,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":55,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":56,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":57,"s":[0]},{"i":{"x":[0.833],"y":[0.929]},"o":{"x":[0.167],"y":[0]},"t":58,"s":[0]},{"i":{"x":[0.833],"y":[0.327]},"o":{"x":[0.167],"y":[0.083]},"t":59,"s":[0]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.095]},"t":60,"s":[0.855]},{"i":{"x":[0.833],"y":[0.867]},"o":{"x":[0.167],"y":[0.133]},"t":61,"s":[6.909]},{"i":{"x":[0.833],"y":[0.736]},"o":{"x":[0.167],"y":[0.223]},"t":62,"s":[17.098]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.122]},"t":63,"s":[23.179]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":64,"s":[36.342]},{"i":{"x":[0.833],"y":[0.762]},"o":{"x":[0.167],"y":[0.256]},"t":65,"s":[49.777]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.128]},"t":66,"s":[56.275]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.18]},"t":67,"s":[68.354]},{"i":{"x":[0.833],"y":[0.778]},"o":{"x":[0.167],"y":[0.277]},"t":68,"s":[78.788]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":69,"s":[83.289]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.197]},"t":70,"s":[90.78]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.308]},"t":71,"s":[96.275]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.144]},"t":72,"s":[98.315]},{"i":{"x":[0.833],"y":[0.905]},"o":{"x":[0.167],"y":[0.261]},"t":73,"s":[101.11]},{"i":{"x":[0.833],"y":[1.079]},"o":{"x":[0.167],"y":[0.663]},"t":74,"s":[102.418]},{"i":{"x":[0.833],"y":[0.664]},"o":{"x":[0.167],"y":[0.04]},"t":75,"s":[102.606]},{"i":{"x":[0.833],"y":[0.86]},"o":{"x":[0.167],"y":[0.111]},"t":76,"s":[102.24]},{"i":{"x":[0.833],"y":[0.724]},"o":{"x":[0.167],"y":[0.207]},"t":77,"s":[101.129]},{"i":{"x":[0.833],"y":[0.826]},"o":{"x":[0.167],"y":[0.119]},"t":78,"s":[100.379]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.16]},"t":79,"s":[98.643]},{"i":{"x":[0.833],"y":[0.757]},"o":{"x":[0.167],"y":[0.25]},"t":80,"s":[96.764]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":81,"s":[95.824]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":82,"s":[94.027]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.271]},"t":83,"s":[92.42]},{"i":{"x":[0.833],"y":[0.853]},"o":{"x":[0.167],"y":[0.132]},"t":84,"s":[91.707]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.192]},"t":85,"s":[90.488]},{"i":{"x":[0.833],"y":[0.794]},"o":{"x":[0.167],"y":[0.297]},"t":86,"s":[89.551]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.14]},"t":87,"s":[89.186]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.23]},"t":88,"s":[88.651]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.411]},"t":89,"s":[88.347]},{"i":{"x":[0.833],"y":[1.177]},"o":{"x":[0.167],"y":[0.289]},"t":90,"s":[88.27]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.057]},"t":91,"s":[88.239]},{"i":{"x":[0.833],"y":[0.703]},"o":{"x":[0.167],"y":[0.18]},"t":92,"s":[88.337]},{"i":{"x":[0.833],"y":[0.819]},"o":{"x":[0.167],"y":[0.116]},"t":93,"s":[88.421]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.154]},"t":94,"s":[88.638]},{"i":{"x":[0.833],"y":[0.752]},"o":{"x":[0.167],"y":[0.243]},"t":95,"s":[88.893]},{"i":{"x":[0.833],"y":[0.839]},"o":{"x":[0.167],"y":[0.126]},"t":96,"s":[89.025]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.173]},"t":97,"s":[89.287]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.267]},"t":98,"s":[89.529]},{"i":{"x":[0.833],"y":[0.85]},"o":{"x":[0.167],"y":[0.131]},"t":99,"s":[89.64]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.188]},"t":100,"s":[89.834]},{"i":{"x":[0.833],"y":[0.788]},"o":{"x":[0.167],"y":[0.29]},"t":101,"s":[89.989]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.137]},"t":102,"s":[90.051]},{"i":{"x":[0.833],"y":[0.891]},"o":{"x":[0.167],"y":[0.214]},"t":103,"s":[90.148]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.353]},"t":104,"s":[90.21]},{"i":{"x":[0.833],"y":[0.933]},"o":{"x":[0.167],"y":[0.171]},"t":105,"s":[90.229]},{"i":{"x":[0.833],"y":[0.727]},"o":{"x":[0.167],"y":[-0.345]},"t":106,"s":[90.247]},{"i":{"x":[0.833],"y":[0.656]},"o":{"x":[0.167],"y":[0.12]},"t":107,"s":[90.243]},{"i":{"x":[0.833],"y":[0.807]},"o":{"x":[0.167],"y":[0.11]},"t":108,"s":[90.235]},{"i":{"x":[0.833],"y":[0.871]},"o":{"x":[0.167],"y":[0.147]},"t":109,"s":[90.21]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.235]},"t":110,"s":[90.177]},{"i":{"x":[0.833],"y":[0.836]},"o":{"x":[0.167],"y":[0.124]},"t":111,"s":[90.159]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.17]},"t":112,"s":[90.122]},{"i":{"x":[0.833],"y":[0.766]},"o":{"x":[0.167],"y":[0.262]},"t":113,"s":[90.086]},{"i":{"x":[0.833],"y":[0.848]},"o":{"x":[0.167],"y":[0.13]},"t":114,"s":[90.069]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.184]},"t":115,"s":[90.039]},{"i":{"x":[0.833],"y":[0.783]},"o":{"x":[0.167],"y":[0.283]},"t":116,"s":[90.014]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.135]},"t":117,"s":[90.004]},{"i":{"x":[0.833],"y":[0.888]},"o":{"x":[0.167],"y":[0.205]},"t":118,"s":[89.987]},{"i":{"x":[0.833],"y":[0.816]},"o":{"x":[0.167],"y":[0.326]},"t":119,"s":[89.975]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.153]},"t":120,"s":[89.971]},{"i":{"x":[0.833],"y":[0.947]},"o":{"x":[0.167],"y":[0.406]},"t":121,"s":[89.967]},{"i":{"x":[0.833],"y":[0.45]},"o":{"x":[0.167],"y":[-0.145]},"t":122,"s":[89.965]},{"i":{"x":[0.833],"y":[0.783]},"o":{"x":[0.167],"y":[0.098]},"t":123,"s":[89.966]},{"i":{"x":[0.833],"y":[0.816]},"o":{"x":[0.167],"y":[0.135]},"t":124,"s":[89.968]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.152]},"t":125,"s":[89.972]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.241]},"t":126,"s":[89.977]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":127,"s":[89.98]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.172]},"t":128,"s":[89.985]},{"i":{"x":[0.833],"y":[0.769]},"o":{"x":[0.167],"y":[0.265]},"t":129,"s":[89.99]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.13]},"t":130,"s":[89.992]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.186]},"t":131,"s":[89.996]},{"i":{"x":[0.833],"y":[0.786]},"o":{"x":[0.167],"y":[0.287]},"t":132,"s":[89.999]},{"i":{"x":[0.833],"y":[0.862]},"o":{"x":[0.167],"y":[0.137]},"t":133,"s":[90.001]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.211]},"t":134,"s":[90.003]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.342]},"t":135,"s":[90.004]},{"i":{"x":[0.833],"y":[0.915]},"o":{"x":[0.167],"y":[0.162]},"t":136,"s":[90.004]},{"i":{"x":[0.833],"y":[2.343]},"o":{"x":[0.167],"y":[5.161]},"t":137,"s":[90.005]},{"i":{"x":[0.833],"y":[0.624]},"o":{"x":[0.167],"y":[0.078]},"t":138,"s":[90.005]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.107]},"t":139,"s":[90.005]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.143]},"t":140,"s":[90.004]},{"i":{"x":[0.833],"y":[0.744]},"o":{"x":[0.167],"y":[0.232]},"t":141,"s":[90.004]},{"i":{"x":[0.833],"y":[0.835]},"o":{"x":[0.167],"y":[0.123]},"t":142,"s":[90.003]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.168]},"t":143,"s":[90.003]},{"i":{"x":[0.833],"y":[0.765]},"o":{"x":[0.167],"y":[0.26]},"t":144,"s":[90.002]},{"i":{"x":[0.833],"y":[0.847]},"o":{"x":[0.167],"y":[0.129]},"t":145,"s":[90.001]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.183]},"t":146,"s":[90.001]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.281]},"t":147,"s":[90]},{"i":{"x":[0.833],"y":[0.858]},"o":{"x":[0.167],"y":[0.135]},"t":148,"s":[90]},{"i":{"x":[0.833],"y":[0.887]},"o":{"x":[0.167],"y":[0.202]},"t":149,"s":[90]},{"i":{"x":[0.833],"y":[0.812]},"o":{"x":[0.167],"y":[0.32]},"t":150,"s":[90]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.167],"y":[0.149]},"t":151,"s":[89.999]},{"i":{"x":[0.833],"y":[0.925]},"o":{"x":[0.167],"y":[0.331]},"t":152,"s":[89.999]},{"i":{"x":[0.833],"y":[-0.019]},"o":{"x":[0.167],"y":[-0.747]},"t":153,"s":[89.999]},{"i":{"x":[0.833],"y":[0.767]},"o":{"x":[0.167],"y":[0.091]},"t":154,"s":[89.999]},{"i":{"x":[0.833],"y":[0.866]},"o":{"x":[0.167],"y":[0.13]},"t":155,"s":[89.999]},{"i":{"x":[0.833],"y":[0.734]},"o":{"x":[0.167],"y":[0.221]},"t":156,"s":[89.999]},{"i":{"x":[0.833],"y":[0.831]},"o":{"x":[0.167],"y":[0.121]},"t":157,"s":[89.999]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.164]},"t":158,"s":[90]},{"i":{"x":[0.833],"y":[0.761]},"o":{"x":[0.167],"y":[0.255]},"t":159,"s":[90]},{"i":{"x":[0.833],"y":[0.844]},"o":{"x":[0.167],"y":[0.128]},"t":160,"s":[90]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.179]},"t":161,"s":[90]},{"i":{"x":[0.833],"y":[0.777]},"o":{"x":[0.167],"y":[0.276]},"t":162,"s":[90]},{"i":{"x":[0.833],"y":[0.855]},"o":{"x":[0.167],"y":[0.133]},"t":163,"s":[90]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.196]},"t":164,"s":[90]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.306]},"t":165,"s":[90]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.143]},"t":166,"s":[90]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.254]},"t":167,"s":[90]},{"i":{"x":[0.833],"y":[1.006]},"o":{"x":[0.167],"y":[0.569]},"t":168,"s":[90]},{"i":{"x":[0.833],"y":[0.592]},"o":{"x":[0.167],"y":[0.006]},"t":169,"s":[90]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.105]},"t":170,"s":[90]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.203]},"t":171,"s":[90]},{"i":{"x":[0.833],"y":[0.825]},"o":{"x":[0.167],"y":[0.119]},"t":172,"s":[90]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.159]},"t":173,"s":[90]},{"i":{"x":[0.833],"y":[0.756]},"o":{"x":[0.167],"y":[0.249]},"t":174,"s":[90]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":175,"s":[90]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":176,"s":[90]},{"i":{"x":[0.833],"y":[0.773]},"o":{"x":[0.167],"y":[0.271]},"t":177,"s":[90]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.132]},"t":178,"s":[90]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.191]},"t":179,"s":[90]},{"t":180,"s":[90]}],"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[150,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":0,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":2,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":3,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":4,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":5,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":6,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":7,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":8,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":9,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":10,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":11,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":12,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":13,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":14,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":15,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":16,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":17,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":18,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":19,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":20,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":21,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":22,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":23,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":24,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":25,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":26,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":27,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":28,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":29,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":30,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":31,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":32,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":33,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":34,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":35,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":36,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":37,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":38,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":39,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":40,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":41,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":42,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":43,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":44,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":45,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":46,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":47,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":48,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":49,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":50,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":51,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":52,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":53,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":54,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":55,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":56,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":57,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.98,0.98,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":58,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.327,0.327,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.083,0.083,0]},"t":59,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.776,0.776,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.095,0.095,0]},"t":60,"s":[170.91,170.91,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":61,"s":[172.632,172.632,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.736,0.736,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.223,0.223,0]},"t":62,"s":[175.53,175.53,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":63,"s":[177.26,177.26,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.876,0.876,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.165,0.165,0]},"t":64,"s":[181.004,181.004,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.762,0.762,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":65,"s":[184.826,184.826,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.845,0.845,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":66,"s":[186.674,186.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.881,0.881,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":67,"s":[190.109,190.109,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.277,0.277,0]},"t":68,"s":[193.077,193.077,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.924,0.924,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":69,"s":[194.358,194.358,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.52,0.52,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.907,-0.907,0]},"t":70,"s":[196.245,196.245,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.641,0.641,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.101,0.101,0]},"t":71,"s":[196.086,196.086,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.804,0.804,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.109,0.109,0]},"t":72,"s":[195.331,195.331,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.871,0.871,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.145,0.145,0]},"t":73,"s":[192.834,192.834,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.745,0.745,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.234,0.234,0]},"t":74,"s":[189.462,189.462,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.836,0.836,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.124,0.124,0]},"t":75,"s":[187.594,187.594,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.169,0.169,0]},"t":76,"s":[183.741,183.741,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.766,0.766,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":77,"s":[179.989,179.989,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.847,0.847,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":78,"s":[178.227,178.227,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.183,0.183,0]},"t":79,"s":[175.034,175.034,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.782,0.782,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.282,0.282,0]},"t":80,"s":[172.369,172.369,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.859,0.859,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":81,"s":[171.251,171.251,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.203,0.203,0]},"t":82,"s":[169.447,169.447,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.814,0.814,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.322,0.322,0]},"t":83,"s":[168.195,168.195,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.892,0.892,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.151,0.151,0]},"t":84,"s":[167.758,167.758,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.934,0.934,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.36,0.36,0]},"t":85,"s":[167.22,167.22,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.307,0.307,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.328,-0.328,0]},"t":86,"s":[167.057,167.057,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.776,0.776,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.095,0.095,0]},"t":87,"s":[167.09,167.09,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":88,"s":[167.331,167.331,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.736,0.736,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.223,0.223,0]},"t":89,"s":[167.738,167.738,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":90,"s":[167.981,167.981,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.876,0.876,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.165,0.165,0]},"t":91,"s":[168.509,168.509,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.762,0.762,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":92,"s":[169.048,169.048,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.845,0.845,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":93,"s":[169.309,169.309,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.881,0.881,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":94,"s":[169.794,169.794,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.778,0.778,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.276,0.276,0]},"t":95,"s":[170.213,170.213,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.855,0.855,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":96,"s":[170.394,170.394,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.886,0.886,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.197,0.197,0]},"t":97,"s":[170.695,170.695,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.802,0.802,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.308,0.308,0]},"t":98,"s":[170.916,170.916,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.144,0.144,0]},"t":99,"s":[170.999,170.999,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.904,0.904,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":100,"s":[171.111,171.111,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.07,1.07,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.651,0.651,0]},"t":101,"s":[171.164,171.164,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.658,0.658,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.038,0.038,0]},"t":102,"s":[171.172,171.172,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.86,0.86,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.11,0.11,0]},"t":103,"s":[171.158,171.158,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.723,0.723,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.207,0.207,0]},"t":104,"s":[171.114,171.114,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.826,0.826,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.119,0.119,0]},"t":105,"s":[171.084,171.084,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.875,0.875,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.16,0.16,0]},"t":106,"s":[171.014,171.014,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.757,0.757,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.25,0.25,0]},"t":107,"s":[170.939,170.939,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.842,0.842,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.127,0.127,0]},"t":108,"s":[170.901,170.901,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.176,0.176,0]},"t":109,"s":[170.829,170.829,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.774,0.774,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.271,0.271,0]},"t":110,"s":[170.764,170.764,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.853,0.853,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":111,"s":[170.736,170.736,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.192,0.192,0]},"t":112,"s":[170.687,170.687,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.297,0.297,0]},"t":113,"s":[170.649,170.649,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.869,0.869,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":114,"s":[170.634,170.634,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.895,0.895,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.23,0.23,0]},"t":115,"s":[170.613,170.613,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.41,0.41,0]},"t":116,"s":[170.6,170.6,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.161,1.161,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.281,0.281,0]},"t":117,"s":[170.597,170.597,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.844,0.844,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.055,0.055,0]},"t":118,"s":[170.596,170.596,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.702,0.702,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.179,0.179,0]},"t":119,"s":[170.6,170.6,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.819,0.819,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.116,0.116,0]},"t":120,"s":[170.603,170.603,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.154,0.154,0]},"t":121,"s":[170.612,170.612,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.752,0.752,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.243,0.243,0]},"t":122,"s":[170.622,170.622,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.839,0.839,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":123,"s":[170.627,170.627,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.844,0.844,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.173,0.173,0]},"t":124,"s":[170.638,170.638,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.179,0.179,0]},"t":125,"s":[170.648,170.648,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.777,0.777,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.275,0.275,0]},"t":126,"s":[170.656,170.656,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.854,0.854,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":127,"s":[170.66,170.66,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.885,0.885,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.195,0.195,0]},"t":128,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.799,0.799,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.304,0.304,0]},"t":129,"s":[170.671,170.671,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.874,0.874,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.142,0.142,0]},"t":130,"s":[170.673,170.673,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.9,0.9,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.247,0.247,0]},"t":131,"s":[170.675,170.675,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.962,0.962,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.513,0.513,0]},"t":132,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.436,0.436,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.07,-0.07,0]},"t":133,"s":[170.677,170.677,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.857,0.857,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.098,0.098,0]},"t":134,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.718,0.718,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.199,0.199,0]},"t":135,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.824,0.824,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.118,0.118,0]},"t":136,"s":[170.675,170.675,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.874,0.874,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.158,0.158,0]},"t":137,"s":[170.674,170.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.756,0.756,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.248,0.248,0]},"t":138,"s":[170.672,170.672,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.841,0.841,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":139,"s":[170.672,170.672,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.879,0.879,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.175,0.175,0]},"t":140,"s":[170.67,170.67,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.773,0.773,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.27,0.27,0]},"t":141,"s":[170.669,170.669,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.852,0.852,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":142,"s":[170.668,170.668,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.19,0.19,0]},"t":143,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.792,0.792,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.294,0.294,0]},"t":144,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":145,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.894,0.894,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.224,0.224,0]},"t":146,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.862,0.862,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.384,0.384,0]},"t":147,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.012,1.012,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.209,0.209,0]},"t":148,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.831,0.831,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.011,0.011,0]},"t":149,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.691,0.691,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.164,0.164,0]},"t":150,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.816,0.816,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.114,0.114,0]},"t":151,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.152,0.152,0]},"t":152,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.75,0.75,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.241,0.241,0]},"t":153,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.838,0.838,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":154,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,0]},"t":155,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.769,0.769,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.265,0.265,0]},"t":156,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.849,0.849,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.13,0.13,0]},"t":157,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.883,0.883,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.186,0.186,0]},"t":158,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.786,0.786,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.287,0.287,0]},"t":159,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.862,0.862,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.137,0.137,0]},"t":160,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.89,0.89,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.211,0.211,0]},"t":161,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.828,0.828,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.341,0.341,0]},"t":162,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.915,0.915,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.162,0.162,0]},"t":163,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.822,1.822,1]},"o":{"x":[0.167,0.167,0.167],"y":[3.388,3.388,0]},"t":164,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.622,0.622,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.076,0.076,0]},"t":165,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.801,0.801,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.107,0.107,0]},"t":166,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.87,0.87,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.143,0.143,0]},"t":167,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.743,0.743,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.232,0.232,0]},"t":168,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.835,0.835,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.123,0.123,0]},"t":169,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.168,0.168,0]},"t":170,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.765,0.765,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.26,0.26,0]},"t":171,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.847,0.847,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":172,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.183,0.183,0]},"t":173,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.781,0.781,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.281,0.281,0]},"t":174,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.858,0.858,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":175,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.887,0.887,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.202,0.202,0]},"t":176,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.811,0.811,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.319,0.319,0]},"t":177,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.149,0.149,0]},"t":178,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.328,0.328,0]},"t":179,"s":[170.667,170.667,100]},{"t":180,"s":[170.667,170.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,120],[255,180]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":44,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,107.5],[255,192.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.6,"y":0},"t":64,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,132.5],[255,167.5]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[225,140],[225,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[50]},{"t":26,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[50]},{"t":26,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.306,0.306]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":69,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":70,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.705,0.705]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":71,"s":[101.609,101.609]},{"i":{"x":[0.833,0.833],"y":[0.818,0.818]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":72,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":73,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[0.242,0.242]},"t":74,"s":[109.01,109.01]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":75,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":76,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[0.267,0.267]},"t":77,"s":[117.647,117.647]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":78,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.907,0.907]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":79,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.278,1.278]},"o":{"x":[0.167,0.167],"y":[0.785,0.785]},"t":80,"s":[123.58,123.58]},{"i":{"x":[0.833,0.833],"y":[0.702,0.702]},"o":{"x":[0.167,0.167],"y":[0.064,0.064]},"t":81,"s":[123.796,123.796]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":82,"s":[122.86,122.86]},{"i":{"x":[0.833,0.833],"y":[0.721,0.721]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":83,"s":[120.447,120.447]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":84,"s":[118.825,118.825]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":85,"s":[115.024,115.024]},{"i":{"x":[0.833,0.833],"y":[0.756,0.756]},"o":{"x":[0.167,0.167],"y":[0.248,0.248]},"t":86,"s":[110.83,110.83]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":87,"s":[108.704,108.704]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":88,"s":[104.601,104.601]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":89,"s":[100.909,100.909]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":90,"s":[99.281,99.281]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":91,"s":[96.542,96.542]},{"i":{"x":[0.833,0.833],"y":[0.814,0.814]},"o":{"x":[0.167,0.167],"y":[0.317,0.317]},"t":92,"s":[94.549,94.549]},{"i":{"x":[0.833,0.833],"y":[0.897,0.897]},"o":{"x":[0.167,0.167],"y":[0.151,0.151]},"t":93,"s":[93.837,93.837]},{"i":{"x":[0.833,0.833],"y":[0.961,0.961]},"o":{"x":[0.167,0.167],"y":[0.43,0.43]},"t":94,"s":[92.96,92.96]},{"i":{"x":[0.833,0.833],"y":[0.484,0.484]},"o":{"x":[0.167,0.167],"y":[-0.073,-0.073]},"t":95,"s":[92.749,92.749]},{"i":{"x":[0.833,0.833],"y":[0.781,0.781]},"o":{"x":[0.167,0.167],"y":[0.099,0.099]},"t":96,"s":[92.861,92.861]},{"i":{"x":[0.833,0.833],"y":[0.867,0.867]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":97,"s":[93.444,93.444]},{"i":{"x":[0.833,0.833],"y":[0.734,0.734]},"o":{"x":[0.167,0.167],"y":[0.222,0.222]},"t":98,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":99,"s":[94.963,94.963]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.164,0.164]},"t":100,"s":[96.212,96.212]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":101,"s":[97.507,97.507]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":102,"s":[98.139,98.139]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":103,"s":[99.32,99.32]},{"i":{"x":[0.833,0.833],"y":[0.783,0.783]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":104,"s":[100.336,100.336]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":105,"s":[100.768,100.768]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.208,0.208]},"t":106,"s":[101.462,101.462]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.346,0.346]},"t":107,"s":[101.926,101.926]},{"i":{"x":[0.833,0.833],"y":[0.945,0.945]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":108,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[-0.16,-0.16]},"t":109,"s":[102.21,102.21]},{"i":{"x":[0.833,0.833],"y":[0.657,0.657]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":110,"s":[102.163,102.163]},{"i":{"x":[0.833,0.833],"y":[0.805,0.805]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":111,"s":[102.082,102.082]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":112,"s":[101.829,101.829]},{"i":{"x":[0.833,0.833],"y":[0.743,0.743]},"o":{"x":[0.167,0.167],"y":[0.233,0.233]},"t":113,"s":[101.49,101.49]},{"i":{"x":[0.833,0.833],"y":[0.835,0.835]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":114,"s":[101.301,101.301]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":115,"s":[100.908,100.908]},{"i":{"x":[0.833,0.833],"y":[0.766,0.766]},"o":{"x":[0.167,0.167],"y":[0.26,0.26]},"t":116,"s":[100.52,100.52]},{"i":{"x":[0.833,0.833],"y":[0.848,0.848]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":117,"s":[100.337,100.337]},{"i":{"x":[0.833,0.833],"y":[0.883,0.883]},"o":{"x":[0.167,0.167],"y":[0.185,0.185]},"t":118,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.79,0.79]},"o":{"x":[0.167,0.167],"y":[0.288,0.288]},"t":119,"s":[99.735,99.735]},{"i":{"x":[0.833,0.833],"y":[0.868,0.868]},"o":{"x":[0.167,0.167],"y":[0.138,0.138]},"t":120,"s":[99.625,99.625]},{"i":{"x":[0.833,0.833],"y":[0.896,0.896]},"o":{"x":[0.167,0.167],"y":[0.226,0.226]},"t":121,"s":[99.457,99.457]},{"i":{"x":[0.833,0.833],"y":[0.898,0.898]},"o":{"x":[0.167,0.167],"y":[0.416,0.416]},"t":122,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[1.583,1.583]},"o":{"x":[0.167,0.167],"y":[0.457,0.457]},"t":123,"s":[99.335,99.335]},{"i":{"x":[0.833,0.833],"y":[0.763,0.763]},"o":{"x":[0.167,0.167],"y":[0.073,0.073]},"t":124,"s":[99.329,99.329]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":125,"s":[99.373,99.373]},{"i":{"x":[0.833,0.833],"y":[0.73,0.73]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":126,"s":[99.454,99.454]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":127,"s":[99.505,99.505]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":128,"s":[99.618,99.618]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":129,"s":[99.738,99.738]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":130,"s":[99.798,99.798]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":131,"s":[99.911,99.911]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":132,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":133,"s":[100.052,100.052]},{"i":{"x":[0.833,0.833],"y":[0.889,0.889]},"o":{"x":[0.167,0.167],"y":[0.204,0.204]},"t":134,"s":[100.122,100.122]},{"i":{"x":[0.833,0.833],"y":[0.827,0.827]},"o":{"x":[0.167,0.167],"y":[0.332,0.332]},"t":135,"s":[100.17,100.17]},{"i":{"x":[0.833,0.833],"y":[0.919,0.919]},"o":{"x":[0.167,0.167],"y":[0.161,0.161]},"t":136,"s":[100.187,100.187]},{"i":{"x":[0.833,0.833],"y":[-0.283,-0.283]},"o":{"x":[0.167,0.167],"y":[-3.463,-3.463]},"t":137,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.621,0.621]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":138,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.798,0.798]},"o":{"x":[0.167,0.167],"y":[0.107,0.107]},"t":139,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":140,"s":[100.177,100.177]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.229,0.229]},"t":141,"s":[100.147,100.147]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":142,"s":[100.13,100.13]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":143,"s":[100.094,100.094]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.258,0.258]},"t":144,"s":[100.057,100.057]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":145,"s":[100.04,100.04]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":146,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.787,0.787]},"o":{"x":[0.167,0.167],"y":[0.285,0.285]},"t":147,"s":[99.981,99.981]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":148,"s":[99.97,99.97]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":149,"s":[99.953,99.953]},{"i":{"x":[0.833,0.833],"y":[0.867,0.867]},"o":{"x":[0.167,0.167],"y":[0.379,0.379]},"t":150,"s":[99.942,99.942]},{"i":{"x":[0.833,0.833],"y":[1.057,1.057]},"o":{"x":[0.167,0.167],"y":[0.222,0.222]},"t":151,"s":[99.939,99.939]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.034,0.034]},"t":152,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":153,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":154,"s":[99.943,99.943]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":155,"s":[99.952,99.952]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.238,0.238]},"t":156,"s":[99.962,99.962]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":157,"s":[99.967,99.967]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":158,"s":[99.978,99.978]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.264,0.264]},"t":159,"s":[99.989,99.989]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":160,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":161,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.295,0.295]},"t":162,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":163,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.244,0.244]},"t":164,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.008,1.008]},"o":{"x":[0.167,0.167],"y":[0.546,0.546]},"t":165,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.575,0.575]},"o":{"x":[0.167,0.167],"y":[0.008,0.008]},"t":166,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.104,0.104]},"t":167,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.715,0.715]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":168,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":169,"s":[100.016,100.016]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":170,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.754,0.754]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":171,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":172,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":173,"s":[100.004,100.004]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.27,0.27]},"t":174,"s":[100.001,100.001]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":175,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.195,0.195]},"t":176,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.309,0.309]},"t":177,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.323,0.323]},"t":179,"s":[99.994,99.994]},{"t":180,"s":[99.994,99.994]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,100],[220,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,87.5],[220,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,112.5],[220,187.5]],"c":false}]},{"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,100],[220,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":24,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":24,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":16,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,70],[185,230]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,57.5],[185,242.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":56,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,82.5],[185,217.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":76,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,70],[185,230]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[175,70],[175,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[50]},{"t":22,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[50]},{"t":22,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.679,0.679]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.615,0.615]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":65,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.797,0.797]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":66,"s":[100.744,100.744]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":67,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":68,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":69,"s":[107.272,107.272]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":70,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":71,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":72,"s":[116.035,116.035]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":73,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.328,0.328]},"t":74,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.343,1.343]},"o":{"x":[0.167,0.167],"y":[0.35,0.35]},"t":75,"s":[122.653,122.653]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.067,0.067]},"t":76,"s":[122.932,122.932]},{"i":{"x":[0.833,0.833],"y":[0.699,0.699]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":77,"s":[121.508,121.508]},{"i":{"x":[0.833,0.833],"y":[0.816,0.816]},"o":{"x":[0.167,0.167],"y":[0.115,0.115]},"t":78,"s":[120.285,120.285]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.153,0.153]},"t":79,"s":[117.086,117.086]},{"i":{"x":[0.833,0.833],"y":[0.749,0.749]},"o":{"x":[0.167,0.167],"y":[0.24,0.24]},"t":80,"s":[113.237,113.237]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":81,"s":[111.193,111.193]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.172,0.172]},"t":82,"s":[107.092,107.092]},{"i":{"x":[0.833,0.833],"y":[0.771,0.771]},"o":{"x":[0.167,0.167],"y":[0.265,0.265]},"t":83,"s":[103.224,103.224]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":84,"s":[101.454,101.454]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":85,"s":[98.354,98.354]},{"i":{"x":[0.833,0.833],"y":[0.799,0.799]},"o":{"x":[0.167,0.167],"y":[0.299,0.299]},"t":86,"s":[95.934,95.934]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":87,"s":[94.998,94.998]},{"i":{"x":[0.833,0.833],"y":[0.906,0.906]},"o":{"x":[0.167,0.167],"y":[0.259,0.259]},"t":88,"s":[93.675,93.675]},{"i":{"x":[0.833,0.833],"y":[1.191,1.191]},"o":{"x":[0.167,0.167],"y":[0.762,0.762]},"t":89,"s":[93.047,93.047]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.058,0.058]},"t":90,"s":[92.97,92.97]},{"i":{"x":[0.833,0.833],"y":[0.86,0.86]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":91,"s":[93.224,93.224]},{"i":{"x":[0.833,0.833],"y":[0.72,0.72]},"o":{"x":[0.167,0.167],"y":[0.206,0.206]},"t":92,"s":[93.92,93.92]},{"i":{"x":[0.833,0.833],"y":[0.824,0.824]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":93,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.158,0.158]},"t":94,"s":[95.508,95.508]},{"i":{"x":[0.833,0.833],"y":[0.755,0.755]},"o":{"x":[0.167,0.167],"y":[0.247,0.247]},"t":95,"s":[96.744,96.744]},{"i":{"x":[0.833,0.833],"y":[0.841,0.841]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":96,"s":[97.373,97.373]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":97,"s":[98.589,98.589]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":98,"s":[99.686,99.686]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":99,"s":[100.171,100.171]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.197,0.197]},"t":100,"s":[100.99,100.99]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.315,0.315]},"t":101,"s":[101.589,101.589]},{"i":{"x":[0.833,0.833],"y":[0.895,0.895]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":102,"s":[101.804,101.804]},{"i":{"x":[0.833,0.833],"y":[0.952,0.952]},"o":{"x":[0.167,0.167],"y":[0.4,0.4]},"t":103,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.448,0.448]},"o":{"x":[0.167,0.167],"y":[-0.115,-0.115]},"t":104,"s":[102.143,102.143]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.098,0.098]},"t":105,"s":[102.113,102.113]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":106,"s":[101.947,101.947]},{"i":{"x":[0.833,0.833],"y":[0.733,0.733]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":107,"s":[101.671,101.671]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":108,"s":[101.504,101.504]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":109,"s":[101.136,101.136]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":110,"s":[100.753,100.753]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":111,"s":[100.566,100.566]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":112,"s":[100.216,100.216]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":113,"s":[99.913,99.913]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":114,"s":[99.784,99.784]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":115,"s":[99.576,99.576]},{"i":{"x":[0.833,0.833],"y":[0.836,0.836]},"o":{"x":[0.167,0.167],"y":[0.343,0.343]},"t":116,"s":[99.436,99.436]},{"i":{"x":[0.833,0.833],"y":[0.939,0.939]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":117,"s":[99.391,99.391]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[-0.226,-0.226]},"t":118,"s":[99.348,99.348]},{"i":{"x":[0.833,0.833],"y":[0.652,0.652]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":119,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.804,0.804]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":120,"s":[99.383,99.383]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.145,0.145]},"t":121,"s":[99.456,99.456]},{"i":{"x":[0.833,0.833],"y":[0.742,0.742]},"o":{"x":[0.167,0.167],"y":[0.232,0.232]},"t":122,"s":[99.555,99.555]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":123,"s":[99.61,99.61]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":124,"s":[99.727,99.727]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":125,"s":[99.841,99.841]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":126,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":127,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.194,0.194]},"t":128,"s":[100.075,100.075]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[0.308,0.308]},"t":129,"s":[100.136,100.136]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":130,"s":[100.159,100.159]},{"i":{"x":[0.833,0.833],"y":[0.923,0.923]},"o":{"x":[0.167,0.167],"y":[0.312,0.312]},"t":131,"s":[100.188,100.188]},{"i":{"x":[0.833,0.833],"y":[-0.267,-0.267]},"o":{"x":[0.167,0.167],"y":[-0.96,-0.96]},"t":132,"s":[100.199,100.199]},{"i":{"x":[0.833,0.833],"y":[0.758,0.758]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":133,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":134,"s":[100.186,100.186]},{"i":{"x":[0.833,0.833],"y":[0.729,0.729]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":135,"s":[100.163,100.163]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":136,"s":[100.148,100.148]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":137,"s":[100.114,100.114]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.251,0.251]},"t":138,"s":[100.079,100.079]},{"i":{"x":[0.833,0.833],"y":[0.843,0.843]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":139,"s":[100.061,100.061]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":140,"s":[100.028,100.028]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":141,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":142,"s":[99.986,99.986]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":143,"s":[99.965,99.965]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.33,0.33]},"t":144,"s":[99.95,99.95]},{"i":{"x":[0.833,0.833],"y":[0.915,0.915]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":145,"s":[99.945,99.945]},{"i":{"x":[0.833,0.833],"y":[2.34,2.34]},"o":{"x":[0.167,0.167],"y":[4.745,4.745]},"t":146,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.612,0.612]},"o":{"x":[0.167,0.167],"y":[0.078,0.078]},"t":147,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":148,"s":[99.941,99.941]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":149,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":150,"s":[99.956,99.956]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":151,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":152,"s":[99.972,99.972]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":153,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":154,"s":[99.988,99.988]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":155,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.786,0.786]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":156,"s":[100.005,100.005]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":157,"s":[100.009,100.009]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":158,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.863,0.863]},"o":{"x":[0.167,0.167],"y":[0.374,0.374]},"t":159,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.032,1.032]},"o":{"x":[0.167,0.167],"y":[0.212,0.212]},"t":160,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.023,0.023]},"t":161,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.685,0.685]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":162,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.812,0.812]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":163,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":164,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.237,0.237]},"t":165,"s":[100.011,100.011]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":166,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":167,"s":[100.007,100.007]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":168,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":169,"s":[100.002,100.002]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":170,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":171,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":172,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.901,0.901]},"o":{"x":[0.167,0.167],"y":[0.241,0.241]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.987,0.987]},"o":{"x":[0.167,0.167],"y":[0.521,0.521]},"t":174,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.523,0.523]},"o":{"x":[0.167,0.167],"y":[-0.016,-0.016]},"t":175,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.101,0.101]},"t":176,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.713,0.713]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":177,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.156,0.156]},"t":179,"s":[99.996,99.996]},{"t":180,"s":[99.997,99.997]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,100],[150,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,87.5],[150,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":52,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,112.5],[150,187.5]],"c":false}]},{"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,100],[150,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[50]},{"t":20,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[50]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":8,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,70],[115,230]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,57.5],[115,242.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":48,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,82.5],[115,217.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":68,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,70],[115,230]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[125,70],[125,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[50]},{"t":18,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[50]},{"t":18,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.679,0.679]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.615,0.615]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":65,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.797,0.797]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":66,"s":[100.744,100.744]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":67,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":68,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":69,"s":[107.272,107.272]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":70,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":71,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":72,"s":[116.035,116.035]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":73,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.328,0.328]},"t":74,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.343,1.343]},"o":{"x":[0.167,0.167],"y":[0.35,0.35]},"t":75,"s":[122.653,122.653]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.067,0.067]},"t":76,"s":[122.932,122.932]},{"i":{"x":[0.833,0.833],"y":[0.699,0.699]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":77,"s":[121.508,121.508]},{"i":{"x":[0.833,0.833],"y":[0.816,0.816]},"o":{"x":[0.167,0.167],"y":[0.115,0.115]},"t":78,"s":[120.285,120.285]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.153,0.153]},"t":79,"s":[117.086,117.086]},{"i":{"x":[0.833,0.833],"y":[0.749,0.749]},"o":{"x":[0.167,0.167],"y":[0.24,0.24]},"t":80,"s":[113.237,113.237]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":81,"s":[111.193,111.193]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.172,0.172]},"t":82,"s":[107.092,107.092]},{"i":{"x":[0.833,0.833],"y":[0.771,0.771]},"o":{"x":[0.167,0.167],"y":[0.265,0.265]},"t":83,"s":[103.224,103.224]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":84,"s":[101.454,101.454]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":85,"s":[98.354,98.354]},{"i":{"x":[0.833,0.833],"y":[0.799,0.799]},"o":{"x":[0.167,0.167],"y":[0.299,0.299]},"t":86,"s":[95.934,95.934]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":87,"s":[94.998,94.998]},{"i":{"x":[0.833,0.833],"y":[0.906,0.906]},"o":{"x":[0.167,0.167],"y":[0.259,0.259]},"t":88,"s":[93.675,93.675]},{"i":{"x":[0.833,0.833],"y":[1.191,1.191]},"o":{"x":[0.167,0.167],"y":[0.762,0.762]},"t":89,"s":[93.047,93.047]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.058,0.058]},"t":90,"s":[92.97,92.97]},{"i":{"x":[0.833,0.833],"y":[0.86,0.86]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":91,"s":[93.224,93.224]},{"i":{"x":[0.833,0.833],"y":[0.72,0.72]},"o":{"x":[0.167,0.167],"y":[0.206,0.206]},"t":92,"s":[93.92,93.92]},{"i":{"x":[0.833,0.833],"y":[0.824,0.824]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":93,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.158,0.158]},"t":94,"s":[95.508,95.508]},{"i":{"x":[0.833,0.833],"y":[0.755,0.755]},"o":{"x":[0.167,0.167],"y":[0.247,0.247]},"t":95,"s":[96.744,96.744]},{"i":{"x":[0.833,0.833],"y":[0.841,0.841]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":96,"s":[97.373,97.373]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":97,"s":[98.589,98.589]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":98,"s":[99.686,99.686]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":99,"s":[100.171,100.171]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.197,0.197]},"t":100,"s":[100.99,100.99]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.315,0.315]},"t":101,"s":[101.589,101.589]},{"i":{"x":[0.833,0.833],"y":[0.895,0.895]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":102,"s":[101.804,101.804]},{"i":{"x":[0.833,0.833],"y":[0.952,0.952]},"o":{"x":[0.167,0.167],"y":[0.4,0.4]},"t":103,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.448,0.448]},"o":{"x":[0.167,0.167],"y":[-0.115,-0.115]},"t":104,"s":[102.143,102.143]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.098,0.098]},"t":105,"s":[102.113,102.113]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":106,"s":[101.947,101.947]},{"i":{"x":[0.833,0.833],"y":[0.733,0.733]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":107,"s":[101.671,101.671]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":108,"s":[101.504,101.504]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":109,"s":[101.136,101.136]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":110,"s":[100.753,100.753]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":111,"s":[100.566,100.566]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":112,"s":[100.216,100.216]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":113,"s":[99.913,99.913]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":114,"s":[99.784,99.784]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":115,"s":[99.576,99.576]},{"i":{"x":[0.833,0.833],"y":[0.836,0.836]},"o":{"x":[0.167,0.167],"y":[0.343,0.343]},"t":116,"s":[99.436,99.436]},{"i":{"x":[0.833,0.833],"y":[0.939,0.939]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":117,"s":[99.391,99.391]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[-0.226,-0.226]},"t":118,"s":[99.348,99.348]},{"i":{"x":[0.833,0.833],"y":[0.652,0.652]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":119,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.804,0.804]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":120,"s":[99.383,99.383]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.145,0.145]},"t":121,"s":[99.456,99.456]},{"i":{"x":[0.833,0.833],"y":[0.742,0.742]},"o":{"x":[0.167,0.167],"y":[0.232,0.232]},"t":122,"s":[99.555,99.555]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":123,"s":[99.61,99.61]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":124,"s":[99.727,99.727]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":125,"s":[99.841,99.841]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":126,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":127,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.194,0.194]},"t":128,"s":[100.075,100.075]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[0.308,0.308]},"t":129,"s":[100.136,100.136]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":130,"s":[100.159,100.159]},{"i":{"x":[0.833,0.833],"y":[0.923,0.923]},"o":{"x":[0.167,0.167],"y":[0.312,0.312]},"t":131,"s":[100.188,100.188]},{"i":{"x":[0.833,0.833],"y":[-0.267,-0.267]},"o":{"x":[0.167,0.167],"y":[-0.96,-0.96]},"t":132,"s":[100.199,100.199]},{"i":{"x":[0.833,0.833],"y":[0.758,0.758]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":133,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":134,"s":[100.186,100.186]},{"i":{"x":[0.833,0.833],"y":[0.729,0.729]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":135,"s":[100.163,100.163]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":136,"s":[100.148,100.148]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":137,"s":[100.114,100.114]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.251,0.251]},"t":138,"s":[100.079,100.079]},{"i":{"x":[0.833,0.833],"y":[0.843,0.843]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":139,"s":[100.061,100.061]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":140,"s":[100.028,100.028]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":141,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":142,"s":[99.986,99.986]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":143,"s":[99.965,99.965]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.33,0.33]},"t":144,"s":[99.95,99.95]},{"i":{"x":[0.833,0.833],"y":[0.915,0.915]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":145,"s":[99.945,99.945]},{"i":{"x":[0.833,0.833],"y":[2.34,2.34]},"o":{"x":[0.167,0.167],"y":[4.745,4.745]},"t":146,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.612,0.612]},"o":{"x":[0.167,0.167],"y":[0.078,0.078]},"t":147,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":148,"s":[99.941,99.941]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":149,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":150,"s":[99.956,99.956]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":151,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":152,"s":[99.972,99.972]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":153,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":154,"s":[99.988,99.988]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":155,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.786,0.786]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":156,"s":[100.005,100.005]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":157,"s":[100.009,100.009]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":158,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.863,0.863]},"o":{"x":[0.167,0.167],"y":[0.374,0.374]},"t":159,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.032,1.032]},"o":{"x":[0.167,0.167],"y":[0.212,0.212]},"t":160,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.023,0.023]},"t":161,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.685,0.685]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":162,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.812,0.812]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":163,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":164,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.237,0.237]},"t":165,"s":[100.011,100.011]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":166,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":167,"s":[100.007,100.007]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":168,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":169,"s":[100.002,100.002]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":170,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":171,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":172,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.901,0.901]},"o":{"x":[0.167,0.167],"y":[0.241,0.241]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.987,0.987]},"o":{"x":[0.167,0.167],"y":[0.521,0.521]},"t":174,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.523,0.523]},"o":{"x":[0.167,0.167],"y":[-0.016,-0.016]},"t":175,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.101,0.101]},"t":176,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.713,0.713]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":177,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.156,0.156]},"t":179,"s":[99.996,99.996]},{"t":180,"s":[99.997,99.997]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,100],[80,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,87.5],[80,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":44,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,112.5],[80,187.5]],"c":false}]},{"t":64,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,100],[80,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[50]},{"t":16,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[50]},{"t":16,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,120],[45,180]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,107.5],[45,192.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,132.5],[45,167.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,120],[45,180]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[75,70],[75,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[50]},{"t":14,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[50]},{"t":14,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.306,0.306]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":60,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":61,"s":[101.609,101.609]},{"i":{"x":[0.833,0.833],"y":[0.731,0.731]},"o":{"x":[0.167,0.167],"y":[0.219,0.219]},"t":62,"s":[104.093,104.093]},{"i":{"x":[0.833,0.833],"y":[0.829,0.829]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":63,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":64,"s":[109.01,109.01]},{"i":{"x":[0.833,0.833],"y":[0.76,0.76]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":65,"s":[112.579,112.579]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":66,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.179,0.179]},"t":67,"s":[117.647,117.647]},{"i":{"x":[0.833,0.833],"y":[0.794,0.794]},"o":{"x":[0.167,0.167],"y":[0.278,0.278]},"t":68,"s":[120.526,120.526]},{"i":{"x":[0.833,0.833],"y":[0.919,0.919]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":69,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[-0.477,-0.477]},"o":{"x":[0.167,0.167],"y":[-3.646,-3.646]},"t":70,"s":[123.58,123.58]},{"i":{"x":[0.833,0.833],"y":[0.621,0.621]},"o":{"x":[0.167,0.167],"y":[0.088,0.088]},"t":71,"s":[123.54,123.54]},{"i":{"x":[0.833,0.833],"y":[0.798,0.798]},"o":{"x":[0.167,0.167],"y":[0.107,0.107]},"t":72,"s":[122.86,122.86]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":73,"s":[120.447,120.447]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.229,0.229]},"t":74,"s":[116.999,116.999]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":75,"s":[115.024,115.024]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":76,"s":[110.83,110.83]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.258,0.258]},"t":77,"s":[106.616,106.616]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":78,"s":[104.601,104.601]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":79,"s":[100.909,100.909]},{"i":{"x":[0.833,0.833],"y":[0.787,0.787]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":80,"s":[97.822,97.822]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":81,"s":[96.542,96.542]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":82,"s":[94.549,94.549]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.378,0.378]},"t":83,"s":[93.31,93.31]},{"i":{"x":[0.833,0.833],"y":[1.055,1.055]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":84,"s":[92.96,92.96]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.033,0.033]},"t":85,"s":[92.749,92.749]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":86,"s":[93.098,93.098]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":87,"s":[93.444,93.444]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":88,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.238,0.238]},"t":89,"s":[95.575,95.575]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":90,"s":[96.212,96.212]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":91,"s":[97.507,97.507]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":92,"s":[98.747,98.747]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":93,"s":[99.32,99.32]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":94,"s":[100.336,100.336]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.295,0.295]},"t":95,"s":[101.144,101.144]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":96,"s":[101.462,101.462]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.244,0.244]},"t":97,"s":[101.926,101.926]},{"i":{"x":[0.833,0.833],"y":[1.006,1.006]},"o":{"x":[0.167,0.167],"y":[0.544,0.544]},"t":98,"s":[102.166,102.166]},{"i":{"x":[0.833,0.833],"y":[0.572,0.572]},"o":{"x":[0.167,0.167],"y":[0.006,0.006]},"t":99,"s":[102.21,102.21]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.103,0.103]},"t":100,"s":[102.163,102.163]},{"i":{"x":[0.833,0.833],"y":[0.715,0.715]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":101,"s":[101.969,101.969]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":102,"s":[101.829,101.829]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":103,"s":[101.49,101.49]},{"i":{"x":[0.833,0.833],"y":[0.754,0.754]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":104,"s":[101.106,101.106]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":105,"s":[100.908,100.908]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":106,"s":[100.52,100.52]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.27,0.27]},"t":107,"s":[100.165,100.165]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":108,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.195,0.195]},"t":109,"s":[99.735,99.735]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.309,0.309]},"t":110,"s":[99.532,99.532]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":111,"s":[99.457,99.457]},{"i":{"x":[0.833,0.833],"y":[0.927,0.927]},"o":{"x":[0.167,0.167],"y":[0.322,0.322]},"t":112,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.032,0.032]},"o":{"x":[0.167,0.167],"y":[-0.607,-0.607]},"t":113,"s":[99.325,99.325]},{"i":{"x":[0.833,0.833],"y":[0.763,0.763]},"o":{"x":[0.167,0.167],"y":[0.091,0.091]},"t":114,"s":[99.329,99.329]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":115,"s":[99.373,99.373]},{"i":{"x":[0.833,0.833],"y":[0.73,0.73]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":116,"s":[99.454,99.454]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":117,"s":[99.505,99.505]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":118,"s":[99.618,99.618]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":119,"s":[99.738,99.738]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":120,"s":[99.798,99.798]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":121,"s":[99.911,99.911]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":122,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":123,"s":[100.052,100.052]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.204,0.204]},"t":124,"s":[100.122,100.122]},{"i":{"x":[0.833,0.833],"y":[0.897,0.897]},"o":{"x":[0.167,0.167],"y":[0.231,0.231]},"t":125,"s":[100.17,100.17]},{"i":{"x":[0.833,0.833],"y":[0.922,0.922]},"o":{"x":[0.167,0.167],"y":[0.444,0.444]},"t":126,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[-2.132,-2.132]},"o":{"x":[0.167,0.167],"y":[-1.2,-1.2]},"t":127,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.851,0.851]},"o":{"x":[0.167,0.167],"y":[0.086,0.086]},"t":128,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.706,0.706]},"o":{"x":[0.167,0.167],"y":[0.189,0.189]},"t":129,"s":[100.189,100.189]},{"i":{"x":[0.833,0.833],"y":[0.819,0.819]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":130,"s":[100.177,100.177]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":131,"s":[100.147,100.147]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[0.242,0.242]},"t":132,"s":[100.112,100.112]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":133,"s":[100.094,100.094]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":134,"s":[100.057,100.057]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[0.267,0.267]},"t":135,"s":[100.023,100.023]},{"i":{"x":[0.833,0.833],"y":[0.853,0.853]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":136,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.885,0.885]},"o":{"x":[0.167,0.167],"y":[0.192,0.192]},"t":137,"s":[99.981,99.981]},{"i":{"x":[0.833,0.833],"y":[0.802,0.802]},"o":{"x":[0.167,0.167],"y":[0.303,0.303]},"t":138,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":139,"s":[99.953,99.953]},{"i":{"x":[0.833,0.833],"y":[0.912,0.912]},"o":{"x":[0.167,0.167],"y":[0.278,0.278]},"t":140,"s":[99.942,99.942]},{"i":{"x":[0.833,0.833],"y":[1.994,1.994]},"o":{"x":[0.167,0.167],"y":[1.71,1.71]},"t":141,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.731,0.731]},"o":{"x":[0.167,0.167],"y":[0.077,0.077]},"t":142,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.862,0.862]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":143,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.725,0.725]},"o":{"x":[0.167,0.167],"y":[0.211,0.211]},"t":144,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.826,0.826]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":145,"s":[99.952,99.952]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.16,0.16]},"t":146,"s":[99.962,99.962]},{"i":{"x":[0.833,0.833],"y":[0.757,0.757]},"o":{"x":[0.167,0.167],"y":[0.249,0.249]},"t":147,"s":[99.973,99.973]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":148,"s":[99.978,99.978]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.177,0.177]},"t":149,"s":[99.989,99.989]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.274,0.274]},"t":150,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":151,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.2,0.2]},"t":152,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.818,0.818]},"o":{"x":[0.167,0.167],"y":[0.321,0.321]},"t":153,"s":[100.015,100.015]},{"i":{"x":[0.833,0.833],"y":[0.903,0.903]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":154,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.009,1.009]},"o":{"x":[0.167,0.167],"y":[0.58,0.58]},"t":155,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.553,0.553]},"o":{"x":[0.167,0.167],"y":[0.008,0.008]},"t":156,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.788,0.788]},"o":{"x":[0.167,0.167],"y":[0.102,0.102]},"t":157,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.868,0.868]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":158,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.736,0.736]},"o":{"x":[0.167,0.167],"y":[0.225,0.225]},"t":159,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":160,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":161,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.762,0.762]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":162,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.846,0.846]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":163,"s":[100.004,100.004]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.181,0.181]},"t":164,"s":[100.001,100.001]},{"i":{"x":[0.833,0.833],"y":[0.784,0.784]},"o":{"x":[0.167,0.167],"y":[0.281,0.281]},"t":165,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.862,0.862]},"o":{"x":[0.167,0.167],"y":[0.136,0.136]},"t":166,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.211,0.211]},"t":167,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.355,0.355]},"t":168,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.968,0.968]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":169,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[-0.053,-0.053]},"t":170,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.67,0.67]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":171,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.111,0.111]},"t":172,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.871,0.871]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.745,0.745]},"o":{"x":[0.167,0.167],"y":[0.235,0.235]},"t":174,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.835,0.835]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":175,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.169,0.169]},"t":176,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.767,0.767]},"o":{"x":[0.167,0.167],"y":[0.261,0.261]},"t":177,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":178,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.186,0.186]},"t":179,"s":[100,100]},{"t":180,"s":[100.001,100.001]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/ids.xml b/TMessagesProj/src/main/res/values/ids.xml index 97fbaf3dce..0774a3a2b9 100644 --- a/TMessagesProj/src/main/res/values/ids.xml +++ b/TMessagesProj/src/main/res/values/ids.xml @@ -11,6 +11,7 @@ + diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 9fcff11773..48ba01d72e 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -528,6 +528,7 @@ joined %1$s Restricted users Administrators + Channel Settings Delete Channel Delete channel Wait! Deleting this channel will remove all members and all messages will be lost. Delete the channel anyway? @@ -588,6 +589,7 @@ Sorry, you are a member of too many groups and channels. Please leave some before joining a new one. un1 added you to this channel You joined this channel + You joined channel %s You joined this group Remove from channel Sorry, you can\'t send messages to this channel. @@ -1067,6 +1069,8 @@ OPEN BOT sponsored recommended + Sponsored + Recommended Advertiser Info What are sponsored\nmessages? Unlike other apps, Telegram never uses your private data to target ads. [Learn more in the Privacy Policy](https://telegram.org/privacy#5-6-no-ads-based-on-user-data) @@ -1110,6 +1114,7 @@ No recent Message Message + Message in %1$s Schedule message SHARE MY PHONE NUMBER Share my contact @@ -1127,7 +1132,8 @@ Delete this chat Delete this chat Delete chats - SLIDE TO CANCEL + Slide to cancel + Cancel Save to downloads Save to GIFs Delete GIF? @@ -2176,7 +2182,7 @@ Blurred Motion Change Chat Background - Change Name Color + Change Your Color Change Name Color Chat Background Reset Chat Backgrounds @@ -2345,6 +2351,7 @@ Videos Press the volume buttons to turn sound on. The account was hidden by the user + The account was hidden by the user Auto-play media Raise to Speak Record voice messages by raising phone to your ear @@ -2352,7 +2359,8 @@ Switch sound to the earpiece by raising phone to your ear Save to Gallery Sound muted - Edit name + Edit Name + Edit Profile Color Customize Custom Enable Custom Notifications @@ -2985,6 +2993,7 @@ Shared Content Shared Links Shared Music + Similar Channels Share photos and videos in this chat and access them on any of your devices. Share music in this chat and access it on any of your devices. Share files and documents in this chat and access them on any of your devices. @@ -3933,10 +3942,15 @@ Growth Followers Interactions + Views and Shares + Reactions + Story Views and Shares + Story Reactions Views by source New followers by source Languages Recent posts + Recent Posts Zoom out IV Interactions Loading stats... @@ -3949,6 +3963,10 @@ Clear Telegram Cache Overview Views Per Post + Views Per Story + Shares Per Story + Reactions Per Story + Reactions Per Post Shares Per Post Enabled Notifications Clear Local Database @@ -4008,6 +4026,7 @@ Public Shares Private Shares View Stats + View Statistics View Channel Stats Message Statistic Open Message @@ -4830,6 +4849,21 @@ updated %1$d minutes ago updated %1$d minutes ago updated %1$d minutes ago + now + today + yesterday + %dm + %dm + %dm + %dm + %dm + %dm + %dh + %dh + %dh + %dh + %dh + %dh %1$d minutes ago %1$d minute ago %1$d minutes ago @@ -5924,6 +5958,8 @@ Add up to %d chats into each of your folders Connected Accounts Connect %d accounts with different mobile numbers + Similar Channels + View up to %d similar channels Doubled Limits Sorry, you can\'t add more than **%1$d** accounts. You can increase this limit to **%2$d** by upgrading to **Telegram Premium**. Sorry, you can\'t add more than **%1$d** accounts. @@ -6031,6 +6067,10 @@ Add any of thousands emojis next to your name to display current activity. Real-Time Translation Real-time translation of channels and chats into other languages. + Wallpaper for Both Sides + Set custom wallpapers for you and your chat partner. + Name and Profile Colors + Choose a color and logo for your profile and replies to your messages. Microphone for voice messages Built-In Headset @@ -6271,17 +6311,17 @@ Create Contact Suggested Photo Suggested Video - You suggested %s to use this photo for their account. - You suggested %s to use this video for their account. - %s suggests you to use this photo for your account. - %s suggests you to use this video for your account. + You suggested %s to use this photo for their account + You suggested %s to use this video for their account + %s suggests you to use this photo for your account + %s suggests you to use this video for your account **Photo updated** You can change it in **Settings.** Suggested profile photo Suggested profile video Set as My Photo Invite To Telegram - You allowed this bot to message you when you added it to your attachment menu. + You allowed this bot to message you when you added it to your attachment menu You shared un1 with un2 You shared a user with un2 You shared a chat with un2 @@ -6590,10 +6630,13 @@ You can only have %1$d shareable folders. Try deleting some shareable folder. You can only have %1$d shareable folders. We are working to let you increase this limit in the future. Set Background From Gallery - You set a new wallpaper for this chat. - You set the same wallpaper for the chat. - %s set a new wallpaper for this chat. - %s set a same wallpaper for this chat. + Setting new wallpaper... + You set a new wallpaper for this chat + You set the same wallpaper for the chat + %s set a new wallpaper for this chat + %s set a new wallpaper for this chat + %s set a same wallpaper for this chat + You set a new wallpaper for %s and you Remove Folder Folder already added Add folder @@ -6715,6 +6758,7 @@ Preview this background in night mode. Preview this background in day mode. View Wallpaper + Remove Wallpaper Set a new chat Wallpaper Set a same chat Wallpaper @@ -6760,6 +6804,8 @@ Couldn’t upload Try Again Story + Story Statistics + Post Statistics Message sent. Just now Expired story @@ -7172,11 +7218,24 @@ View Location > Like Long tap for more reactions + Add Reactions... + You can also **create your own** emoji packs and use them. + You can add emoji from any emoji pack as a reaction. + Update Reactions + Level %1$d Required + Level %1$d Required + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions. + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions. + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Custom Reactions + You have changed the list of reactions. Apply changes? + You can select maximum %1$d reaction. + You can select maximum %1$d reactions. 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 @@ -7207,6 +7266,7 @@ list of viewers. Photo Send reaction as a private message Remove Audio + Remove Video Publish story as Who can view your story Style @@ -7249,6 +7309,11 @@ list of viewers. %s just started a giveaway of Telegram Premium subscriptions to its followers. Delete announcement Deleting this message won\'t cancel the giveaway - the winners will still be selected on **%s**.\n\nOnce deleted, the Giveaway Announcement cannot be restored. + %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. + %d winner of the giveaway were randomly selected by Telegram and received private message with giftcode. + %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. + %d undistributed link codes were forwarded to channel administrators. + %d undistributed links codes were forwarded to channel administrators. %d boost %d boost %d boosts @@ -7669,8 +7734,10 @@ list of viewers. Your selected color will also tint the link preview. Apply Color and Icon Subscribe to **Telegram Premium** to choose a custom color for your name. + Subscribe to **Telegram Premium** to choose a custom color for your profile. Add Icons to Replies - Make replies to your messages stand out by adding custom icons to them. + Add Icons to Profile + Choose a color and an icon for your profile Off Off Your Channel Color @@ -7681,7 +7748,12 @@ list of viewers. Your selected color will also tint the link preview. Apply Color and Icon Add Icons to Replies - Make replies to your messages stand out by adding custom icons to them. + Add Icons to Profile + Choose a color and an icon for your profile + Name + Profile + Name + Profile Outdated Quote Quote too long! The selected text is too long to quote. @@ -7698,6 +7770,7 @@ list of viewers. Swipe left or right Warmth Intensity + Dimming Unsaved Changes You have changed your color or icon settings. Apply changes? Unsaved Changes @@ -7705,5 +7778,36 @@ list of viewers. OPEN Your name color has been updated! Your channel color has been updated! + Your profile color has been updated! + Your channel profile color has been updated! + Your profile color has been reset! + Your channel profile color has been reset! + Your profile emoji has been put! + Your channel profile emoji has been put! Copy Code + Similar Channels + Apply for Me + Apply for Me and %s + Set Background + Remove wallpaper + Are you sure you want to reset wallpaper back? + Repost\nStory + Remove Video + Are you sure you want to remove your video message? + You have **%1$d** free voice transcription left. + You have **%1$d** free voice transcriptions left. + You have **%1$d** free voice transcription left until %2$s. + You have **%1$d** free voice transcriptions left until %2$s. + You have used your **%1$d** free transcription this week. + You have used all your **%1$d** free transcriptions this week. + Wait until %1$s or subscribe to **Telegram Premium** now. + Subscribe to **Telegram Premium** to unlock unlimited transcriptions. + Reset Profile Color + Reset Profile Color + Subscribe to **Telegram Premium** to unlock up to %d similar channels. + You can set multiple reactions with Telegram Premium. + More Channels + Unlock more channels + Show More Channels + Subscribe to **Telegram Premium**\nto unlock up to %s similar channels.