diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp index 68ef0738e..b65148290 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 5ab7064f9..9093b19c8 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 0318c1a64..edee2074f 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -339,8 +339,10 @@ public: 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 @@ public: 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 d3dde3c6f..01f4a439f 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.MessageObject; 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 bd3393cde..c7e4b5863 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -454,11 +454,11 @@ public class AndroidUtilities { 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); } @@ -516,6 +516,10 @@ public class AndroidUtilities { } 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("**", ""); @@ -537,7 +541,9 @@ public class AndroidUtilities { @Override public void onClick(@NonNull View view) { - + if (onClick != null) { + onClick.run(); + } } }, index, index + len, 0); } @@ -1061,7 +1067,7 @@ public class AndroidUtilities { 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]; @@ -5461,6 +5467,9 @@ public class AndroidUtilities { } 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/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index dc75af5f0..4c5454d0d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,8 +24,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 4087; - public static String BUILD_VERSION_STRING = "10.2.9"; + public static int BUILD_VERSION = 4139; + public static String BUILD_VERSION_STRING = "10.3.2"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index a6d1c9613..7cb7b1dd1 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 @@ public class ChatObject { } } } + + 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 1726ba893..29cb2c552 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -403,20 +403,59 @@ public class ChatThemeController extends BaseController { 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); @@ -438,6 +477,7 @@ public class ChatThemeController extends BaseController { 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 21aaa4340..fc12553cd 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 @@ class ChatsRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 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 91c576f8d..201dfe5c6 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 @@ public class CodeHighlighting { 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 675b4852d..9e564ee54 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 @@ class ContactsRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactor 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 4f7ce0c49..26d7d02cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1113,25 +1113,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 30c0a43cd..8593d8d63 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1170,6 +1170,11 @@ public class LocaleController { 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) { @@ -1685,6 +1690,42 @@ public class LocaleController { 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 8d1715f3c..bf26ad48b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -613,7 +613,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 55e6b24b8..c577da7e1 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 class MediaDataController extends BaseController { public void checkReactions() { if (!isLoadingReactions && Math.abs(System.currentTimeMillis() / 1000 - reactionsUpdateDate) >= 60 * 60) { - loadReactions(true, false); + loadReactions(true, null); } } @@ -701,7 +701,7 @@ public class MediaDataController extends BaseController { return reactionsList; } - public void loadReactions(boolean cache, boolean force) { + public void loadReactions(boolean cache, Integer lastHash) { isLoadingReactions = true; if (cache) { getMessagesStorage().getStorageQueue().postRunnable(() -> { @@ -741,7 +741,7 @@ public class MediaDataController extends BaseController { }); } 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) { @@ -781,7 +781,7 @@ public class MediaDataController extends BaseController { if (!cache) { putReactionsToCache(reactions, hash, date); } else if (Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) { - loadReactions(false, true); + loadReactions(false, hash); } } @@ -6344,6 +6344,9 @@ public class MediaDataController extends BaseController { } } 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; @@ -6630,12 +6633,7 @@ public class MediaDataController extends BaseController { 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) { @@ -6671,6 +6669,8 @@ public class MediaDataController extends BaseController { 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 36958d2e2..24c2fa93f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -121,6 +121,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; @@ -205,10 +206,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 @@ -417,6 +423,19 @@ public class MessageObject { 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; } @@ -506,6 +525,9 @@ public class MessageObject { 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)); @@ -791,6 +813,7 @@ public class MessageObject { case "dockerfile": case "dart": case "java": + case "fift": return capitalizeFirst(lng); case "http": case "html": @@ -814,7 +837,13 @@ public class MessageObject { 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; } @@ -1772,9 +1801,9 @@ public class MessageObject { } } 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(); @@ -1798,9 +1827,9 @@ public class MessageObject { } 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); @@ -3507,11 +3536,12 @@ public class MessageObject { 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<>(); @@ -3521,26 +3551,47 @@ public class MessageObject { } 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) { @@ -3680,6 +3731,7 @@ public class MessageObject { } 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) { @@ -3729,6 +3781,15 @@ public class MessageObject { } 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) { @@ -4435,7 +4496,10 @@ public class MessageObject { 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) { @@ -4444,7 +4508,7 @@ public class MessageObject { } 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; @@ -4518,7 +4582,7 @@ public class MessageObject { } 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; @@ -4893,6 +4957,16 @@ public class MessageObject { } } } + } 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(); + } } } @@ -5202,7 +5276,6 @@ public class MessageObject { public boolean isVoiceTranscriptionOpen() { return ( - UserConfig.getInstance(currentAccount).isPremium() && messageOwner != null && (isVoice() || isRoundVideo() && TranscribeButton.isVideoTranscriptionOpen(this)) && messageOwner.voiceTranscriptionOpen && @@ -5864,7 +5937,9 @@ public class MessageObject { } public boolean needDrawShareButton() { - if (isSponsored()) { + if (type == TYPE_JOINED_CHANNEL) { + return false; + } else if (isSponsored()) { return false; } else if (hasCode) { return false; @@ -6846,9 +6921,6 @@ public class MessageObject { if (forceAvatar || customAvatarDrawable != null) { return true; } - if (isSponsored() && (isFromChat() || sponsoredShowPeerPhoto)) { - return true; - } return !isSponsored() && (isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null); } @@ -6856,9 +6928,6 @@ public class MessageObject { if (forceAvatar || customAvatarDrawable != null) { return true; } - if (isSponsored() && (isFromChat() || sponsoredShowPeerPhoto)) { - return true; - } return !isSponsored() && (isFromChat() && isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null); } @@ -7963,7 +8032,7 @@ public class MessageObject { } public boolean shouldDrawWithoutBackground() { - return type == TYPE_STICKER || type == TYPE_ANIMATED_STICKER || type == TYPE_ROUND_VIDEO || type == TYPE_EMOJIS || isExpiredStory(); + return !isSponsored() && (type == TYPE_STICKER || type == TYPE_ANIMATED_STICKER || type == TYPE_ROUND_VIDEO || type == TYPE_EMOJIS || isExpiredStory()); } public boolean isAnimatedEmojiStickers() { @@ -9101,17 +9170,25 @@ public class MessageObject { return type == MessageObject.TYPE_GIFT_PREMIUM || type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL; } - private static CharSequence userSpan; + private static CharSequence[] userSpan; public static CharSequence userSpan() { + return userSpan(0); + } + public static CharSequence userSpan(int a) { if (userSpan == null) { - userSpan = new SpannableStringBuilder("u"); + userSpan = new CharSequence[2]; + } + if (userSpan[a] == null) { + userSpan[a] = new SpannableStringBuilder("u"); ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_reply_user); span.spaceScaleX = .9f; - span.translate(0, AndroidUtilities.dp(1)); + if (a == 0) { + span.translate(0, AndroidUtilities.dp(1)); + } // span.setScale(.7f, .7f); - ((SpannableStringBuilder) userSpan).setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ((SpannableStringBuilder) userSpan[a]).setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - return userSpan; + return userSpan[a]; } private static CharSequence groupSpan; public static CharSequence groupSpan() { @@ -9353,9 +9430,8 @@ public class MessageObject { 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; @@ -9364,7 +9440,7 @@ public class MessageObject { 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++; @@ -9380,4 +9456,34 @@ public class MessageObject { 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 c6b72c4af..abba21a22 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.annotation.Nullable; 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; @@ -518,6 +519,14 @@ public class MessagesController extends BaseController implements NotificationCe 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; @@ -1420,7 +1429,16 @@ public class MessagesController extends BaseController implements NotificationCe 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"); @@ -1561,6 +1579,7 @@ public class MessagesController extends BaseController implements NotificationCe } } AndroidUtilities.runOnUIThread(this::loadAppConfig, 2000); + AndroidUtilities.runOnUIThread(() -> checkPeerColors(false), 400); topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); @@ -2187,8 +2206,8 @@ public class MessagesController extends BaseController implements NotificationCe 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) { @@ -3483,24 +3502,6 @@ public class MessagesController extends BaseController implements NotificationCe } break; } - case "peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - peer_colors = (TLRPC.TL_jsonObject) value.value; - } - break; - } - case "dark_peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - dark_peer_colors = (TLRPC.TL_jsonObject) value.value; - } - break; - } - case "peer_colors_available": { - if (value.value instanceof TLRPC.TL_jsonArray) { - peer_colors_available = (TLRPC.TL_jsonArray) value.value; - } - break; - } case "giveaway_gifts_purchase_available": { if (value.value instanceof TLRPC.TL_jsonBool) { if (giveawayGiftsPurchaseAvailable != ((TLRPC.TL_jsonBool) value.value).value) { @@ -3511,15 +3512,85 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + 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 "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 "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; + } + } + break; + } } } - 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) { editor.apply(); @@ -3540,12 +3611,51 @@ public class MessagesController extends BaseController implements NotificationCe 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) { @@ -3555,6 +3665,9 @@ public class MessagesController extends BaseController implements NotificationCe @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(";"); @@ -3563,15 +3676,24 @@ public class MessagesController extends BaseController implements NotificationCe 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; @@ -3580,14 +3702,34 @@ public class MessagesController extends BaseController implements NotificationCe 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); @@ -3600,14 +3742,13 @@ public class MessagesController extends BaseController implements NotificationCe 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); } } @@ -3624,9 +3765,8 @@ public class MessagesController extends BaseController implements NotificationCe 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; @@ -3655,16 +3795,44 @@ public class MessagesController extends BaseController implements NotificationCe 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(); @@ -3672,55 +3840,149 @@ public class MessagesController extends BaseController implements NotificationCe 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) { @@ -3808,9 +4070,9 @@ public class MessagesController extends BaseController implements NotificationCe public void updateConfig(final TLRPC.TL_config config) { AndroidUtilities.runOnUIThread(() -> { - // TODO: receive those removed parameters from appconfig getDownloadController().loadAutoDownloadConfig(false); loadAppConfig(true); + checkPeerColors(true); remoteConfigLoaded = true; maxMegagroupCount = config.megagroup_size_max; maxGroupCount = config.chat_size_max; @@ -4180,7 +4442,7 @@ public class MessagesController extends BaseController implements NotificationCe } } 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; @@ -4195,7 +4457,7 @@ public class MessagesController extends BaseController implements NotificationCe 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)); } } @@ -5518,6 +5780,7 @@ public class MessagesController extends BaseController implements NotificationCe 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 { @@ -14064,14 +14327,18 @@ public class MessagesController extends BaseController implements NotificationCe public void generateJoinMessage(long chatId, boolean ignoreLeft) { TLRPC.Chat chat = getChat(chatId); - if (chat == null || !ChatObject.isChannel(chatId, currentAccount) || (chat.left || chat.kicked) && !ignoreLeft) { + if (chat == null || !ChatObject.isChannel(chatId, currentAccount) || ChatObject.isNotInChat(chat) && !ignoreLeft || chat.creator) { return; } 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 = getConnectionsManager().getCurrentTime(); + if (chat instanceof TLRPC.TL_channel && !ignoreLeft) { + message.date = chat.date; + } else { + message.date = getConnectionsManager().getCurrentTime(); + } message.from_id = new TLRPC.TL_peerUser(); message.from_id.user_id = getUserConfig().getClientUserId(); message.peer_id = new TLRPC.TL_peerChannel(); @@ -14144,67 +14411,65 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.TL_channels_channelParticipant res = (TLRPC.TL_channels_channelParticipant) response; if (res != null && res.participant instanceof TLRPC.TL_channelParticipantSelf) { TLRPC.TL_channelParticipantSelf selfParticipant = (TLRPC.TL_channelParticipantSelf) res.participant; - if (selfParticipant.inviter_id != getUserConfig().getClientUserId() || selfParticipant.via_invite) { - 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); - - 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); - } - - 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); - }); + 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); + + 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 { + message.action = new TLRPC.TL_messageActionChatJoinedByRequest(); + } + message.action.users.add(getUserConfig().getClientUserId()); + 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); + } + + 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); + }); } }); } @@ -14339,6 +14604,8 @@ public class MessagesController extends BaseController implements NotificationCe 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); @@ -15394,6 +15661,11 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new 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) { @@ -16153,6 +16425,11 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -16285,6 +16562,9 @@ public class MessagesController extends BaseController implements NotificationCe if (update.user_id == getUserConfig().getClientUserId()) { getNotificationsController().setLastOnlineFromOtherDevice(update.status.expires); } + } else if (baseUpdate instanceof TLRPC.TL_updatePeerWallpaper) { + TLRPC.TL_updatePeerWallpaper update = (TLRPC.TL_updatePeerWallpaper) baseUpdate; + ChatThemeController.getInstance(currentAccount).processUpdate(update); } else if (baseUpdate instanceof TLRPC.TL_updateUserEmojiStatus) { TLRPC.TL_updateUserEmojiStatus update = (TLRPC.TL_updateUserEmojiStatus) baseUpdate; TLRPC.User currentUser = getUser(update.user_id); @@ -16958,6 +17238,27 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.TL_updateSentStoryReaction updateReaction = (TLRPC.TL_updateSentStoryReaction) baseUpdate; long dialogId = DialogObject.getPeerDialogId(updateReaction.peer); getStoriesController().updateStoryReaction(dialogId, updateReaction.story_id, updateReaction.reaction); + } else if (baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + TLRPC.TL_updateChannelViewForumAsMessages update = (TLRPC.TL_updateChannelViewForumAsMessages) baseUpdate; + TLRPC.ChatFull chatFull = getChatFull(update.channel_id); + if (chatFull != null) { + if (chatFull.view_forum_as_messages != update.enabled) { + chatFull.view_forum_as_messages = update.enabled; + if (update.enabled) { + chatFull.flags2 |= 64; + } else { + chatFull.flags2 &= ~64; + } + getMessagesStorage().updateChatInfo(chatFull, false); + } + } else { + getMessagesController().loadFullChat(update.channel_id, 0, true); + } + TLRPC.Dialog dialog = getDialog(-update.channel_id); + if (dialog != null) { + dialog.view_forum_as_messages = update.enabled; + } + getMessagesStorage().setDialogViewThreadAsMessages(-update.channel_id, update.enabled); } } if (editor != null) { @@ -17616,6 +17917,8 @@ public class MessagesController extends BaseController implements NotificationCe messageObject.sponsoredInfo = sponsoredMessage.sponsor_info; messageObject.sponsoredAdditionalInfo = sponsoredMessage.additional_info; messageObject.sponsoredWebPage = sponsoredMessage.webpage; + messageObject.sponsoredBotApp = sponsoredMessage.app; + messageObject.sponsoredButtonText = sponsoredMessage.button_text; result.add(messageObject); } } @@ -18436,13 +18739,13 @@ public class MessagesController extends BaseController implements NotificationCe fragment.presentFragment(new ProfileActivity(args)); } else if (type == 2) { if (ChatObject.isForum(chat)) { - fragment.presentFragment(new TopicsFragment(args), true, true); + fragment.presentFragment(TopicsFragment.getTopicsOrChat(fragment, args), true, true); } else { fragment.presentFragment(new ChatActivity(args), true, true); } } else { if (ChatObject.isForum(chat)) { - fragment.presentFragment(new TopicsFragment(args), closeLast); + fragment.presentFragment(TopicsFragment.getTopicsOrChat(fragment, args), closeLast); } else { fragment.presentFragment(new ChatActivity(args), closeLast); } @@ -18656,6 +18959,48 @@ public class MessagesController extends BaseController implements NotificationCe }); } + public void setCustomChatReactions(long chatId, int type, List 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); @@ -19143,4 +19488,85 @@ public class MessagesController extends BaseController implements NotificationCe 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 09760b785..18015e67c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -2070,6 +2070,7 @@ public class MessagesStorage extends BaseController { 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(); @@ -8400,6 +8401,9 @@ public class MessagesStorage extends BaseController { 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(); } } @@ -11264,7 +11268,7 @@ public class MessagesStorage extends BaseController { 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); @@ -11561,7 +11565,7 @@ public class MessagesStorage extends BaseController { 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; @@ -12764,6 +12768,7 @@ public class MessagesStorage extends BaseController { 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); @@ -14163,6 +14168,19 @@ public class MessagesStorage extends BaseController { } } } + 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); } @@ -14195,7 +14213,7 @@ public class MessagesStorage extends BaseController { } } - 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); @@ -14296,6 +14314,7 @@ public class MessagesStorage extends BaseController { 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(); @@ -14804,6 +14823,9 @@ public class MessagesStorage extends BaseController { 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; @@ -15113,6 +15135,46 @@ public class MessagesStorage extends BaseController { }); } + 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 d9b304578..8df45b841 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++; @@ -219,6 +220,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 25dc93b92..274bd9fdc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -156,6 +156,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe 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) { @@ -189,6 +191,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe 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; } @@ -3864,6 +3870,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe 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); @@ -3984,6 +3992,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe 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 58d31ed4d..fab279e0e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -335,6 +335,7 @@ public class SharedConfig { public static int storiesColumnsCount = 3; public static int fastScrollHintCount = 3; public static boolean dontAskManageStorage; + public static boolean multipleReactionsPromoShowed; public static boolean translateChats = true; @@ -649,6 +650,7 @@ public class SharedConfig { 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); @@ -862,6 +864,14 @@ public class SharedConfig { 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 a52e23562..5822315ad 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 class TopicsController extends BaseController { }); } + 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 7a55d21ff..6dec98993 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -271,7 +271,7 @@ public class UserConfig extends BaseController { 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 c60c8279d..e2f259b7e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -142,4 +142,33 @@ public class UserObject { 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 001798c0d..b8a7e7d38 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 8b7398c06..031e0a7e4 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.DispatchQueue; 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; @@ -677,6 +678,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur } } + protected boolean square() { + return false; + } + private void updateCameraInfoSize(int i) { ArrayList cameraInfos = CameraController.getInstance().getCameras(); if (cameraInfos == null) { @@ -706,7 +711,11 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur 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; @@ -1962,6 +1971,10 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur }); } + protected void receivedAmplitude(double amplitude) { + + } + private class VideoRecorder implements Runnable { @@ -2078,7 +2091,17 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur 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 931f4281d..63eb63d16 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 class AudioRecoder { } } - 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 f6e5495f2..22d8ec1c2 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 @@ public class MediaCodecVideoConvertor { } 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 @@ public class MediaCodecVideoConvertor { 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 @@ public class MediaCodecVideoConvertor { 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 6a9c203c3..140b797cf 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 class OutputSurface implements SurfaceTexture.OnFrameAvailableListener { 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 4989e1420..57f8bff82 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.AnimatedEmojiDrawable; 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 @@ public class TextureRenderer { 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 class TextureRenderer { } 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 @@ public class TextureRenderer { 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 @@ public class TextureRenderer { if (entity1 == null) { continue; } - drawEntity(entity1, entity.color); + drawEntity(entity1, entity.color, time); } } } @@ -1040,7 +1123,11 @@ public class TextureRenderer { 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 @@ public class TextureRenderer { 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 5b8c0ecbc..f4a1d7273 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 @@ package org.telegram.tgnet; 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; @@ -74,7 +75,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; @@ -5500,30 +5501,65 @@ public class TLRPC { } } - public static class TL_messageInteractionCounters extends TLObject { - public static final int constructor = 0xad4fc9bd; + public static abstract class PostInteractionCounters extends TLObject { + + 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 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 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 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) { @@ -5531,6 +5567,7 @@ public class TLRPC { stream.writeInt32(msg_id); stream.writeInt32(views); stream.writeInt32(forwards); + stream.writeInt32(reactions); } } @@ -13048,6 +13085,7 @@ public class TLRPC { 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; @@ -15529,6 +15567,7 @@ public class TLRPC { 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) { @@ -15671,6 +15710,7 @@ public class TLRPC { 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); @@ -19076,9 +19116,10 @@ public class TLRPC { } 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) { @@ -19095,11 +19136,13 @@ public class TLRPC { 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); } } @@ -23765,8 +23808,8 @@ public class TLRPC { 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 static User TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { User result = null; @@ -23774,8 +23817,8 @@ public class TLRPC { 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(); @@ -23920,6 +23963,208 @@ public class TLRPC { } public static class TL_user extends User { + public static final int constructor = 0x215c4438; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + self = (flags & 1024) != 0; + contact = (flags & 2048) != 0; + mutual_contact = (flags & 4096) != 0; + deleted = (flags & 8192) != 0; + bot = (flags & 16384) != 0; + bot_chat_history = (flags & 32768) != 0; + bot_nochats = (flags & 65536) != 0; + verified = (flags & 131072) != 0; + restricted = (flags & 262144) != 0; + min = (flags & 1048576) != 0; + bot_inline_geo = (flags & 2097152) != 0; + support = (flags & 8388608) != 0; + scam = (flags & 16777216) != 0; + apply_min_photo = (flags & 33554432) != 0; + fake = (flags & 67108864) != 0; + bot_attach_menu = (flags & 134217728) != 0; + premium = (flags & 268435456) != 0; + attach_menu_enabled = (flags & 536870912) != 0; + flags2 = stream.readInt32(exception); + bot_can_edit = (flags2 & 2) != 0; + close_friend = (flags2 & 4) != 0; + stories_hidden = (flags2 & 8) != 0; + stories_unavailable = (flags2 & 16) != 0; + id = stream.readInt64(exception); + if ((flags & 1) != 0) { + access_hash = stream.readInt64(exception); + } + if ((flags & 2) != 0) { + first_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + last_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + username = stream.readString(exception); + } + if ((flags & 16) != 0) { + phone = stream.readString(exception); + } + if ((flags & 32) != 0) { + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16384) != 0) { + bot_info_version = stream.readInt32(exception); + } + if ((flags & 262144) != 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++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 524288) != 0) { + bot_inline_placeholder = stream.readString(exception); + } + if ((flags & 4194304) != 0) { + lang_code = stream.readString(exception); + } + if ((flags & 1073741824) != 0) { + emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 1) != 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++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + try { + if ((flags2 & 32) != 0) { + stories_max_id = stream.readInt32(exception); + } + } catch (Throwable e) { + FileLog.e(e); + } + if ((flags2 & 256) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 512) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + if (username == null) { + flags = flags & ~8; + } + stream.writeInt32(constructor); + flags = self ? (flags | 1024) : (flags &~ 1024); + flags = contact ? (flags | 2048) : (flags &~ 2048); + flags = mutual_contact ? (flags | 4096) : (flags &~ 4096); + flags = deleted ? (flags | 8192) : (flags &~ 8192); + flags = bot ? (flags | 16384) : (flags &~ 16384); + flags = bot_chat_history ? (flags | 32768) : (flags &~ 32768); + flags = bot_nochats ? (flags | 65536) : (flags &~ 65536); + flags = verified ? (flags | 131072) : (flags &~ 131072); + flags = restricted ? (flags | 262144) : (flags &~ 262144); + flags = min ? (flags | 1048576) : (flags &~ 1048576); + flags = bot_inline_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = support ? (flags | 8388608) : (flags &~ 8388608); + flags = scam ? (flags | 16777216) : (flags &~ 16777216); + flags = apply_min_photo ? (flags | 33554432) : (flags &~ 33554432); + flags = fake ? (flags | 67108864) : (flags &~ 67108864); + flags = bot_attach_menu ? (flags | 134217728) : (flags &~ 134217728); + flags = premium ? (flags | 268435456) : (flags &~ 268435456); + flags = attach_menu_enabled ? (flags | 536870912) : (flags &~ 536870912); + stream.writeInt32(flags); + flags2 = bot_can_edit ? (flags2 | 2) : (flags2 &~ 2); + flags2 = close_friend ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_hidden ? (flags2 | 8) : (flags2 &~ 8); + flags2 = stories_unavailable ? (flags2 | 16) : (flags2 &~ 16); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 1) != 0) { + stream.writeInt64(access_hash); + } + if ((flags & 2) != 0) { + stream.writeString(first_name); + } + if ((flags & 4) != 0) { + stream.writeString(last_name); + } + if ((flags & 8) != 0) { + stream.writeString(username); + } + if ((flags & 16) != 0) { + stream.writeString(phone); + } + if ((flags & 32) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 64) != 0) { + status.serializeToStream(stream); + } + if ((flags & 16384) != 0) { + stream.writeInt32(bot_info_version); + } + if ((flags & 262144) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 524288) != 0) { + stream.writeString(bot_inline_placeholder); + } + if ((flags & 4194304) != 0) { + stream.writeString(lang_code); + } + if ((flags & 1073741824) != 0) { + emoji_status.serializeToStream(stream); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 32) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 256) != 0) { + color.serializeToStream(stream); + } + if ((flags2 & 512) != 0) { + profile_color.serializeToStream(stream); + } + } + } + + public static class TL_user_layer166 extends TL_user { public static final int constructor = 0xeb602f25; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -24023,10 +24268,14 @@ public class TLRPC { FileLog.e(e); } if ((flags2 & 128) != 0) { - color = stream.readInt32(exception); + 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); } } @@ -24113,208 +24362,10 @@ public class TLRPC { stream.writeInt32(stories_max_id); } if ((flags2 & 128) != 0) { - stream.writeInt32(color); + stream.writeInt32(color.color); } if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); - } - } - } - - public static class TL_user_layer165_2 extends User { - public static final int constructor = 0x6fdee0df; - - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - self = (flags & 1024) != 0; - contact = (flags & 2048) != 0; - mutual_contact = (flags & 4096) != 0; - deleted = (flags & 8192) != 0; - bot = (flags & 16384) != 0; - bot_chat_history = (flags & 32768) != 0; - bot_nochats = (flags & 65536) != 0; - verified = (flags & 131072) != 0; - restricted = (flags & 262144) != 0; - min = (flags & 1048576) != 0; - bot_inline_geo = (flags & 2097152) != 0; - support = (flags & 8388608) != 0; - scam = (flags & 16777216) != 0; - apply_min_photo = (flags & 33554432) != 0; - fake = (flags & 67108864) != 0; - bot_attach_menu = (flags & 134217728) != 0; - premium = (flags & 268435456) != 0; - attach_menu_enabled = (flags & 536870912) != 0; - flags2 = stream.readInt32(exception); - bot_can_edit = (flags2 & 2) != 0; - close_friend = (flags2 & 4) != 0; - stories_hidden = (flags2 & 8) != 0; - stories_unavailable = (flags2 & 16) != 0; - id = stream.readInt64(exception); - if ((flags & 1) != 0) { - access_hash = stream.readInt64(exception); - } - if ((flags & 2) != 0) { - first_name = stream.readString(exception); - } - if ((flags & 4) != 0) { - last_name = stream.readString(exception); - } - if ((flags & 8) != 0) { - username = stream.readString(exception); - } - if ((flags & 16) != 0) { - phone = stream.readString(exception); - } - if ((flags & 32) != 0) { - photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 64) != 0) { - status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 16384) != 0) { - bot_info_version = stream.readInt32(exception); - } - if ((flags & 262144) != 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++) { - TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - restriction_reason.add(object); - } - } - if ((flags & 524288) != 0) { - bot_inline_placeholder = stream.readString(exception); - } - if ((flags & 4194304) != 0) { - lang_code = stream.readString(exception); - } - if ((flags & 1073741824) != 0) { - emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags2 & 1) != 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++) { - TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - usernames.add(object); - } - } - try { - if ((flags2 & 32) != 0) { - stories_max_id = stream.readInt32(exception); - } - } catch (Throwable e) { - FileLog.e(e); - } - color = stream.readInt32(exception); - if ((flags2 & 64) != 0) { - background_emoji_id = stream.readInt64(exception); - } - } - - public void serializeToStream(AbstractSerializedData stream) { - if (username == null) { - flags = flags & ~8; - } - stream.writeInt32(constructor); - flags = self ? (flags | 1024) : (flags &~ 1024); - flags = contact ? (flags | 2048) : (flags &~ 2048); - flags = mutual_contact ? (flags | 4096) : (flags &~ 4096); - flags = deleted ? (flags | 8192) : (flags &~ 8192); - flags = bot ? (flags | 16384) : (flags &~ 16384); - flags = bot_chat_history ? (flags | 32768) : (flags &~ 32768); - flags = bot_nochats ? (flags | 65536) : (flags &~ 65536); - flags = verified ? (flags | 131072) : (flags &~ 131072); - flags = restricted ? (flags | 262144) : (flags &~ 262144); - flags = min ? (flags | 1048576) : (flags &~ 1048576); - flags = bot_inline_geo ? (flags | 2097152) : (flags &~ 2097152); - flags = support ? (flags | 8388608) : (flags &~ 8388608); - flags = scam ? (flags | 16777216) : (flags &~ 16777216); - flags = apply_min_photo ? (flags | 33554432) : (flags &~ 33554432); - flags = fake ? (flags | 67108864) : (flags &~ 67108864); - flags = bot_attach_menu ? (flags | 134217728) : (flags &~ 134217728); - flags = premium ? (flags | 268435456) : (flags &~ 268435456); - flags = attach_menu_enabled ? (flags | 536870912) : (flags &~ 536870912); - stream.writeInt32(flags); - flags2 = bot_can_edit ? (flags2 | 2) : (flags2 &~ 2); - flags2 = close_friend ? (flags2 | 4) : (flags2 &~ 4); - flags2 = stories_hidden ? (flags2 | 8) : (flags2 &~ 8); - flags2 = stories_unavailable ? (flags2 | 16) : (flags2 &~ 16); - stream.writeInt32(flags2); - stream.writeInt64(id); - if ((flags & 1) != 0) { - stream.writeInt64(access_hash); - } - if ((flags & 2) != 0) { - stream.writeString(first_name); - } - if ((flags & 4) != 0) { - stream.writeString(last_name); - } - if ((flags & 8) != 0) { - stream.writeString(username); - } - if ((flags & 16) != 0) { - stream.writeString(phone); - } - if ((flags & 32) != 0) { - photo.serializeToStream(stream); - } - if ((flags & 64) != 0) { - status.serializeToStream(stream); - } - if ((flags & 16384) != 0) { - stream.writeInt32(bot_info_version); - } - if ((flags & 262144) != 0) { - stream.writeInt32(0x1cb5c415); - int count = restriction_reason.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - restriction_reason.get(a).serializeToStream(stream); - } - } - if ((flags & 524288) != 0) { - stream.writeString(bot_inline_placeholder); - } - if ((flags & 4194304) != 0) { - stream.writeString(lang_code); - } - if ((flags & 1073741824) != 0) { - emoji_status.serializeToStream(stream); - } - if ((flags2 & 1) != 0) { - stream.writeInt32(0x1cb5c415); - int count = usernames.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - usernames.get(a).serializeToStream(stream); - } - } - if ((flags2 & 32) != 0) { - stream.writeInt32(stories_max_id); - } - stream.writeInt32(color); - if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); + stream.writeInt64(color.background_emoji_id); } } } @@ -24422,7 +24473,6 @@ public class TLRPC { } catch (Throwable e) { FileLog.e(e); } - color = (int) (id % 7); } public void serializeToStream(AbstractSerializedData stream) { @@ -26220,6 +26270,9 @@ public class TLRPC { case 0x332ba9ed: result = new TL_messageActionGiveawayLaunch(); break; + case 0x2a9fadc5: + result = new TL_messageActionGiveawayResults(); + break; case 0xea3948e9: result = new TL_messageActionChannelMigrateFrom(); break; @@ -26260,6 +26313,9 @@ public class TLRPC { result = new TL_messageActionCreatedBroadcastList(); break; case 0xbc44a927: + result = new TL_messageActionSetChatWallPaper_layer166(); + break; + case 0x5060a3f4: result = new TL_messageActionSetChatWallPaper(); break; case 0x55555550: @@ -26968,7 +27024,7 @@ public class TLRPC { } } - 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) { @@ -26981,6 +27037,28 @@ public class TLRPC { } } + 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; @@ -29108,6 +29186,7 @@ public class TLRPC { 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; @@ -29121,6 +29200,9 @@ public class TLRPC { 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; @@ -29154,6 +29236,92 @@ public class TLRPC { } 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) { @@ -29638,12 +29806,16 @@ public class TLRPC { } 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; @@ -29654,7 +29826,10 @@ public class TLRPC { 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) { @@ -29674,6 +29849,10 @@ public class TLRPC { 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); @@ -29684,6 +29863,9 @@ public class TLRPC { 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) { @@ -29693,11 +29875,11 @@ public class TLRPC { } 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); } } @@ -29707,6 +29889,10 @@ public class TLRPC { 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); @@ -29717,11 +29903,14 @@ public class TLRPC { 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); } } } @@ -33555,324 +33744,330 @@ public class TLRPC { 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)); @@ -40717,7 +40912,7 @@ public class TLRPC { } 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; @@ -40728,9 +40923,11 @@ public class TLRPC { 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; @@ -40770,6 +40967,9 @@ public class TLRPC { 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); @@ -40788,6 +40988,9 @@ public class TLRPC { entities.add(object); } } + if ((flags & 2048) != 0) { + button_text = stream.readString(exception); + } if ((flags & 128) != 0) { sponsor_info = stream.readString(exception); } @@ -40820,6 +41023,9 @@ public class TLRPC { if ((flags & 512) != 0) { webpage.serializeToStream(stream); } + if ((flags & 1024) != 0) { + app.serializeToStream(stream); + } stream.writeString(message); if ((flags & 2) != 0) { stream.writeInt32(0x1cb5c415); @@ -40829,6 +41035,9 @@ public class TLRPC { entities.get(a).serializeToStream(stream); } } + if ((flags & 2048) != 0) { + stream.writeString(button_text); + } if ((flags & 128) != 0) { stream.writeString(sponsor_info); } @@ -45505,8 +45714,7 @@ public class TLRPC { 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<>(); @@ -45532,8 +45740,8 @@ public class TLRPC { 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(); @@ -45976,6 +46184,173 @@ public class TLRPC { } public static class TL_channel extends Chat { + public static final int constructor = 0x8e87ccd8; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + left = (flags & 4) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + scam = (flags & 524288) != 0; + has_link = (flags & 1048576) != 0; + has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; + call_active = (flags & 8388608) != 0; + call_not_empty = (flags & 16777216) != 0; + fake = (flags & 33554432) != 0; + gigagroup = (flags & 67108864) != 0; + noforwards = (flags & 134217728) != 0; + join_to_send = (flags & 268435456) != 0; + join_request = (flags & 536870912) != 0; + forum = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; + stories_unavailable = (flags2 & 8) != 0; + id = stream.readInt64(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + if ((flags & 512) != 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++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 1) != 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++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = left ? (flags | 4) : (flags &~ 4); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + flags = scam ? (flags | 524288) : (flags &~ 524288); + flags = has_link ? (flags | 1048576) : (flags &~ 1048576); + flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); + flags = call_active ? (flags | 8388608) : (flags &~ 8388608); + flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); + flags = fake ? (flags | 33554432) : (flags &~ 33554432); + flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); + flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); + flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); + flags = join_request ? (flags | 536870912) : (flags &~ 536870912); + flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); + stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); + } + } + } + + public static class TL_channel_layer166 extends TL_channel { public static final int constructor = 0x1981ea7e; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -46064,10 +46439,14 @@ public class TLRPC { stories_max_id = stream.readInt32(exception); } if ((flags2 & 64) != 0) { - color = stream.readInt32(exception); + 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); } } @@ -46140,184 +46519,15 @@ public class TLRPC { stream.writeInt32(stories_max_id); } if ((flags2 & 64) != 0) { - stream.writeInt32(color); + 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 extends TL_channel { - public static final int constructor = 0x2458af8c; - - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - creator = (flags & 1) != 0; - left = (flags & 4) != 0; - broadcast = (flags & 32) != 0; - verified = (flags & 128) != 0; - megagroup = (flags & 256) != 0; - restricted = (flags & 512) != 0; - signatures = (flags & 2048) != 0; - min = (flags & 4096) != 0; - scam = (flags & 524288) != 0; - has_link = (flags & 1048576) != 0; - has_geo = (flags & 2097152) != 0; - slowmode_enabled = (flags & 4194304) != 0; - call_active = (flags & 8388608) != 0; - call_not_empty = (flags & 16777216) != 0; - fake = (flags & 33554432) != 0; - gigagroup = (flags & 67108864) != 0; - noforwards = (flags & 134217728) != 0; - join_to_send = (flags & 268435456) != 0; - join_request = (flags & 536870912) != 0; - forum = (flags & 1073741824) != 0; - flags2 = stream.readInt32(exception); - stories_hidden = (flags2 & 2) != 0; - stories_hidden_min = (flags2 & 4) != 0; - stories_unavailable = (flags2 & 8) != 0; - id = stream.readInt64(exception); - if ((flags & 8192) != 0) { - access_hash = stream.readInt64(exception); - } - title = stream.readString(exception); - if ((flags & 64) != 0) { - username = stream.readString(exception); - } - photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); - date = stream.readInt32(exception); - if ((flags & 512) != 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++) { - TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - restriction_reason.add(object); - } - } - if ((flags & 16384) != 0) { - admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 32768) != 0) { - banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 262144) != 0) { - default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 131072) != 0) { - participants_count = stream.readInt32(exception); - } - if ((flags2 & 1) != 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++) { - TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - usernames.add(object); - } - } - if ((flags2 & 16) != 0) { - stories_max_id = stream.readInt32(exception); - } - color = stream.readInt32(exception); - if ((flags2 & 32) != 0) { - background_emoji_id = stream.readInt64(exception); - } - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = creator ? (flags | 1) : (flags &~ 1); - flags = left ? (flags | 4) : (flags &~ 4); - flags = broadcast ? (flags | 32) : (flags &~ 32); - flags = verified ? (flags | 128) : (flags &~ 128); - flags = megagroup ? (flags | 256) : (flags &~ 256); - flags = restricted ? (flags | 512) : (flags &~ 512); - flags = signatures ? (flags | 2048) : (flags &~ 2048); - flags = min ? (flags | 4096) : (flags &~ 4096); - flags = scam ? (flags | 524288) : (flags &~ 524288); - flags = has_link ? (flags | 1048576) : (flags &~ 1048576); - flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); - flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); - flags = call_active ? (flags | 8388608) : (flags &~ 8388608); - flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); - flags = fake ? (flags | 33554432) : (flags &~ 33554432); - flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); - flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); - flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); - flags = join_request ? (flags | 536870912) : (flags &~ 536870912); - flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); - stream.writeInt32(flags); - flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); - flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); - flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); - stream.writeInt32(flags2); - stream.writeInt64(id); - if ((flags & 8192) != 0) { - stream.writeInt64(access_hash); - } - stream.writeString(title); - if ((flags & 64) != 0) { - stream.writeString(username); - } - photo.serializeToStream(stream); - stream.writeInt32(date); - if ((flags & 512) != 0) { - stream.writeInt32(0x1cb5c415); - int count = restriction_reason.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - restriction_reason.get(a).serializeToStream(stream); - } - } - if ((flags & 16384) != 0) { - admin_rights.serializeToStream(stream); - } - if ((flags & 32768) != 0) { - banned_rights.serializeToStream(stream); - } - if ((flags & 262144) != 0) { - default_banned_rights.serializeToStream(stream); - } - if ((flags & 131072) != 0) { - stream.writeInt32(participants_count); - } - if ((flags2 & 1) != 0) { - stream.writeInt32(0x1cb5c415); - int count = usernames.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - usernames.get(a).serializeToStream(stream); - } - } - if ((flags2 & 16) != 0) { - stream.writeInt32(stories_max_id); - } - stream.writeInt32(color); - if ((flags2 & 32) != 0) { - stream.writeInt64(background_emoji_id); - } - } - } - - public static class TL_channel_layer165_2 extends TL_channel { public static final int constructor = 0x94f592db; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -46405,6 +46615,11 @@ public class TLRPC { 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) { @@ -46475,6 +46690,10 @@ public class TLRPC { 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); + } } } @@ -50103,6 +50322,7 @@ public class TLRPC { 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; @@ -50193,6 +50413,7 @@ public class TLRPC { 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); @@ -50270,6 +50491,7 @@ public class TLRPC { 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) { @@ -51830,6 +52052,7 @@ public class TLRPC { 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; @@ -62625,6 +62848,168 @@ public class TLRPC { } } + 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 { @@ -66603,6 +66988,7 @@ public class TLRPC { 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; @@ -66651,6 +67037,7 @@ public class TLRPC { 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); @@ -66677,6 +67064,7 @@ public class TLRPC { 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); @@ -69347,12 +69735,14 @@ public class TLRPC { } 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) { @@ -69372,6 +69762,10 @@ public class TLRPC { 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) { @@ -69380,6 +69774,10 @@ public class TLRPC { 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); + } } } @@ -70704,9 +71102,10 @@ public class TLRPC { } 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; @@ -70716,8 +71115,11 @@ public class TLRPC { 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); } @@ -70739,10 +71141,58 @@ public class TLRPC { } } + 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; @@ -70754,6 +71204,8 @@ public class TLRPC { 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) { @@ -70821,6 +71273,7 @@ public class TLRPC { 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; @@ -70831,6 +71284,9 @@ public class TLRPC { 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; @@ -70846,6 +71302,70 @@ public class TLRPC { } 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) { @@ -71734,7 +72254,377 @@ public class TLRPC { } } - //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 dbf55895c..f2d7899d2 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 class TL_stories { } 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 class TL_stories { 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 class TL_stories { 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 class TL_stories { 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 class TL_stories { 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 class TL_stories { 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 class TL_stories { 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 class TL_stories { } } + 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 class TL_stories { 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 977ae9300..304910e89 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -63,6 +63,7 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugController; 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; @@ -250,10 +251,27 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F 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(); @@ -1237,14 +1255,16 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F 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()); @@ -2052,7 +2072,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F 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 28c1b073c..8ea9ed562 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -1864,6 +1864,17 @@ public class ActionBarMenuItem extends FrameLayout { } } + 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 1f482cee9..8dd2cd34b 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.graphics.drawable.Drawable; 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; @@ -81,7 +82,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; @@ -822,7 +823,8 @@ public abstract class BaseFragment { 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(); @@ -843,8 +845,13 @@ public abstract class BaseFragment { 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 @@ -853,8 +860,17 @@ public abstract class BaseFragment { } @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 @@ -902,6 +918,7 @@ public abstract class BaseFragment { bottomSheet[0].transitionFromRight(params.transitionFromLeft); } fragment.setParentDialog(bottomSheet[0]); + bottomSheet[0].setOpenNoDelay(true); bottomSheet[0].show(); return actionBarLayout; @@ -928,7 +945,7 @@ public abstract class BaseFragment { } 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); } @@ -1093,12 +1110,17 @@ public abstract class BaseFragment { 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; } } \ No newline at end of file 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 0711bd2a8..67f034d89 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.graphics.drawable.Drawable; 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; @@ -342,6 +343,7 @@ public class BottomSheet extends Dialog { private float y = 0f; private float swipeBackX = 0f; + private boolean allowedSwipeToBack; public boolean processTouchEvent(MotionEvent ev, boolean intercept) { if (dismissed) { return false; @@ -349,8 +351,9 @@ public class BottomSheet extends Dialog { 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); @@ -418,6 +421,7 @@ public class BottomSheet extends Dialog { 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)) { @@ -434,7 +438,7 @@ public class BottomSheet extends Dialog { 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(); } @@ -474,7 +478,7 @@ public class BottomSheet extends Dialog { startedTrackingPointerId = -1; } } - return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack()); + return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack(ev)); } @Override @@ -566,7 +570,7 @@ public class BottomSheet extends Dialog { 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(); @@ -668,7 +672,7 @@ public class BottomSheet extends Dialog { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (canDismissWithSwipe() || canSwipeToBack()) { + if (canDismissWithSwipe() || canSwipeToBack(event)) { return processTouchEvent(event, true); } return super.onInterceptTouchEvent(event); @@ -758,7 +762,7 @@ public class BottomSheet extends Dialog { 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); } @@ -1113,7 +1117,7 @@ public class BottomSheet extends Dialog { } public void fixNavigationBar(int bgColor) { - drawNavigationBar = true; + drawNavigationBar = !occupyNavigationBar; drawDoubleNavigationBar = true; scrollNavBar = true; navBarColorKey = -1; @@ -1324,7 +1328,10 @@ public class BottomSheet extends Dialog { } 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); @@ -1664,7 +1671,7 @@ public class BottomSheet extends Dialog { 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 d58d58a22..38a52e7fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -367,7 +367,7 @@ public class SimpleTextView extends View implements Drawable.Callback { 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); @@ -386,7 +386,7 @@ public class SimpleTextView extends View implements Drawable.Callback { 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); @@ -395,7 +395,7 @@ public class SimpleTextView extends View implements Drawable.Callback { 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 4f9aecb94..a007d091d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -126,11 +126,13 @@ import org.telegram.ui.Components.TypingDotsDrawable; import org.telegram.ui.LaunchActivity; import org.telegram.ui.RoundVideoProgressShadow; import org.telegram.ui.ThemeActivity; +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; @@ -1453,7 +1455,7 @@ public class Theme { } 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); } @@ -1466,7 +1468,7 @@ public class Theme { 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); @@ -1508,7 +1510,7 @@ public class Theme { } 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); } @@ -1528,7 +1530,7 @@ public class Theme { } 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); } @@ -1994,7 +1996,9 @@ public class Theme { 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); } @@ -2045,6 +2049,7 @@ public class Theme { public long wallpaperId; public long accessHash; public long dialogId; + public boolean forBoth; public ThemeInfo parentTheme; public ThemeAccent parentAccent; @@ -2971,6 +2976,12 @@ public class Theme { 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); } @@ -3070,8 +3081,6 @@ public class Theme { 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; @@ -3090,7 +3099,7 @@ public class Theme { 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; @@ -3176,8 +3185,6 @@ public class Theme { 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; @@ -3293,6 +3300,7 @@ public class Theme { 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; @@ -4174,6 +4182,7 @@ public class Theme { 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"; @@ -4183,6 +4192,7 @@ public class Theme { 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"; @@ -4202,11 +4212,11 @@ public class Theme { 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; @@ -4515,7 +4525,7 @@ public class Theme { 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(); @@ -5290,6 +5300,14 @@ public class Theme { } 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(); @@ -5299,9 +5317,9 @@ public class Theme { 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)); } } @@ -6542,6 +6560,24 @@ public class Theme { 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; @@ -6551,7 +6587,7 @@ public class Theme { 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) { @@ -6609,7 +6645,7 @@ public class Theme { } 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]; } @@ -6618,7 +6654,7 @@ public class Theme { 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); @@ -8098,6 +8134,7 @@ public class Theme { 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); @@ -8503,7 +8540,7 @@ public class Theme { 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")); @@ -8513,13 +8550,12 @@ public class Theme { 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); @@ -8647,6 +8683,7 @@ public class Theme { 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); @@ -8741,6 +8778,7 @@ public class Theme { 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); @@ -8994,6 +9032,18 @@ public class Theme { 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 { @@ -9006,7 +9056,7 @@ public class Theme { } 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; } @@ -9033,40 +9083,44 @@ public class Theme { 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(); } @@ -9115,28 +9169,85 @@ public class Theme { 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() { applyChatMessageSelectedBackgroundColor(null, wallpaper); } @@ -9285,7 +9396,7 @@ public class Theme { 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; } @@ -9567,8 +9678,6 @@ public class Theme { int[] result = AndroidUtilities.calcDrawableColor(drawable); serviceMessageColor = serviceMessageColorBackup = result[0]; serviceSelectedMessageColor = serviceSelectedMessageColorBackup = result[1]; - serviceMessage2Color = result[2]; - serviceSelectedMessage2Color = result[3]; } } @@ -9651,7 +9760,8 @@ public class Theme { hasPreviousTheme, isApplyingAccent, wallpaperMotion, - finalWallpaperDocument + finalWallpaperDocument, + false ); isWallpaperMotion = settings.isWallpaperMotion != null ? settings.isWallpaperMotion : isWallpaperMotion; isPatternWallpaper = settings.isPatternWallpaper != null ? settings.isPatternWallpaper : isPatternWallpaper; @@ -9660,6 +9770,7 @@ public class Theme { wallpaper = settings.wallpaper != null ? settings.wallpaper : wallpaper; Drawable drawable = settings.wallpaper; calcBackgroundColor(drawable, 1); + applyChatServiceMessageColor(); return drawable; } @@ -9668,7 +9779,8 @@ public class Theme { 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); @@ -9680,7 +9792,7 @@ public class Theme { : (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( @@ -9696,10 +9808,11 @@ public class Theme { 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 a39368786..da994f514 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -1365,7 +1365,7 @@ public class ThemeColors { 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 238aff2eb..cc43dbee9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -112,6 +112,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; @@ -163,11 +164,13 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { 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) { @@ -176,7 +179,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @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); } @@ -244,9 +247,10 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { 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) { @@ -1418,7 +1422,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { 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 000000000..ef6c0614f --- /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 9e4877b79..aadf792bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -3167,7 +3167,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe @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 fb6115a9d..e92aade49 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java @@ -21,7 +21,6 @@ import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -122,7 +121,7 @@ public class AccountSelectCell extends FrameLayout { 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 680a24b78..c7c1bcfc3 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 class AdminedChannelCell extends FrameLayout { 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 class AdminedChannelCell extends FrameLayout { } 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 000000000..b1438fc89 --- /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 1dcd5a6f6..6c683cbd3 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.graphics.RectF; 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.View; 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.Components.spoilers.SpoilerEffect; 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 java.util.ArrayList; import java.util.HashMap; @@ -156,6 +164,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD default void didClickImage(ChatActionCell cell) { } + default void didClickButton(ChatActionCell cell) { + } + default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, boolean animateConfetti) { } @@ -231,6 +242,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD TextPaint textPaint; private float viewTop; + private float viewTranslationX; private int backgroundHeight; private boolean visiblePartSet; @@ -265,8 +277,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -340,7 +354,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -420,7 +434,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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()) { @@ -429,6 +443,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -436,7 +451,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -518,7 +533,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -669,6 +684,20 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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 @@ -749,7 +778,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -777,7 +806,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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); + } } } } @@ -943,7 +976,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } private void createLayout(CharSequence text, int width) { - int maxWidth = width - AndroidUtilities.dp(30); + int maxWidth = width - dp(30); if (maxWidth < 0) { return; } @@ -981,7 +1014,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD FileLog.e(e); } textX = (width - textWidth) / 2; - textY = AndroidUtilities.dp(7); + textY = dp(7); textXLeft = (width - textLayout.getWidth()) / 2; spoilersPool.addAll(spoilers); @@ -996,22 +1029,22 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1020,9 +1053,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); } } @@ -1032,36 +1065,36 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1072,25 +1105,25 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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)); } } @@ -1101,7 +1134,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; } @@ -1124,9 +1157,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); } @@ -1140,11 +1173,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1153,24 +1186,24 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1178,13 +1211,18 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1199,9 +1237,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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; @@ -1211,9 +1249,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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)); @@ -1246,18 +1284,20 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1265,18 +1305,30 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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)); } - giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + 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; + } + } + 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; } } @@ -1292,6 +1344,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD return maxWidth; } + public boolean showingCancelButton() { + return radialProgress != null && radialProgress.getIcon() == MediaActionDrawable.ICON_CANCEL; + } + public int getCustomDate() { return customDate; } @@ -1301,10 +1357,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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()) { @@ -1316,10 +1372,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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) { @@ -1354,7 +1410,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1366,8 +1422,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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); @@ -1402,18 +1458,18 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); } } @@ -1421,26 +1477,40 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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()); @@ -1452,7 +1522,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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(); @@ -1464,7 +1535,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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(); @@ -1474,30 +1545,36 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } 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); @@ -1505,16 +1582,18 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1539,7 +1618,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1551,7 +1630,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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(); } @@ -1567,7 +1646,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1587,6 +1666,19 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } + @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) { @@ -1597,6 +1689,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } 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); @@ -1605,7 +1698,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1615,8 +1708,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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++) { @@ -1640,12 +1733,12 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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(); @@ -1659,10 +1752,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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; @@ -1686,12 +1779,12 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); @@ -1744,22 +1837,35 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - backgroundPaint.setAlpha((int) (oldAlpha * getAlpha())); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * 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 = 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; @@ -1767,26 +1873,26 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD 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); } } @@ -1925,6 +2031,10 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } + 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 9bca14fc9..c34e19cd4 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 class ChatLoadingCell extends FrameLayout { 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 5845d4666..0396fb8d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -207,6 +207,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public ExpiredStoryView expiredStoryView; private boolean skipFrameUpdate; + public ChannelRecommendationsCell channelRecommendationsCell; + public RadialProgress2 getRadialProgress() { return radialProgress; } @@ -271,7 +273,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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) { @@ -279,7 +281,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { currentPhoto = null; } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); avatarImage.setForUserOrChat(currentChat, avatarDrawable); } else if (messageObject.isSponsored()) { if (messageObject.sponsoredWebPage != null) { @@ -289,10 +291,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -500,6 +502,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } + 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) { } @@ -748,7 +762,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int unmovedTextX; private int linkPreviewY; public int textY; - private int totalHeight; + public int totalHeight; private int additionalTimeOffsetY; private int keyboardHeight; private int linkBlockNum; @@ -850,6 +864,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean drawInstantView; private boolean pollInstantViewTouchesBottom; public int drawInstantViewType; + public String instantViewButtonText; private int imageBackgroundColor; private float imageBackgroundIntensity; private int imageBackgroundGradientColor1; @@ -945,6 +960,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -992,7 +1009,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int seekBarY; private boolean useTranscribeButton; - private TranscribeButton transcribeButton; + public TranscribeButton transcribeButton; private float transcribeX, transcribeY; private StaticLayout durationLayout; @@ -1213,8 +1230,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean drawName; private boolean drawNameLayout; - private Paint closeSponsoredPaint; - private Path closeSponsoredPath; private ButtonBounce closeSponsoredBounce; private RectF closeSponsoredBounds; @@ -2133,7 +2148,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 { @@ -3247,6 +3262,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); } @@ -3391,7 +3412,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; } @@ -3605,7 +3630,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -3614,7 +3641,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; } } @@ -3912,7 +3942,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -4382,6 +4412,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.detach(this); } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onDetachedFromWindow(); + } } @Override @@ -4468,6 +4501,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate mediaSpoilerEffect2.attach(this); } } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onAttachedToWindow(); + } } boolean imageReceiversAttachState; @@ -4753,7 +4789,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawVideoSize = false; canStreamVideo = false; animatingNoSound = 0; - if (MessagesController.getInstance(currentAccount).isChatNoForwards(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards)) { + if (messageObject.isSponsored()) { + drawSideButton = 4; + } else if (MessagesController.getInstance(currentAccount).isChatNoForwards(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards)) { drawSideButton = 0; } else { drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) && (currentPosition == null || currentPosition.last) ? 1 : 0; @@ -4843,6 +4881,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate docTitleLayout = null; drawImageButton = false; drawVideoImageButton = false; + currentPhotoLocation = null; + currentPhotoThumbLocation = null; currentPhotoObject = null; photoParentObject = null; currentPhotoObjectThumb = null; @@ -4864,6 +4904,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate useTranscribeButton = false; drawInstantView = false; drawInstantViewType = 0; + instantViewButtonText = null; drawForwardedName = false; drawCommentButton = false; photoImage.setSideClip(0); @@ -4976,10 +5017,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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, "", ""); @@ -5035,11 +5076,24 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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(); @@ -5058,7 +5112,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -5111,7 +5165,27 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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)) { @@ -5304,7 +5378,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -5351,6 +5429,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate String title; CharSequence author; String description; + TLObject peerPhoto = null; TLRPC.Photo photo; TLRPC.Document document; WebFile webDocument; @@ -5358,7 +5437,43 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -5638,12 +5753,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); @@ -5655,7 +5771,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; } @@ -5910,6 +6026,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } + } 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); @@ -5931,7 +6058,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; @@ -6140,9 +6267,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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) { @@ -6227,11 +6358,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -6343,7 +6474,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); @@ -6611,7 +6742,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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), "", ""); @@ -6975,13 +7106,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -7145,7 +7276,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -8144,25 +8275,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - 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(); @@ -8456,6 +8568,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -8590,7 +8703,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (replySelector != null) { replySelectorPressed = false; - replySelector.setState(new int[]{}); + replySelector.setState(StateSet.NOTHING); invalidate(); } if (nameStatusSelector != null) { @@ -8920,11 +9033,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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() @@ -9146,7 +9271,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -9175,9 +9300,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; } @@ -9217,7 +9342,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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++) { @@ -9612,7 +9737,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -9848,14 +9975,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -10667,6 +10796,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate }; 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( @@ -10812,7 +10942,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -11129,9 +11259,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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()) { @@ -11174,7 +11301,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -11187,7 +11314,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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(); @@ -11446,7 +11573,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -11876,14 +12003,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -11898,7 +12027,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public void drawMessageText(Canvas canvas) { - if (currentMessageObject == null) { + if (currentMessageObject == null || currentMessageObject.isSponsored()) { return; } float textY = this.textY; @@ -13492,11 +13621,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } 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) { @@ -14394,6 +14519,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.forceAvatar) { return true; } + if (currentMessageObject.isSponsored()) { + return false; + } if (currentMessageObject.isGiveaway()) { return false; } @@ -14410,6 +14538,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; } @@ -14481,7 +14612,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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) { @@ -14591,6 +14722,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -15226,6 +15365,50 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -15300,6 +15483,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public boolean hasOutboundsContent() { + if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + return true; + } if (getAlpha() != 1f) { return false; } @@ -15317,6 +15503,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); } @@ -15360,11 +15550,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); + 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]); @@ -15372,7 +15562,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); } @@ -15448,6 +15638,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; @@ -15477,7 +15670,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; @@ -15510,7 +15703,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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(); } } @@ -15555,22 +15752,29 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 (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 (!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); @@ -15608,6 +15812,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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); @@ -15890,11 +16104,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); + 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])); @@ -15902,7 +16116,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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)); } @@ -16023,38 +16237,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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(); } } @@ -16158,12 +16340,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { @@ -16172,7 +16354,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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())); } } } @@ -16364,7 +16546,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); } @@ -16376,7 +16558,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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); } @@ -16568,7 +16750,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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(); } @@ -16589,7 +16771,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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(); } @@ -17252,7 +17434,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public boolean needDrawTime() { - return !forceNotDrawTime; + return !forceNotDrawTime && (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL); } public boolean shouldDrawTimeOnMedia() { @@ -17266,6 +17448,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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()) { @@ -17402,7 +17587,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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) { @@ -20668,6 +20853,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public int lastReplyTextXOffset; public float animateReplyTextOffset; + public boolean lastDrawingRecommendationsExpanded; + public boolean animateRecommendationsExpanded; + public boolean animateFromRecommendationsExpanded; + public void recordDrawingState() { wasDraw = true; lastDrawingImageX = photoImage.getImageX(); @@ -20694,6 +20883,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastDrawingLinkPreviewHeight = linkPreviewHeight; lastDrawingLinkAbove = linkPreviewAbove; + lastDrawingRecommendationsExpanded = currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); + if (commentLayout != null) { lastCommentsCount = getRepliesCount(); lastTotalCommentWidth = totalCommentWidth; @@ -20868,6 +21059,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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; @@ -21135,6 +21334,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animateSign = false; animateSmallImage = false; animateLinkAbove = false; + animateRecommendationsExpanded = false; animateDrawingTimeAlpha = false; animateLocationIsExpired = false; animatePlayingRound = false; @@ -21222,4 +21422,32 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 aa3bbd2b2..d878df5f9 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.annotation.SuppressLint; 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.Spanned; 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; @@ -2175,7 +2176,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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); } } @@ -2886,10 +2887,10 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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); @@ -2900,7 +2901,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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); } } @@ -3387,7 +3388,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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(); @@ -3432,7 +3433,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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); } @@ -3466,7 +3467,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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++) { @@ -3479,7 +3480,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } 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(); @@ -3574,7 +3575,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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++) { @@ -3587,7 +3588,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } 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(); } @@ -5234,4 +5235,17 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } } + + 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 6adfb8b54..314dd8378 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 class DialogMeUrlCell extends BaseCell { 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 class DialogMeUrlCell extends BaseCell { drawVerified = user.verified; } 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 class DialogMeUrlCell extends BaseCell { 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.verified; 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 a50ffbd07..b52279776 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -135,7 +135,7 @@ public class DrawerUserCell extends FrameLayout implements NotificationCenter.No 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 c62b1365b..74ef91919 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.FrameLayout; 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 bcbccaa0b..48a236803 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.LiteMode; 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 class GroupCallUserCell extends FrameLayout { 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.verified) { @@ -509,7 +509,7 @@ public class GroupCallUserCell extends FrameLayout { } 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 bf500bcc2..53b5ccfb3 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 class GroupCreateUserCell extends FrameLayout { return; } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); lastStatus = currentUser.status != null ? currentUser.status.expires : 0; if (currentName != null) { @@ -374,7 +374,7 @@ public class GroupCreateUserCell extends FrameLayout { } } - 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 1a254677e..280caf3af 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 class HintDialogCell extends FrameLayout { } }; 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 class HintDialogCell extends FrameLayout { 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 class HintDialogCell extends FrameLayout { 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 class HintDialogCell extends FrameLayout { } 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 class HintDialogCell extends FrameLayout { } 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 5ae3384b5..671ac9bbe 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 android.widget.TextView; 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 21f1205ca..c1478c2bd 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.UserConfig; 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 class ManageChatUserCell extends FrameLayout { 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 class ManageChatUserCell extends FrameLayout { } } + 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 class ManageChatUserCell extends FrameLayout { 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 class ManageChatUserCell extends FrameLayout { avatarImageView.setImageDrawable(null); return; } - currrntStatus = status; + currentStatus = status; currentName = name; currentObject = object; if (optionsButton != null) { @@ -229,7 +258,7 @@ public class ManageChatUserCell extends FrameLayout { } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { @@ -243,9 +272,9 @@ public class ManageChatUserCell extends FrameLayout { 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 class ManageChatUserCell extends FrameLayout { } } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentName != null) { lastName = null; @@ -302,9 +331,9 @@ public class ManageChatUserCell extends FrameLayout { 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 class ManageChatUserCell extends FrameLayout { } 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 de252724e..f96144722 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -33,11 +33,11 @@ import org.telegram.ui.Components.LayoutHelper; 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 4030f5c3a..01797c4dd 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 android.widget.TextView; 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 class NotificationsCheckCell extends FrameLayout { 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 63ca326c3..dbd87813e 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 @@ package org.telegram.ui.Cells; 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.UserConfig; 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.CheckBox2; 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; @@ -134,6 +132,13 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No 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); @@ -367,7 +372,19 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No 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; @@ -492,6 +509,18 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No } 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); @@ -581,7 +610,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No 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); @@ -606,7 +635,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No 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); @@ -687,10 +716,17 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No } 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 ae37d0cc6..616957c36 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.BackupImageView; 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 class ReactedUserHolderView extends FrameLayout { 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 4e6a15801..a48fe493c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java @@ -236,7 +236,7 @@ public class SessionCell extends FrameLayout { 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 6c5d83b3d..694593da1 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.view.accessibility.AccessibilityNodeInfo; 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.BackupImageView; 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 class ShareDialogCell extends FrameLayout { 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 class ShareDialogCell extends FrameLayout { 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 class ShareDialogCell extends FrameLayout { }); 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 class ShareDialogCell extends FrameLayout { } 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 class ShareDialogCell extends FrameLayout { } 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 class ShareDialogCell extends FrameLayout { 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 class ShareDialogCell extends FrameLayout { 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 @@ public class ShareDialogCell extends FrameLayout { 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 @@ public class ShareDialogCell extends FrameLayout { 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 class ShareDialogCell extends FrameLayout { 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 4ad4eb637..81ef27e44 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.BackupImageView; 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 class SharingLiveLocationCell extends FrameLayout { 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 class SharingLiveLocationCell extends FrameLayout { 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 6360a6e0d..f625af089 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.FrameLayout; 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; +import java.util.Date; + +@SuppressLint("ViewConstructor") public class StatisticPostInfoCell extends FrameLayout { - private TextView message; - private TextView views; - private TextView shares; - private TextView date; - private BackupImageView imageView; - private AvatarDrawable avatarDrawable = new AvatarDrawable(); - + 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; + message = new SimpleTextView(context) { @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); - } - - @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 @@ public class StatisticPostInfoCell extends FrameLayout { 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)); + } - addView(contentLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.NO_GRAVITY, 72, 0, 12, 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, !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 void setData(StatisticActivity.RecentPostInfo postInfo) { + public BackupImageView getImageView() { + return imageView; + } + + public StoriesUtilities.AvatarStoryParams getStoryAvatarParams() { + return storyAvatarParams; + } + + public StatisticActivity.RecentPostInfo getPostInfo() { + return 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))); - 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))); + 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)); + + 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 class StatisticPostInfoCell extends FrameLayout { 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 b0b5e1b10..61b7f2958 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.Paint; 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.LayoutHelper; 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 class TextCell extends FrameLayout { 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); } } @@ -408,7 +425,7 @@ public class TextCell extends FrameLayout { setTextAndValueAndIcon(text, value, false, resId, divider); } - public void setTextAndValueAndIcon(String text, String value, boolean animated, int resId, boolean divider) { + public void setTextAndValueAndIcon(CharSequence text, String value, boolean animated, int resId, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); @@ -428,6 +445,15 @@ public class TextCell extends FrameLayout { } } + 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 988d204d1..dac002634 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java @@ -33,7 +33,7 @@ import org.telegram.ui.Components.LinkSpanDrawable; 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 39fcda257..8294b7c2e 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 class ThemePreviewMessagesCell extends LinearLayout { 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 class ThemePreviewMessagesCell extends LinearLayout { 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 class ThemePreviewMessagesCell extends LinearLayout { 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 class ThemePreviewMessagesCell extends LinearLayout { } 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 @@ public class ThemePreviewMessagesCell extends LinearLayout { 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 class ThemePreviewMessagesCell extends LinearLayout { } } + 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 bbdfa1634..67386d2cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -505,14 +505,14 @@ public class UserCell extends FrameLayout implements NotificationCenter.Notifica ((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 95cc8d1d1..a6610cb8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java @@ -228,14 +228,14 @@ public class UserCell2 extends FrameLayout { 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 1b47e52b4..a03937c11 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2090,6 +2090,9 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } 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 1529283d9..296c09793 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java @@ -62,6 +62,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); @@ -223,9 +224,15 @@ public abstract class BaseChartView 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(); } @@ -259,23 +266,23 @@ public abstract class BaseChartView } 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(); @@ -726,13 +733,13 @@ public abstract class BaseChartView 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, @@ -1589,10 +1596,16 @@ public abstract class BaseChartView 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; @@ -1606,8 +1619,8 @@ public abstract class BaseChartView 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 1a360db04..a604d66c0 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 @@ import org.telegram.ui.Charts.view_data.LineViewData; 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 @@ public class DoubleLinearChartView extends BaseChartView 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 @@ public class DoubleLinearChartView extends BaseChartView { datesTmp.setPivotX(datesTmp.getMeasuredWidth() * 0.7f); @@ -87,11 +93,11 @@ public class ChartHeaderView extends FrameLayout { 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 class ChartHeaderView extends FrameLayout { } 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 c1091e04c..056965b8c 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 class LegendSignatureView extends FrameLayout { }; 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 class LegendSignatureView extends FrameLayout { } 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 class LegendSignatureView extends FrameLayout { 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 7c81692e8..0d1f7256a 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 class LineViewData { 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 62b09d71e..9ca28a2c4 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 b9c8d3900..c6dcf3daa 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; @@ -45,6 +47,7 @@ import android.graphics.RectF; 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; @@ -254,6 +257,7 @@ import org.telegram.ui.Components.InviteMembersBottomSheet; 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; @@ -733,7 +737,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; @@ -808,6 +812,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public int highlightMessageId = Integer.MAX_VALUE; public boolean showNoQuoteAlert; public String highlightMessageQuote; + public int highlightMessageQuoteOffset = -1; private int scrollToMessagePosition = -10000; private Runnable unselectRunnable; @@ -920,6 +925,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int contentPaddingTop; private float contentPanTranslation; + private float contentPanTranslationT; private float floatingDateViewOffset; private float topChatPanelViewOffset; private float pinnedMessageEnterOffset; @@ -1148,6 +1154,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return isTopic ? threadMessageId : 0; } + public boolean isForumInViewAsMessagesMode() { + return ChatObject.isForum(currentChat) && !isTopic; + } + @Override public List onGetDebugItems() { List items = new ArrayList<>(); @@ -1387,7 +1397,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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; } @@ -1533,6 +1543,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); } @@ -1561,7 +1584,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } ChatMessageCell cell = (ChatMessageCell) view; MessageObject primaryMessage = cell.getPrimaryMessageObject(); - if (primaryMessage.isSecretMedia() || primaryMessage.isExpiredStory()) { + if (primaryMessage.isSecretMedia() || primaryMessage.isExpiredStory() || primaryMessage.type == MessageObject.TYPE_JOINED_CHANNEL) { return; } ReactionsEffectOverlay.removeCurrent(false); @@ -1673,7 +1696,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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()) { @@ -2413,6 +2436,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -2780,6 +2805,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); } @@ -3017,6 +3044,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else if (id == view_as_topics) { + getMessagesController().getTopicsController().toggleViewForumAsMessages(-dialog_id, false); TopicsFragment.prepareToSwitchAnimation(ChatActivity.this); } else if (id == copy) { SpannableStringBuilder str = new SpannableStringBuilder(); @@ -4016,18 +4044,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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()) { slidingView.setSlidingOffset(0); slidingView = null; @@ -4383,8 +4405,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); @@ -5736,8 +5762,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); @@ -5746,6 +5793,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -9702,7 +9753,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -11385,11 +11436,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; } @@ -11680,12 +11731,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } 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) { @@ -12531,8 +12597,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -12565,6 +12631,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -12573,7 +12645,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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; @@ -12637,13 +12709,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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()); } @@ -12918,6 +12995,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + 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() { @@ -13007,7 +13095,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 0; } - int index = text.toString().indexOf(highlightMessageQuote); + int index = MessageObject.findQuoteStart(text.toString(), highlightMessageQuote, highlightMessageQuoteOffset); if (index < 0) { return 0; } @@ -13052,6 +13140,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not unselectRunnable = () -> { highlightMessageId = Integer.MAX_VALUE; highlightMessageQuote = null; + highlightMessageQuoteOffset = -1; showNoQuoteAlert = false; updateVisibleRows(); unselectRunnable = null; @@ -13494,6 +13583,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } contentPanTranslation = y; + contentPanTranslationT = progress; if (chatAttachAlert != null && chatAttachAlert.isShowing()) { setNonNoveTranslation(y); } else { @@ -14673,6 +14763,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not emptyViewContainer.setTranslationY(0); progressView.setTranslationY(0); contentPanTranslation = 0; + contentPanTranslationT = 0; contentView.setBackgroundTranslation(0); if (instantCameraView != null) { instantCameraView.onPanTranslationUpdate(0); @@ -15264,6 +15355,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -15271,7 +15369,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; } @@ -15414,7 +15512,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); @@ -16757,7 +16855,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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()) { @@ -17871,6 +17968,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (pendingRequestsDelegate != null) { pendingRequestsDelegate.setChatInfo(chatInfo, true); } + checkLeaveChannelButton(); } } else if (id == NotificationCenter.chatInfoCantLoad) { long chatId = (Long) args[0]; @@ -19023,6 +19121,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); loadingPinnedMessagesList = true; } + updateVisibleWallpaperActions(); } } else if (id == NotificationCenter.didSetNewWallpapper) { if (fragmentView != null) { @@ -19349,6 +19448,41 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); + } + } + } + } } } @@ -19918,7 +20052,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not wallpaper = ((SizeNotifierFrameLayout) fragmentView).getBackgroundImage(); } if (wallpaper instanceof ChatBackgroundDrawable) { - wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(); + wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(true); } if (wallpaper instanceof MotionBackgroundDrawable) { ((MotionBackgroundDrawable) wallpaper).switchToNextPosition(); @@ -19958,12 +20092,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; } } @@ -20643,7 +20784,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (scrollToMessageObject != null) { int scrollToIndex = messages.indexOf(scrollToMessageObject); if (scrollToIndex > 0) { - chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); +// chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); } } } @@ -21242,7 +21383,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @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))) { @@ -21646,7 +21787,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (bottomOverlayChatText == null || chatMode == MODE_SCHEDULED || getContext() == null) { return; } - boolean haveBeenWaiting = bottomOverlayChatWaitsReply; bottomOverlayChatWaitsReply = false; if (reportType >= 0) { updateActionModeTitle(); @@ -21692,7 +21832,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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)); @@ -21715,7 +21855,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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)); @@ -21897,7 +22037,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); @@ -21948,6 +22088,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -23837,8 +24001,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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; @@ -23930,25 +24094,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); + } } } } @@ -24291,11 +24458,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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()) { @@ -24973,7 +25150,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not isReactionsAvailable = !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) { @@ -26030,6 +26207,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -26202,12 +26382,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -26220,9 +26427,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -27502,9 +27712,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; } @@ -27587,7 +27798,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not startMessageUnselect(); } if (cell.isHighlighted() && highlightMessageQuote != null) { - if (!cell.setHighlightedText(highlightMessageQuote, true) && showNoQuoteAlert) { + if (!cell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset) && showNoQuoteAlert) { showNoQuoteFound(); } showNoQuoteAlert = false; @@ -29067,6 +29278,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -29079,9 +29312,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -29402,6 +29634,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -29430,7 +29669,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -29756,7 +29995,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -30316,7 +30555,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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(); @@ -30422,10 +30661,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 { @@ -30679,6 +30915,37 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not try { 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(); } } @@ -30943,6 +31210,80 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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) { @@ -31058,8 +31399,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -31134,11 +31479,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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, () -> { @@ -31379,7 +31725,49 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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)); @@ -32918,7 +33306,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; @@ -33173,7 +33561,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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); @@ -33192,6 +33580,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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]; @@ -33204,20 +33594,56 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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; @@ -33231,22 +33657,49 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); } } @@ -33261,6 +33714,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not msgBackgroundSelectedPaint.setAlpha(64); msgBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix2)); msgBackgroundSelectedPaint.setShader(serviceShaderSource); + msgBackgroundSelectedPaint.setFilterBitmap(true); } else { if (selectedBackgroundColor == 0) { selectedBackgroundColor = getColor(Theme.key_chat_selectedBackground); @@ -33323,9 +33777,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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); @@ -33335,7 +33793,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } 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); @@ -33353,7 +33813,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 { @@ -33523,4 +33983,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 b5371b5aa..fff49d045 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 class ChatBackgroundDrawable extends Drawable { 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 class ChatBackgroundDrawable extends Drawable { } } } - return thumb; + return wallPaper.thumbDrawable = thumb; } private static Drawable bitmapDrawableOf(Drawable drawable) { @@ -205,6 +208,13 @@ public class ChatBackgroundDrawable extends Drawable { } } + 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 class ChatBackgroundDrawable extends Drawable { } } - 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 e5fc3f5ef..45d4d12d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -75,6 +75,7 @@ import org.telegram.ui.Cells.TextDetailCell; 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; @@ -86,6 +87,8 @@ import org.telegram.ui.Components.ImageUpdater; 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; @@ -177,6 +180,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image private final static int done_button = 1; private boolean hasUploadedPhoto; + private final List preloadedReactions = new ArrayList<>(); private PhotoViewer.PhotoViewerProvider provider = new PhotoViewer.EmptyPhotoViewerProvider() { @@ -397,6 +401,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image @Override public void onPause() { super.onPause(); + ReactionsUtils.stopPreloadReactions(preloadedReactions); if (nameTextView != null) { nameTextView.onPause(); } @@ -883,7 +888,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } 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 -> { @@ -1029,11 +1034,15 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image 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); @@ -1632,8 +1641,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image 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); } } } @@ -1737,6 +1745,8 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } historyHidden = !ChatObject.isChannel(currentChat) || info.hidden_prehistory; availableReactions = info.available_reactions; + preloadedReactions.clear(); + preloadedReactions.addAll(ReactionsUtils.startPreloadReactions(currentChat, info)); } } @@ -1995,6 +2005,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } 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); @@ -2009,17 +2020,25 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image 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, animated, 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 @@ -2126,6 +2145,12 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image 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 f861e527a..b5a8bc911 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 @@ public class ChatLinkActivity extends BaseFragment implements NotificationCenter 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 0053db7b3..77aa81792 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.AnimatorListenerAdapter; 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.graphics.RectF; 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; @@ -130,7 +126,7 @@ public class ChatPullingDownDrawable implements NotificationCenter.NotificationC 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 06d7ed86a..103ba2e42 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; @@ -1322,6 +1324,14 @@ public class ChatRightsEditActivity extends BaseFragment { } }, 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) { @@ -1400,19 +1410,26 @@ public class ChatRightsEditActivity extends BaseFragment { 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 d18d44cb8..3a8c648c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -1380,11 +1380,11 @@ public class AlertsCreator { 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); } @@ -1461,7 +1461,7 @@ public class AlertsCreator { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1582,7 +1582,7 @@ public class AlertsCreator { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1757,11 +1757,11 @@ public class AlertsCreator { 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); } @@ -2046,7 +2046,7 @@ public class AlertsCreator { 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)); @@ -2386,7 +2386,7 @@ public class AlertsCreator { 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)); @@ -2489,9 +2489,9 @@ public class AlertsCreator { 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); } @@ -3208,7 +3208,7 @@ public class AlertsCreator { 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 -> { @@ -3396,7 +3396,7 @@ public class AlertsCreator { 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 -> { @@ -3541,7 +3541,7 @@ public class AlertsCreator { 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)); @@ -3685,7 +3685,7 @@ public class AlertsCreator { 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)); @@ -3855,7 +3855,7 @@ public class AlertsCreator { 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 1d8d97a1d..145ea3762 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 @@ public class AnimatedEmojiDrawable extends Drawable { } 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 @@ public class AnimatedEmojiDrawable extends Drawable { 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 @@ public class AnimatedEmojiDrawable extends Drawable { 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 class AnimatedEmojiDrawable extends Drawable { 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 e7c20ab13..af509b0f2 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.HashMap; 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { } } - 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 @@ public class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { 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 class AnimatedEmojiSpan extends ReplacementSpan { } 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 489e53d30..d8acbd1ca 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, return nextRenderingBitmapTime != 0 ? nextRenderingBitmapTime : renderingBitmapTime; } + public int getProgressMs() { + return metaData[3]; + } + public int getDurationMs() { return metaData[4]; } @@ -1083,7 +1087,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, return isRecycled || decoderTryCount >= 15; } - public Bitmap getNextFrame() { + public Bitmap getNextFrame(boolean loop) { if (nativePtr == 0) { return backgroundBitmap; } @@ -1094,7 +1098,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 d0b595a9d..c32374e04 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 class AnimatedFloat { 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 a5d2028c0..386ec1581 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 class AutoDeletePopupWrapper { } } - 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 b09f90079..9481d99ec 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.TextPaint; 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; @@ -66,12 +68,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; @@ -102,7 +106,7 @@ public class AvatarDrawable extends Drawable { 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) { @@ -190,8 +194,12 @@ public class AvatarDrawable extends Drawable { } public void setInfo(TLRPC.User user) { + setInfo(UserConfig.selectedAccount, user); + } + + public void setInfo(int currentAccount, TLRPC.User user) { if (user != null) { - setInfo(user.id, user.first_name, user.last_name, null, (user.flags2 & 128) != 0 ? user.color : null); + 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); } } @@ -206,12 +214,23 @@ public class AvatarDrawable extends Drawable { } } + 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); @@ -222,6 +241,11 @@ public class AvatarDrawable extends Drawable { 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)]); @@ -263,7 +287,7 @@ public class AvatarDrawable extends Drawable { 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) { @@ -275,13 +299,20 @@ public class AvatarDrawable extends Drawable { } 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)); } } @@ -303,7 +334,7 @@ public class AvatarDrawable extends Drawable { } 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() { @@ -323,13 +354,16 @@ public class AvatarDrawable extends Drawable { } 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) { @@ -419,12 +453,19 @@ public class AvatarDrawable extends Drawable { 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) { @@ -488,6 +529,8 @@ public class AvatarDrawable extends Drawable { 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]; } @@ -508,8 +551,8 @@ public class AvatarDrawable extends Drawable { } 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; } @@ -522,10 +565,10 @@ public class AvatarDrawable extends Drawable { 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); @@ -540,7 +583,7 @@ public class AvatarDrawable extends Drawable { } } 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 8c21a30dd..fcef07bf4 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 class AvatarsDrawable { 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 class AvatarsDrawable { } 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 b6637edcf..d223db3f5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java @@ -105,7 +105,7 @@ public class BackButtonMenu { 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; } @@ -126,11 +126,11 @@ public class BackButtonMenu { 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 b3e2653bd..9c7dfcc4f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -42,6 +42,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) { @@ -183,6 +184,11 @@ public class BackupImageView extends View { 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 743d114c1..c05dcaf77 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 class BlobDrawable { 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 26b57060f..4dd5fa3b1 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 class BlurringShader { 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 class BlurringShader { } 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 class BlurringShader { 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 4b55e6164..bc8b718e0 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 @@ public class BottomPagerTabs extends View { 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 class BottomPagerTabs extends View { 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 9fdc90d95..d5a99c865 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 class Bulletin { return this; } + public Bulletin setTag(int tag) { + this.tag = tag; + return this; + } + public Bulletin show() { return show(false); } @@ -1897,9 +1902,4 @@ public class Bulletin { } } } - - 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 de2f14ca1..9d003eb01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -219,6 +219,26 @@ public final class BulletinFactory { 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); @@ -497,6 +517,20 @@ public final class BulletinFactory { 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 7852b1cb2..b0115a5a8 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 class ButtonBounce { 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 8632df7f2..3b886b8e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -602,6 +602,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private boolean ignoreTextChange; private int innerTextChange; private MessageObject replyingMessageObject; + private MessageObject replyingTopMessage; private ChatActivity.ReplyQuote replyingQuote; private MessageObject botMessageObject; private TLRPC.WebPage messageWebPage; @@ -840,7 +841,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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); @@ -854,9 +855,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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)); @@ -3496,7 +3494,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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); @@ -4263,6 +4261,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { if (clickMaybe) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } if (messageEditText != null && !AndroidUtilities.showKeyboard(messageEditText)) { @@ -4275,6 +4274,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } } @@ -4282,6 +4282,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + /* + * 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); @@ -5381,6 +5388,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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; @@ -5413,27 +5431,35 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } 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) { @@ -6048,9 +6074,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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); applyStoryToSendMessageParams(params); params.invert_media = parentFragment != null && parentFragment.messagePreviewParams != null && parentFragment.messagePreviewParams.webpageTop; @@ -7989,10 +8015,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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); } } @@ -8612,7 +8634,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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)) { @@ -10556,8 +10582,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 cdf325dac..40d6645d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -112,8 +112,6 @@ import org.telegram.ui.PaymentFormActivity; 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; @@ -477,6 +475,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } public interface ChatAttachViewDelegate { + default boolean selectItemOnClicking() { + return false; + } + void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); default void onCameraOpened() { @@ -1154,7 +1156,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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); @@ -1172,7 +1174,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 ae36a6060..1a738067e 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 class ChatAttachAlertContactsLayout extends ChatAttachAlert.AttachAlertLa } 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 6991a08bb..5950d27db 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -782,6 +782,20 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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); @@ -836,7 +850,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } int finalPosition = position; BaseFragment finalFragment = fragment; - AndroidUtilities.runOnUIThread(()-> { + AndroidUtilities.runOnUIThread(() -> { int avatarType = type; if (parentAlert.isPhotoPicker) { PhotoViewer.getInstance().setParentActivity(finalFragment); @@ -1459,6 +1473,12 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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 5ef9a14e1..ed9bf0315 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.SimpleTextView; 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; @@ -63,6 +61,7 @@ import java.util.concurrent.atomic.AtomicReference; 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<>(); @@ -76,6 +75,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; @@ -107,6 +107,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent subtitleTextView.setVisibility(View.GONE); } + public void setStoriesForceState(Integer storiesForceState) { + this.storiesForceState = storiesForceState; + } + private class SimpleTextConnectedView extends SimpleTextView { private AtomicReference reference; @@ -141,7 +145,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent 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; @@ -188,7 +192,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent 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); } @@ -523,7 +530,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent 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()); @@ -550,6 +557,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent 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; @@ -954,7 +965,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } 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)); @@ -966,7 +977,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } 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); @@ -994,7 +1005,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent 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); @@ -1014,7 +1025,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } } 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 6dad3210c..1923c90b8 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.net.Uri; 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 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen 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 class ChatThemeBottomSheet extends BottomSheet implements NotificationCen 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 class ChatThemeBottomSheet extends BottomSheet implements NotificationCen @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 class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } @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 class ChatThemeBottomSheet extends BottomSheet implements NotificationCen 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 dd43d015a..db55fa969 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java @@ -150,7 +150,7 @@ public class EditTextEffects extends EditText { @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 5c2ce835c..8af807ab9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -755,6 +755,7 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not 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 a0b99a14c..ec05c3f38 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -94,7 +94,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; @@ -298,6 +298,9 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { 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(); @@ -498,7 +501,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { 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); @@ -654,7 +657,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } 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); @@ -995,10 +998,15 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { 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(); + } } } } @@ -1135,7 +1143,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } 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 f82d065c4..b0f45edd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -7550,7 +7550,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific 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 000000000..b30784b3f --- /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 7e96afaf5..32063ad62 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 @@ public class FlatCheckBox extends View { 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 466dec1cc..564fcd232 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 class MessageTopicButton { 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 52bba9adb..c020b6c66 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.content.Context; 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 c253edbec..55a9a6093 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 class GroupCallFullscreenAdapter extends RecyclerListView.SelectionAdapte 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 class GroupCallFullscreenAdapter extends RecyclerListView.SelectionAdapte } 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 018d6a144..8df2ab073 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java @@ -285,7 +285,7 @@ public class GroupCallPipAlertView extends LinearLayout implements VoIPService.S 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 41aa685c3..277222605 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.RectF; 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 80e47f959..34e1b166e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -537,7 +537,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha 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() { @@ -783,7 +783,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha 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; } } @@ -796,7 +796,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha avatarDrawable.setScaleSize(.8f); } else { nameTextView[0].setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarObject = user; } } @@ -804,7 +804,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha 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; } } @@ -937,7 +937,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha return; } - if (id < 0 || mediaCount[id] < 0) { + if (id < 0 || id < mediaCount.length && mediaCount[id] < 0) { return; } if (id == SharedMediaLayout.TAB_PHOTOVIDEO) { @@ -964,6 +964,10 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha } 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 ac1f16f65..810bc0b26 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.animation.ValueAnimator; 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 class MessageContainsEmojiButton extends FrameLayout implements Notificat } }, 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 1a520a579..0798d2a61 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 @@ -1002,6 +1002,10 @@ public class EntityView extends FrameLayout { } } + public boolean trashCenter() { + return false; + } + @Override protected void dispatchDraw(Canvas canvas) { final float scale = bounce.getScale(.05f); @@ -1009,9 +1013,13 @@ public class EntityView extends FrameLayout { 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 000000000..1d9488f3c --- /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 b1a6d01b0..bb7edab91 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 class PhonebookShareAlert extends BottomSheet { 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 de529582e..a570f423f 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 class PollVotesAlert extends BottomSheet { } 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 ba68888ad..23e8eff5c 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im LocaleController.formatString("ConnectedAccountsLimitSubtitle", R.string.ConnectedAccountsLimitSubtitle, 4), UserConfig.MAX_ACCOUNT_DEFAULT_COUNT, UserConfig.MAX_ACCOUNT_COUNT )); + 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 236cdfe08..f15071943 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 @@ import java.util.HashMap; 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 @@ public class HelloParticles { 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 3be324633..a06c831e8 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.Layout; 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 class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { 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 b1c1aa414..56edb6411 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.GroupCreateUserCell; 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.BoostDialogs; 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp "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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } } - 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 0abf142d2..3367a1760 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.ActionBar; 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.LayoutHelper; 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; @@ -289,12 +292,16 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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)); @@ -339,7 +346,15 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } } 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)); } @@ -478,6 +493,8 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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)); @@ -677,6 +694,15 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 { @@ -808,7 +834,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 80e4d070d..95dfa49ff 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 @@ public class StarParticlesView extends View { 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 class StarParticlesView extends View { 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 d728c621c..c055a6b23 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 @@ package org.telegram.ui.Components.Premium; 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 org.telegram.ui.PremiumPreviewFragment; 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 04019e1a1..0e348a4ac 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 class BoostCounterView extends View { 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 @@ public class BoostCounterView extends View { } 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 64ea478d7..8ba91f29e 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 class BoostDialogs { } 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 119a2625e..d9540ae32 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 class GiftInfoBottomSheet extends BottomSheetWithRecyclerListView { 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 386348ff9..cf28bbc47 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 @@ package org.telegram.ui.Components.Premium.boosts.adapters; 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 abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter 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 abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter 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 6ec4cf4db..ed15c92af 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.AndroidUtilities; 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 55f840100..59107741c 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 class HeaderCell extends FrameLayout { 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 5ee5d736b..4ad6ce208 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 class LinkCell extends FrameLayout { 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 51fa8e580..5b208ff3a 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 static org.telegram.tgnet.tl.TL_stories.TL_boost.NO_USER_ID; 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.TableRow; 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 @@ public class TableCell extends FrameLayout { 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 7f6e833f8..652b603d3 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.formatString; 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 android.view.SoundEffectConstants; 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 class GiveawayMessageCell { 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 000000000..12fb4c64b --- /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 000000000..cddb46a99 --- /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 000000000..8d27acfc4 --- /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 74295e18a..78cbb7cb3 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 class CustomEmojiReactionsWindow { // 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 @@ public class CustomEmojiReactionsWindow { } 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 @@ public class CustomEmojiReactionsWindow { } } 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 @@ public class CustomEmojiReactionsWindow { } 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 000000000..a9bd07b04 --- /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 6d5713f4e..59c923449 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 class ReactionsEffectOverlay { 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 class ReactionsEffectOverlay { 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 @@ public class ReactionsEffectOverlay { 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 ef0f86d56..f20c5ecd7 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 class ReactionsLayoutInBubble { 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 class ReactionsLayoutInBubble { 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 class ReactionsLayoutInBubble { 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 class ReactionsLayoutInBubble { 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 class ReactionsLayoutInBubble { 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 1e4f6ff22..7fb97beb5 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 class ReactionsUtils { 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 class ReactionsUtils { } 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 class ReactionsUtils { 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 000000000..861cb02d1 --- /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 d9e7fbcba..95846a567 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -168,6 +168,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio HashSet lastVisibleViews = new HashSet<>(); HashSet lastVisibleViewsTmp = new HashSet<>(); private boolean allReactionsAvailable; + private boolean showExpandableReactions; private boolean allReactionsIsDefault; private Paint selectedPaint; ChatScrimPopupContainerLayout parentLayout; @@ -319,6 +320,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio switch (viewType) { default: case VIEW_TYPE_REACTION: + case VIEW_TYPE_CUSTOM_REACTION: view = new ReactionHolderView(context, true); break; case VIEW_TYPE_PREMIUM_BUTTON: @@ -365,7 +367,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio @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); @@ -389,6 +391,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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() { @@ -396,7 +399,8 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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)); @@ -421,7 +425,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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; @@ -506,6 +510,10 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio MediaDataController.getInstance(currentAccount).preloadDefaultReactions(); } + public boolean showExpandableReactions() { + return showExpandableReactions; + } + private void animatePullingBack() { if (pullingLeftOffset != 0) { pullingDownBackAnimator = ValueAnimator.ofFloat(pullingLeftOffset, 0); @@ -559,7 +567,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } public boolean showCustomEmojiReaction() { - return !MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable; + return (!MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable) || showExpandableReactions; } private boolean showUnlockPremiumButton() { @@ -1077,6 +1085,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio fillRecentReactionsList(visibleReactions); } filterReactions(visibleReactions); + showExpandableReactions = !allReactionsAvailable && visibleReactions.size() > 16; setVisibleReactionsList(visibleReactions); if (message != null && message.messageOwner.reactions != null && message.messageOwner.reactions.results != null) { @@ -1832,7 +1841,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 ecc64a5c4..e5bf8e323 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java @@ -17,11 +17,13 @@ import androidx.core.graphics.ColorUtils; 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; @@ -105,6 +107,7 @@ public class ReplyMessageLine { 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) { @@ -126,9 +129,9 @@ public class ReplyMessageLine { 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) { @@ -144,12 +147,13 @@ public class ReplyMessageLine { 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 || @@ -167,44 +171,28 @@ public class ReplyMessageLine { } 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); - } + 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; } @@ -228,30 +216,24 @@ public class ReplyMessageLine { } 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; - } + 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; } @@ -284,7 +266,7 @@ public class ReplyMessageLine { 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 43e676e1b..78a5c3af4 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.LiteMode; 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; @@ -343,7 +344,7 @@ public class ScrollSlidingTabStrip extends HorizontalScrollView { 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 5afb94556..051666196 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 class ScrollSlidingTextTabStrip extends HorizontalScrollView { } }; + protected int processColor(int color) { + return color; + } + public ScrollSlidingTextTabStrip(Context context) { this(context, null); } @@ -144,6 +148,16 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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); @@ -278,7 +292,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { }; 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")); @@ -331,7 +345,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { if (delegate != null) { delegate.onPageSelected(pageId, scrollingForward); } - scrollToChild(position1); + scrollToChild(position1, true); } public void scrollTo(int pageId) { @@ -343,7 +357,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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; } @@ -355,14 +369,27 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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); @@ -428,7 +455,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - private void scrollToChild(int position) { + private void scrollToChild(int position, boolean smooth) { if (tabCount == 0 || scrollingToChild == position) { return; } @@ -441,9 +468,17 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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); + } } } @@ -526,7 +561,7 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { child.setTag(unactiveTextColorKey); nextChild.setTag(activeTextColorKey); } - scrollToChild(tabsContainer.indexOfChild(nextChild)); + scrollToChild(tabsContainer.indexOfChild(nextChild), true); } if (progress >= 1.0f) { currentPosition = position; @@ -555,9 +590,9 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView { 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 75d110cf2..657d457f2 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 class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie 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 c7e183cc6..300834d3d 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.Color; 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 efa7c5059..b29d2f4c7 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.DialogsSearchAdapter; 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; @@ -146,11 +147,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); @@ -460,16 +463,17 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } 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; @@ -868,6 +872,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } 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) { @@ -878,37 +883,44 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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(); @@ -1124,7 +1136,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -1174,7 +1186,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); searchGridView.setHasFixedSize(true); searchGridView.setItemAnimator(null); @@ -1192,11 +1204,15 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } 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; @@ -2338,6 +2373,10 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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<>(); @@ -2352,6 +2391,11 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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); @@ -2566,7 +2610,12 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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) { @@ -2956,11 +3005,15 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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); @@ -2988,11 +3041,11 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi }; 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); } @@ -3066,16 +3119,19 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi @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; @@ -3086,6 +3142,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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; @@ -3101,9 +3158,13 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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--; @@ -3114,7 +3175,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } 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; @@ -3134,7 +3195,12 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } } } - 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(); } @@ -3152,7 +3218,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } else if (position == resentTitleCell) { return 3; } - return 0; + return TextUtils.isEmpty(lastSearchText) ? 0 : 5; } public boolean isSearching() { @@ -3163,6 +3229,10 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi 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 27760caaa..2b6692f31 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.content.res.Configuration; 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.NotificationCenter; 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; @@ -116,11 +121,14 @@ import org.telegram.ui.ChatActivity; 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; @@ -140,6 +148,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; @@ -364,7 +373,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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); @@ -417,11 +426,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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); @@ -494,6 +503,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter private SharedDocumentsAdapter audioAdapter; private GifAdapter gifAdapter; private CommonGroupsAdapter commonGroupsAdapter; + private ChannelRecommendationsAdapter channelRecommendationsAdapter; private ChatUsersAdapter chatUsersAdapter; private StoriesAdapter storiesAdapter; private StoriesAdapter animationSupportingStoriesAdapter; @@ -520,7 +530,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -1019,7 +1029,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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)) { @@ -1027,10 +1037,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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()) { @@ -1038,7 +1048,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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()); @@ -1248,7 +1258,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -1261,14 +1271,16 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; } } @@ -1304,6 +1316,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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)); @@ -1418,14 +1431,14 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -1445,7 +1458,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 { @@ -1608,7 +1621,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } - optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -AndroidUtilities.dp(56)); + optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -dp(56)); } }); @@ -1634,7 +1647,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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()); @@ -1650,7 +1663,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter gotoItem.setIcon(R.drawable.msg_message); gotoItem.setContentDescription(LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); gotoItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(gotoItem); gotoItem.setOnClickListener(v -> onActionBarItemClick(v, gotochat)); @@ -1658,7 +1671,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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)); @@ -1668,7 +1681,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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)); @@ -1692,10 +1705,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 @@ -1796,7 +1810,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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); } } @@ -1897,6 +1911,25 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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) { @@ -1911,10 +1944,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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; @@ -1928,7 +1961,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -2256,8 +2289,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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); @@ -2311,11 +2344,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -2375,7 +2408,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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) { @@ -2400,6 +2437,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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() { @@ -2424,51 +2467,77 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; } - 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); + 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 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); @@ -2549,7 +2618,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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()) { @@ -2567,7 +2636,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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); @@ -2829,7 +2898,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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() ); @@ -3030,7 +3099,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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() ); @@ -3114,8 +3183,17 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } + 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; @@ -3234,7 +3312,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 @@ -3257,17 +3335,17 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -3336,13 +3414,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -3503,6 +3581,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -3848,10 +3927,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 @@ -3937,7 +4016,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -4156,7 +4235,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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); @@ -4569,6 +4648,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } } + } else if (id == NotificationCenter.channelRecommendationsLoaded) { + long chatId = (long) args[0]; + if (chatId == -dialog_id) { + channelRecommendationsAdapter.update(); + updateTabs(true); + } } } @@ -4861,6 +4946,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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++; @@ -4896,6 +4982,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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) { @@ -4956,55 +5046,60 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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) { - if (!scrollSlidingTextTabStrip.hasTab(0)) { + 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(0, LocaleController.getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); } else { - scrollSlidingTextTabStrip.addTextTab(0, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView); + 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); } } } @@ -5124,7 +5219,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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() ); @@ -5134,7 +5229,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; } @@ -5200,8 +5295,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 { @@ -5248,7 +5348,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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(); @@ -5968,7 +6068,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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)); } @@ -5978,12 +6078,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -6711,6 +6811,165 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } + 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; @@ -7644,7 +7903,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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; @@ -7652,7 +7911,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return super.drawChild(canvas, child, drawingTime); } - private class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { + public class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { protected Paint backgroundPaint; public int backgroundColor = Color.TRANSPARENT; @@ -7726,7 +7985,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @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 97dd775c5..8008f5e90 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java @@ -476,6 +476,8 @@ public class SizeNotifierFrameLayout extends FrameLayout { return emojiHeight; } return backgroundTranslationY; + } else if (backgroundDrawable instanceof ChatBackgroundDrawable) { + return backgroundTranslationY; } return 0; } @@ -495,6 +497,8 @@ public class SizeNotifierFrameLayout extends FrameLayout { } 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 7de5f6732..a49fb323f 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 class StaticLayoutEx { .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 ed3664221..caf86c1ed 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 class StickerCategoriesListView extends RecyclerListView { // } } - 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 d8e971451..4fea03c39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -1126,7 +1126,7 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not 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 ddaa682bf..4fb546f17 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java @@ -189,8 +189,8 @@ public class Switch extends View { }; } 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) { @@ -199,13 +199,11 @@ public class Switch extends View { 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; @@ -222,6 +220,10 @@ public class Switch extends View { 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; @@ -414,8 +416,8 @@ public class Switch extends View { 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.MULTIPLY)); } @@ -469,8 +471,8 @@ public class Switch extends View { 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 9161dba4f..819cabdfc 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.Layout; 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 class Text { 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 class Text { 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 class Text { } } + 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 a0ae92c12..e846e2978 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.MessagesStorage; 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 class TranscribeButton { 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 class TranscribeButton { }, 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 class TranscribeButton { 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 class TranscribeButton { } 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 class TranscribeButton { 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 class TranscribeButton { 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 class TranscribeButton { } 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 class TranscribeButton { 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 class TranscribeButton { } 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 class TranscribeButton { 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 class TranscribeButton { ); } - 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 @@ public class TranscribeButton { 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 @@ public class TranscribeButton { 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 @@ public class TranscribeButton { if (isFinal) { AndroidUtilities.runOnUIThread(() -> finishTranscription(messageObject, finalId, finalText), Math.max(0, minDuration - duration)); } - }); + }, flags); } } else { if (transcribeOperationsByDialogPosition != null) { @@ -695,4 +806,42 @@ public class TranscribeButton { }); } } + + 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 b0130948d..edccc1ab0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -543,7 +543,7 @@ public class UndoView extends FrameLayout { 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; @@ -568,7 +568,7 @@ public class UndoView extends FrameLayout { 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; @@ -578,12 +578,12 @@ public class UndoView extends FrameLayout { 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 28cb79dcd..1edfda29e 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 class VectorAvatarThumbDrawable extends Drawable implements AnimatedEmoji 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 class VectorAvatarThumbDrawable extends Drawable implements AnimatedEmoji } 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 e16dfce99..886bbd11b 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.animation.ObjectAnimator; 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.text.TextPaint; 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 class WallpaperCheckBoxView extends View { 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 @@ public class WallpaperCheckBoxView extends View { 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 @@ public class WallpaperCheckBoxView extends View { 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 e8e7a52d0..87478e8fe 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 class GroupCallMiniTextureView extends FrameLayout implements GroupCallSt 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 b5aba70ef..31c93533a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -203,6 +203,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent 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); @@ -873,7 +874,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent 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 9ded923ce..5fa425160 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 class DataUsage2Activity extends BaseFragment { @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 16c14e0ad..4a2efd73c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -163,6 +163,7 @@ import org.telegram.ui.Components.ArchiveHelp; import org.telegram.ui.Components.AvatarDrawable; 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; @@ -2854,6 +2855,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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) { @@ -3497,7 +3503,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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); @@ -7737,22 +7743,36 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. slowedReloadAfterDialogClick = true; if (getMessagesController().checkCanOpenChat(args, DialogsActivity.this)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + 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)); - } 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); + presentFragment(new TopicsFragment(args)); + } + } else if (!searching) { + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); + } else { + 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 6c733a05a..d73536d25 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.AudioPlayerAlert; 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; @@ -7022,7 +7020,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter 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 5ac945a0d..6cf844c3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -257,8 +257,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; @@ -266,7 +266,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; @@ -950,7 +950,12 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ -3244,10 +3249,10 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Integer threadId, TLRPC.Chat chat) { - return runCommentRequest(intentAccount, dismissLoading, messageId, commentId, threadId, chat, null, null, 0); + return runCommentRequest(intentAccount, dismissLoading, messageId, commentId, threadId, chat, null, null, 0, -1); } - private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Integer threadId, TLRPC.Chat chat, Runnable onOpened, String quote, int fromMessageId) { + private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Integer threadId, TLRPC.Chat chat, Runnable onOpened, String quote, int fromMessageId, int quoteOffset) { if (chat == null) { return 0; } @@ -3266,7 +3271,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } if (!arrayList.isEmpty() || chat.forum && threadId != null && threadId == 1) { if (chat.forum) { - openTopicRequest(intentAccount, threadId, chat, commentId != null ? commentId : messageId, null, onOpened, quote, fromMessageId, arrayList); + openTopicRequest(intentAccount, threadId, chat, commentId != null ? commentId : messageId, null, onOpened, quote, fromMessageId, arrayList, quoteOffset); chatOpened = true; } else { Bundle args = new Bundle(); @@ -3276,13 +3281,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati chatActivity.setThreadMessages(arrayList, chat, req.msg_id, res.read_inbox_max_id, res.read_outbox_max_id, null); if (commentId != null) { if (quote != null) { - chatActivity.setHighlightQuote(commentId, quote); + chatActivity.setHighlightQuote(commentId, quote, quoteOffset); } else { chatActivity.setHighlightMessageId(commentId); } } else if (threadId != null) { if (quote != null) { - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); } else { chatActivity.setHighlightMessageId(messageId); } @@ -3314,7 +3319,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati })); } - private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, int messageId, TLRPC.TL_forumTopic forumTopic, Runnable whenDone, String quote, int fromMessageId, 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); } @@ -3335,7 +3340,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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; @@ -3343,7 +3348,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 { @@ -3362,7 +3367,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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); } @@ -3509,7 +3514,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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)) { @@ -3520,7 +3525,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } } @@ -3537,7 +3542,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } args.putLong("chat_id", -dialogId); @@ -3547,7 +3552,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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(); @@ -3569,7 +3574,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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); } } @@ -4171,7 +4176,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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) { @@ -4307,7 +4312,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 @@ -4874,7 +4879,12 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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(); } @@ -5011,6 +5021,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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; @@ -5038,6 +5055,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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); @@ -5054,14 +5078,14 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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(); @@ -5085,13 +5109,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } 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(); @@ -5223,7 +5247,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati }); } - 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 9309c13b2..f4a63769a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -1491,9 +1491,9 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } 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 c7adda3a6..7f172e396 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.ImageView; 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.MessagesController; 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 class MessageSeenView extends FrameLayout { 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 25b259722..ffd77d907 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.Canvas; 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.TextView; 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.messenger.R; 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.BaseChartView; 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 class MessageStatisticActivity extends BaseFragment implements Notificati 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 class MessageStatisticActivity extends BaseFragment implements Notificati 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 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati endRow = -1; loadingRow = -1; interactionsChartRow = -1; + reactionsByEmotionChartRow = -1; overviewHeaderRow = -1; overviewRow = -1; @@ -178,6 +202,10 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati interactionsChartRow = rowCount++; shadowDivideCells.add(rowCount++); } + if (reactionsByEmotionData != null) { + reactionsByEmotionChartRow = rowCount++; + shadowDivideCells.add(rowCount++); + } if (!messages.isEmpty()) { headerRow = rowCount++; @@ -220,12 +248,8 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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 class MessageStatisticActivity extends BaseFragment implements Notificati } } + 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 class MessageStatisticActivity extends BaseFragment implements Notificati 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 class MessageStatisticActivity extends BaseFragment implements Notificati 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 class MessageStatisticActivity extends BaseFragment implements Notificati 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 class MessageStatisticActivity extends BaseFragment implements Notificati @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,65 +454,66 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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)); + thumbImage.setRoundRadius(AndroidUtilities.dp(9)); - 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; + 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); } - message = Emoji.replaceEmoji(message, avatarContainer.getSubtitleTextView().getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); - } 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 @@ -427,26 +522,25 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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; } @@ -463,7 +557,35 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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(); @@ -480,6 +602,54 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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) { @@ -490,7 +660,7 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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; @@ -511,7 +681,9 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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(); } @@ -524,22 +696,45 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati } 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(); @@ -622,20 +817,23 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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() { @@ -729,17 +927,17 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati // 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: @@ -754,26 +952,38 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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); - } else { - object = getMessagesController().getChat(-did); - TLRPC.Chat chat = (TLRPC.Chat) object; - if (chat.participants_count != 0) { - if (ChatObject.isChannel(chat) && !chat.megagroup) { - status = LocaleController.formatPluralString("Subscribers", chat.participants_count); - } else { - status = LocaleController.formatPluralString("Members", chat.participants_count); - } - status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.views)); - } - } - if (object != null) { + 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 { + 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("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)); + } + } + if (object != null) { + userCell.setData(object, null, status, position != endRow - 1); + } } break; case 1: @@ -782,9 +992,13 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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: @@ -796,6 +1010,11 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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; } } @@ -820,11 +1039,13 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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); } @@ -834,64 +1055,90 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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)); + int views; + int forwards; + int reactions; + + if (recentPostInfo != null) { + views = recentPostInfo.getViews(); + forwards = recentPostInfo.getForwards(); + reactions = recentPostInfo.getReactions(); + } else { + 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; + } + } + } + } + + primary[0].setText(AndroidUtilities.formatWholeNumber(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)); - } else { - cell[1].setVisibility(View.GONE); + 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 = 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); - } + 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())); } } } @@ -924,7 +1171,7 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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)); @@ -960,6 +1207,7 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati 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; } @@ -968,10 +1216,10 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati ((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); @@ -979,10 +1227,16 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati ((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 da47eec0b..01868fc12 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.BulletinFactory; 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; @@ -84,39 +106,746 @@ 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 ColoredActionBar colorBar; - private int selectedColor; - private long selectedEmoji; - private ThemePreviewMessagesCell messagesCellPreview; - private SetReplyIconCell setReplyIconCell; + public static final int PAGE_NAME = 0; + public static final int PAGE_PROFILE = 1; - private CharSequence buttonLocked, buttonUnlocked; + public Page namePage; + public Page profilePage; - int previewRow; - int colorPickerRow; - int infoRow; - int iconRow; - int info2Row; - int buttonRow; + public Page getCurrentPage() { + return viewPager.getCurrentPosition() == 0 ? namePage : profilePage; + } - int rowCount; + public boolean loading; - 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 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); + } + } + + listView = new RecyclerListView(getContext(), getResourceProvider()) { + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, heightSpec); + updateButtonY(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + updateButtonY(); + } + }; + ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); + listView.setLayoutManager(new LinearLayoutManager(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; + } + 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)); + } + + updateColors(); + updateRows(); + + setWillNotDraw(false); + } + + private int actionBarHeight; + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getParentLayout() != null) { + getParentLayout().drawHeaderShadow(canvas, actionBarHeight); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (type == PAGE_NAME) { + actionBarHeight = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; + } else { + actionBarHeight = dp(144) + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; + ((MarginLayoutParams) profilePreview.getLayoutParams()).height = actionBarHeight; + } + 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 { + 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 (!foundLastPosition) { + maxTop = listView.getMeasuredHeight(); + } + buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14)))); + } + + + 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); + } + + public void updateColors() { + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + } + + 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 < 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 + 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()); + 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); + } + } + 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(); + } + } + + @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(); + } + + public void checkResetColorButton() { + if (type != PAGE_PROFILE) { + return; + } + final int wasIndex = clearRow; + updateRows(); + if (wasIndex >= 0 && clearRow < 0) { + listAdapter.notifyItemRangeRemoved(wasIndex, 2); + } else if (wasIndex < 0 && clearRow >= 0) { + listAdapter.notifyItemRangeInserted(clearRow, 2); + } + } + + 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++; + } + + 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(); + } + } + } + } + } + + 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(); + } + }); + } + + public void premiumChanged() { + if (button != null && !isChannel) { + button.setText(!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked, true); + } + } + } + + private Theme.ResourcesProvider parentResourcesProvider; + private final SparseIntArray currentColors = new SparseIntArray(); + private final Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; + + 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"; + } + } + + if (isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } + + 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); + } + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); + } + } + if (themeColors != null) { + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } + } + + if (namePage != null && namePage.messagesCellPreview != null) { + if (Theme.isCurrentThemeDark() == isDark) { + namePage.messagesCellPreview.setOverrideBackground(null); + } else { + 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 void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + parentResourcesProvider = resourceProvider; + } + + private boolean startAtProfile; + public PeerColorActivity startOnProfile() { + this.startAtProfile = true; + return this; } private BaseFragment bulletinFragment; @@ -146,233 +875,160 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente return super.onFragmentCreate(); } + private ViewPagerFixed viewPager; + + private ImageView backButton; + private ImageView dayNightItem; + + private FrameLayout actionBarContainer; + private FilledTabsView tabsView; + private SimpleTextView titleView; + @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); - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + 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 - public void onItemClick(int id) { - if (id == -1) { - if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { - showUnsavedAlert(); - return; - } - finishFragment(); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (actionBarContainer != null) { + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).height = ActionBar.getCurrentActionBarHeight(); + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).topMargin = AndroidUtilities.statusBarHeight; } - } - }); - - if (dialogId < 0) { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if ((chat.flags2 & 32) != 0) { - selectedEmoji = chat.background_emoji_id; - } - if ((chat.flags2 & 64) != 0) { - selectedColor = chat.color; - } else { - selectedColor = (int) (chat.id % 7); - } - } else { - TLRPC.User user = getUserConfig().getCurrentUser(); - if ((user.flags2 & 64) != 0) { - selectedEmoji = user.background_emoji_id; - } - if ((user.flags2 & 128) != 0) { - selectedColor = user.color; - } else { - selectedColor = (int) (user.id % 7); - } - } - - FrameLayout frameLayout = new FrameLayout(context); - - listView = new RecyclerListView(context) { - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - super.onMeasure(widthSpec, heightSpec); - updateButtonY(); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - updateButtonY(); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }; - ((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; - } + frameLayout.setFitsSystemWindows(true); - @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; - } - return new RecyclerListView.Holder(view); - } + 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 - 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)); - } - } + protected void onTabAnimationUpdate(boolean manual) { + tabsView.setSelected(viewPager.getPositionAnimated()); + colorBar.setProgressToGradient(viewPager.getPositionAnimated()); } - + }; + viewPager.setAdapter(new ViewPagerFixed.Adapter() { @Override public int getItemCount() { - return rowCount; + 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) { - if (position == previewRow) { - return VIEW_TYPE_MESSAGE; - } - if (position == infoRow || position == info2Row) { - 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 == getItemCount() - 1) { - return 4; - } - return VIEW_TYPE_INFO; + return position; } - }); - listView.setOnItemClickListener((view, position) -> { - if (view instanceof SetReplyIconCell) { - showSelectStatusDialog((SetReplyIconCell) view); - } - }); - 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)); - - 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(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)); - - 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 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 { + 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); + } + 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; - updateColors(); - updateRows(); - return contentView; } - private void updateButtonY() { - if (buttonContainer == null) { - return; - } - final int lastPosition = listAdapter.getItemCount() - 1; - boolean foundLastPosition = false; - int maxTop = 0; - for (int i = 0; i < listView.getChildCount(); ++i) { - View child = listView.getChildAt(i); - final int position = listView.getChildAdapterPosition(child); - if (position != RecyclerListView.NO_POSITION && position <= lastPosition) { - maxTop = Math.max(maxTop, child.getTop()); - if (position == lastPosition) { - foundLastPosition = true; - } - } - } - if (!foundLastPosition) { - maxTop = listView.getMeasuredHeight(); - } - buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14)))); + private boolean isDark = Theme.isCurrentThemeDark(); + private RLottieDrawable sunDrawable; + + public boolean hasUnsavedChanged() { + return namePage.hasUnsavedChanged() || profilePage.hasUnsavedChanged(); } private void showBoostLimit(boolean error) { @@ -401,7 +1057,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente presentFragment(fragment); }); showDialog(limitReachedBottomSheet); - AndroidUtilities.runOnUIThread(() -> button.setLoading(false), 300); + loading = false; + AndroidUtilities.runOnUIThread(() -> getCurrentPage().button.setLoading(false), 300); }); } else { apply(); @@ -418,25 +1075,6 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente return super.onBackPressed(); } - public boolean hasUnsavedChanged() { - if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat == null) { - return false; - } - if (selectedColor == chat.color && selectedEmoji == ((chat.flags2 & 64) == 0 ? 0 : chat.background_emoji_id)) { - return false; - } - return true; - } else { - final TLRPC.User me = getUserConfig().getCurrentUser(); - if (selectedColor == me.color && selectedEmoji == ((me.flags2 & 64) == 0 ? 0 : me.background_emoji_id)) { - return false; - } - return true; - } - } - @Override public boolean isSwipeBackEnabled(MotionEvent event) { if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { @@ -464,22 +1102,22 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } 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; } } @@ -489,9 +1127,10 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente showBulletin(); } + private boolean applyingName, applyingProfile; private boolean applying; private void apply() { - if (applying || peerColorPicker == null || !isChannel && !getUserConfig().isPremium()) { + if (applying || !isChannel && !getUserConfig().isPremium()) { return; } @@ -500,7 +1139,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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(); @@ -509,18 +1150,20 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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(() -> { @@ -534,25 +1177,54 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente })); } else { 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); } - 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 (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); + } + 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); @@ -560,27 +1232,32 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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(); + 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 { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + R.raw.contact_check, + LocaleController.getString(isChannel ? R.string.ChannelProfileColorResetApplied : R.string.UserProfileColorResetApplied) + ).show(); } + } else { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + PeerColorDrawable.fromProfile(currentAccount, profilePage.selectedColor), + LocaleController.getString(isChannel ? R.string.ChannelProfileColorApplied : R.string.UserProfileColorApplied) + ).show(); } } + bulletinFragment = null; } } @@ -590,161 +1267,6 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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(); @@ -776,8 +1298,16 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente @SuppressLint("NotifyDataSetChanged") private void updateColors() { - contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); - listAdapter.notifyDataSetChanged(); + 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") @@ -785,268 +1315,13 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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) - ); - } 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; - } - } - } - 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(); - } - - final float selectT = selectedT.set(selected); - - 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 - ); - } - - canvas.restore(); - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - bounce.setPressed(pressed); - } + namePage.premiumChanged(); + profilePage.premiumChanged(); } } public static class ChangeNameColorCell extends View { + private final int currentAccount; private final boolean isChannel; private final Theme.ResourcesProvider resourcesProvider; @@ -1058,8 +1333,13 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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; @@ -1089,7 +1369,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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 { @@ -1104,6 +1384,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); + + color1Drawable = color2Drawable = null; } public void set(TLRPC.User user) { @@ -1119,7 +1401,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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 { @@ -1134,6 +1416,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } 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 @@ -1161,7 +1446,19 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente .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); @@ -1174,8 +1471,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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) { @@ -1188,10 +1485,11 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } - 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); @@ -1201,13 +1499,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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; @@ -1225,16 +1517,24 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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; @@ -1247,14 +1547,10 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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) { @@ -1299,6 +1595,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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), @@ -1319,26 +1616,49 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } - 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)); @@ -1349,11 +1669,15 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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)); + } } } } @@ -1363,10 +1687,10 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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; @@ -1378,6 +1702,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + @Override protected void dispatchDraw(Canvas canvas) { if (buttons != null) { @@ -1385,7 +1711,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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; @@ -1393,7 +1720,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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); } } } @@ -1466,20 +1793,42 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } 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 from(MessagesController.PeerColor peerColor) { + 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, 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); @@ -1492,10 +1841,16 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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(); } @@ -1503,6 +1858,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente 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); @@ -1527,12 +1885,480 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente @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 5c31f86b3..55b7da1ca 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -6871,7 +6871,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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(() -> { @@ -13387,8 +13387,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 50f404e7a..ad26d33ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -159,6 +159,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; @@ -228,6 +230,10 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification 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; } @@ -278,6 +284,10 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification 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; } @@ -352,7 +362,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification 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) { @@ -637,24 +647,26 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification 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--; } @@ -678,7 +690,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } 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); @@ -1572,21 +1584,27 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification @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 @@ -1604,11 +1622,13 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification } 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(); } @@ -1649,7 +1669,9 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification 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 4e172834a..a311fca7c 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; @@ -32,8 +33,10 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.DataSetObserver; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -42,7 +45,9 @@ import android.graphics.PorterDuff; 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; @@ -168,8 +173,10 @@ import org.telegram.ui.Cells.TextDetailCell; 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; @@ -270,12 +277,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; @@ -284,6 +291,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private boolean sharedMediaLayoutAttached; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; + private View blurredView; + private RLottieDrawable cameraDrawable; private RLottieDrawable cellCameraDrawable; @@ -358,6 +367,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private boolean needSendMessage; private boolean hasVoiceChatItem; private boolean isTopic; + private boolean openSimilar; private boolean scrolling; @@ -458,6 +468,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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(); @@ -531,6 +542,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int subscribersRow; private int subscribersRequestsRow; private int administratorsRow; + private int settingsRow; private int blockedUsersRow; private int membersSectionRow; @@ -846,6 +858,78 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + 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); @@ -864,7 +948,36 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } 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; @@ -1566,6 +1679,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -1821,7 +1935,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -2233,6 +2347,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } 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) { @@ -2505,14 +2621,20 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(1f); + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(1f); + } + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].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); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); actionBar.setItemsColor(Color.WHITE, false); overlaysView.setOverlaysVisible(); @@ -2613,7 +2735,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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) { @@ -2796,6 +2918,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ -2803,6 +2937,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (pinchToZoomHelper.isInOverlayMode() && (child == avatarContainer2 || child == actionBar || child == writeButton)) { return true; } + if (child == blurredView) { + return true; + } return super.drawChild(canvas, child, drawingTime); } @@ -2830,7 +2967,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }; 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(); @@ -3403,6 +3545,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -3552,6 +3696,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SharedConfig.updateStealthModeSendMessageConfirm(2); SharedConfig.setStoriesReactionsLongPressHintUsed(false); SharedConfig.setStoriesIntroShown(false); + SharedConfig.setMultipleReactionsPromoShowed(false); ChatThemeController.getInstance(currentAccount).clearCache(); getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); RestrictedLanguagesSelectActivity.cleanup(); @@ -3770,6 +3915,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); + if (openSimilar) { + updateRowsIds(); + scrollToSharedMedia(); + savedScrollToSharedMedia = true; + savedScrollPosition = sharedMediaRow; + savedScrollOffset = 0; + } + if (searchItem != null) { searchListView = new RecyclerListView(context); searchListView.setVerticalScrollBarEnabled(false); @@ -3912,6 +4065,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } topView = new TopView(context); + topView.setBackgroundColorId(peerColor, false); topView.setBackgroundColor(getThemedColor(Theme.key_avatar_backgroundActionBarBlue)); frameLayout.addView(topView); contentView.blurBehindViews.add(topView); @@ -4222,7 +4376,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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); @@ -4286,14 +4440,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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.MULTIPLY)); - 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); @@ -4310,7 +4457,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. writeButton.setImageResource(R.drawable.profile_discuss); writeButton.setContentDescription(LocaleController.getString("ViewDiscussion", R.string.ViewDiscussion)); } - writeButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_profile_actionIcon), PorterDuff.Mode.MULTIPLY)); writeButton.setScaleType(ImageView.ScaleType.CENTER); frameLayout.addView(writeButton, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.TOP, 0, 0, 16, 0)); @@ -4377,7 +4523,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @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); @@ -4470,6 +4616,27 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. contentView.blurBehindViews.add(sharedMediaLayout); updateTtlIcon(); + 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; } @@ -4604,7 +4771,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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)); @@ -4703,12 +4870,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -4737,12 +4910,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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)); @@ -4751,8 +4926,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -4846,7 +5021,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. Bundle args = new Bundle(); args.putLong("chat_id", chatId); - presentFragment(new TopicsFragment(args)); + presentFragment(TopicsFragment.getTopicsOrChat(this, args)); } private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; @@ -4887,7 +5062,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); } @@ -5643,36 +5818,52 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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)); + 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)); - 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.MULTIPLY); + 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.MULTIPLY); + 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(); @@ -5973,6 +6164,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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)); } } @@ -6247,7 +6441,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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)); @@ -6255,12 +6449,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -6830,6 +7024,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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(); @@ -6879,7 +7077,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; } } @@ -6990,6 +7188,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } getNotificationCenter().onAnimationFinish(transitionIndex); + + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } } transitionAnimationInProress = false; checkPhotoDescriptionAlpha(); @@ -7030,8 +7233,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -7044,12 +7247,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -7157,7 +7359,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); overlaysView.setOverlaysVisible(); } @@ -7543,6 +7745,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. membersSectionRow = -1; sharedMediaRow = -1; notificationsSimpleRow = -1; + settingsRow = -1; unblockRow = -1; joinRow = -1; @@ -7566,6 +7769,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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) { @@ -7734,6 +7942,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (chatInfo.banned_count != 0 || chatInfo.kicked_count != 0) { blockedUsersRow = rowCount++; } + settingsRow = rowCount++; membersSectionRow = rowCount++; } } @@ -7853,22 +8062,29 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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) { @@ -7883,7 +8099,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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]; @@ -7894,18 +8110,25 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; } @@ -7918,6 +8141,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. ); } + private MessagesController.PeerColor peerColor; + private void updateProfileData(boolean reload) { if (avatarContainer == null || nameTextView == null || getParentActivity() == null) { return; @@ -7951,7 +8176,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -8011,10 +8247,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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])); } } } @@ -8048,7 +8284,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -8071,7 +8307,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (user.scam || user.fake) { rightIcon = getScamDrawable(user.scam ? 0 : 1); } else if (user.verified) { - 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; @@ -8187,6 +8423,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); } @@ -8299,7 +8546,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[a].setRightDrawable(getScamDrawable(chat.scam ? 0 : 1)); nameTextViewRightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); } else if (chat.verified) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable()); + nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable(a)); nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); } else { nameTextView[a].setRightDrawable(null); @@ -8309,7 +8556,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 { @@ -8371,7 +8618,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -8406,6 +8653,80 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -8425,7 +8746,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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) { @@ -8674,7 +8996,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }, 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) { @@ -9351,7 +9674,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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: { @@ -9360,7 +9688,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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: { @@ -9534,6 +9867,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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: @@ -9652,7 +9986,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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 { @@ -9660,6 +9994,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -9739,6 +10074,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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); @@ -9815,6 +10152,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -9982,7 +10320,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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(", "); @@ -10053,7 +10391,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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 || @@ -10936,9 +11274,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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)); } } } @@ -10952,8 +11290,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[1].setTextColor(getThemedColor(Theme.key_profile_title)); } 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(); @@ -11064,11 +11402,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -11111,9 +11449,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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; @@ -11155,15 +11494,28 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @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) {} } @@ -11326,6 +11678,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); @@ -11354,6 +11707,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); } @@ -11530,4 +11885,33 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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); + } + } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index f1ac9be34..dbd631ca0 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.Spanned; 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.ViewTreeObserver; 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; @@ -142,6 +142,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; @@ -442,7 +445,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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) -> { @@ -560,7 +563,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } 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) { @@ -577,7 +580,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -648,8 +651,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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; } @@ -666,7 +671,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } }; 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 @@ -677,7 +684,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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(); } @@ -705,7 +712,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -863,8 +870,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati }); 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 @@ -884,7 +891,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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(); performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); ImageViewEmoji imageViewEmoji = (ImageViewEmoji) view; @@ -1078,7 +1085,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } 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() { @@ -1216,7 +1227,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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(); @@ -1909,7 +1920,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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 @@ -2184,7 +2195,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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) { @@ -2304,7 +2315,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); } @@ -2428,7 +2439,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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(); @@ -2452,6 +2463,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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; @@ -2539,12 +2554,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -2818,6 +2833,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati ValueAnimator backAnimator; PremiumLockIconView premiumLockIconView; public boolean selected; + private boolean shouldSelected; private float pressedProgress; public float skewAlpha; public int skewIndex; @@ -2904,6 +2920,66 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } + 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; @@ -2914,23 +2990,24 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } 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); } } @@ -2984,7 +3061,13 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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; } @@ -3078,7 +3161,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -3150,14 +3233,14 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -3191,6 +3274,20 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } + } 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); @@ -3227,7 +3324,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } - 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); } @@ -3235,9 +3332,13 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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) { @@ -3246,7 +3347,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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) { @@ -3356,13 +3457,13 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } - 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)) { @@ -3388,7 +3489,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } - 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); @@ -3421,7 +3522,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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; } @@ -3453,7 +3554,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - 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); @@ -3463,7 +3564,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - emojiTabs.updateEmojiPacks(packs); + if (type != TYPE_EXPANDABLE_REACTIONS) { + emojiTabs.updateEmojiPacks(packs); + } if (animated) { emojiGridView.setItemAnimator(emojiItemAnimator); @@ -3501,6 +3604,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } + 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; @@ -3575,15 +3684,32 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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; } @@ -3644,14 +3770,16 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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++) { @@ -3816,7 +3944,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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++) { @@ -3890,7 +4018,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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)); } @@ -4053,7 +4181,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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); @@ -4079,11 +4207,15 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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 { @@ -4253,7 +4385,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati 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) { @@ -4328,7 +4460,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } }); - 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(); @@ -4904,6 +5036,67 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } + 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 72475b6f0..536b08afc 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.messenger.UserConfig; 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.RLottieImageView; 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente languagesData = chartsViewData[7]; notificationsData = chartsViewData[8]; + reactionsByEmotionData = chartsViewData[9]; + storyInteractionsData = chartsViewData[10]; + storyReactionsByEmotionData = chartsViewData[11]; + dataLoaded(chartsViewData); }); @@ -359,17 +410,45 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente if (recentPostsLoaded.size() < 20) { loadMessages(); } + sortAllLoadedData(); if (adapter != null) { recyclerListView.setItemAnimator(null); diffUtilsCallback.update(); @@ -450,13 +530,15 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente @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 class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente }; 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente } } 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 class StatisticActivity extends BaseFragment implements NotificationCente } 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 class StatisticActivity extends BaseFragment implements NotificationCente ivInteractionsCell = -1; topHourseCell = -1; notificationsCell = -1; + storyReactionsByEmotionCell = -1; + storyInteractionsCell = -1; + reactionsByEmotionCell = -1; groupMembersCell = -1; newMembersBySourceCell = -1; membersLanguageCell = -1; @@ -1216,13 +1333,31 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } 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 class StatisticActivity extends BaseFragment implements NotificationCente @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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } } }; - 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente } errorTextView.setVisibility(View.VISIBLE); } + checkboxContainer.removeAllViews(); + checkBoxes.clear(); chartView.setData(null); return; } @@ -1989,8 +2131,59 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 @@ public class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente 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 class StatisticActivity extends BaseFragment implements NotificationCente } 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 2eb82b3b9..2c76eab60 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 android.util.SparseIntArray; 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 87556b5d1..d548f11b6 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter avatarImage.clearImage(); return; } - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); avatarImage.setForUserOrChat(object, avatarDrawable); if (mini) { return; @@ -1640,7 +1640,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 cbd8bdabb..50b7e2100 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 static org.telegram.messenger.AndroidUtilities.dp; 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.net.Uri; 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.LinearLayout; 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.AdjustPanLayoutHelper; 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.URLSpanNoUnderline; 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.ArrayList; 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } public boolean clipWithGradient(int tag) { - return tag == 1 || tag == 2; + return tag == 1 || tag == 2 || tag == 3; } @Override @@ -874,6 +893,40 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } + addViewStatistics(popupLayout, storyItem); + if (!unsupported) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, str, false, resourcesProvider).setOnClickListener(v -> { saveToGallery(); @@ -1174,7 +1333,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } + 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } + 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } }; + 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica // 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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(); } @@ -2816,7 +3114,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } }; 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()) { @@ -2924,21 +3222,13 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -2954,8 +3244,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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); @@ -2983,21 +3273,6 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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(); @@ -3355,6 +3630,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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); @@ -3364,6 +3640,57 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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) { @@ -3430,8 +3757,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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) { @@ -3445,13 +3772,20 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -3664,7 +3998,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica "&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) { @@ -3764,6 +4099,12 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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; @@ -3772,6 +4113,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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)); @@ -3785,13 +4129,14 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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); @@ -3825,6 +4170,14 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -3840,8 +4193,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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(""); @@ -3873,7 +4226,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica "&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) { @@ -4154,7 +4508,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica headerView.backupImageView.getImageReceiver().setVisible(true, true); if (changeBoundAnimator != null) { chatActivityEnterView.reset(); - chatActivityEnterView.setAlpha(1f); + chatActivityEnterView.setAlpha(1f - outT); } if (reactionsContainerLayout != null) { reactionsContainerLayout.reset(); @@ -4464,9 +4818,10 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -4476,6 +4831,12 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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) { @@ -4483,6 +4844,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica subtitleAnimator = null; } if (animated) { + subtitleView[1].setOnClickListener(null); subtitleView[1].setText(subtitleView[0].getText()); subtitleView[1].setVisibility(View.VISIBLE); subtitleView[1].setAlpha(1f); @@ -4661,6 +5023,19 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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) { @@ -4708,6 +5083,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica void set(TL_stories.StoryItem storyItem) { this.storyItem = storyItem; + this.reply = null; this.uploadingStory = null; skipped = storyItem instanceof TL_stories.TL_storyItemSkipped; isVideo = isVideoInternal(); @@ -4728,6 +5104,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica void set(StoriesController.UploadingStory uploadingStory) { this.uploadingStory = uploadingStory; + this.reply = null; this.storyItem = null; skipped = false; isVideo = isVideoInternal(); @@ -5062,14 +5439,12 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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); } @@ -5134,6 +5509,17 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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; @@ -5157,17 +5543,6 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -5186,7 +5561,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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) { @@ -5218,8 +5593,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } } - 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); @@ -5254,7 +5632,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } private float getHideInterfaceAlpha() { - return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); + return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); } @Override @@ -5311,7 +5689,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -5718,6 +6096,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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; @@ -5729,6 +6108,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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); @@ -5882,6 +6262,21 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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() { @@ -5903,6 +6298,21 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 07fa34e56..c5bb95363 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.NotificationCenter; 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif } 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 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif } 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 de81dd3f5..30dda1c2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -1256,10 +1256,12 @@ public class StoriesController { } } 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; } } @@ -1440,6 +1442,8 @@ public class StoriesController { 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); @@ -1721,7 +1725,7 @@ public class StoriesController { } public void start() { - if (entry.isEdit && !entry.editedMedia) { + if ((entry.isEdit || entry.isRepost && entry.repostMedia != null) && (!entry.editedMedia && entry.round == null)) { sendUploadedRequest(null); return; } @@ -1892,8 +1896,31 @@ public class StoriesController { 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; @@ -2012,6 +2039,13 @@ public class StoriesController { 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 { @@ -2179,7 +2213,7 @@ public class StoriesController { } } - private final HashMap[] storiesLists = new HashMap[2]; + private final HashMap[] storiesLists = new HashMap[3]; @Nullable public StoriesList getStoriesList(long dialogId, int type) { @@ -2286,6 +2320,7 @@ public class StoriesController { 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; @@ -2394,8 +2429,10 @@ public class StoriesController { 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)); @@ -2413,6 +2450,14 @@ public class StoriesController { 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(); @@ -2423,6 +2468,9 @@ public class StoriesController { 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 { @@ -2436,6 +2484,7 @@ public class StoriesController { 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; @@ -2618,11 +2667,26 @@ public class StoriesController { } 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; } @@ -2638,6 +2702,12 @@ public class StoriesController { } 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 cd3998657..f54614683 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.ActionBar.Theme; 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 e43c492ff..555ededf8 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 class StoriesStorage { 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 498b87501..a26808d75 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.tgnet.tl.TL_stories; 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; @@ -138,6 +139,10 @@ public class StoriesUtilities { unreadState = state = getPredictiveUnreadState(storiesController, dialogId); } + if (params.forceState != 0) { + unreadState = state = params.forceState; + } + if (params.currentState != state) { if (params.currentState == STATE_PROGRESS) { animated = true; @@ -1042,6 +1047,7 @@ public class StoriesUtilities { private long dialogId; public int currentState; + public int forceState; public int prevState; public float progressToSate = 1f; public boolean showProgress = false; @@ -1315,4 +1321,90 @@ public class StoriesUtilities { 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 1187a302a..57b35053f 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.Path; 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.os.Build; 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.SpringAnimation; 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.Field; 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } } + public void onReplyClick(Reply reply) { + + } + public void onLinkLongPress(URLSpan span, View spoilersTextView, Runnable done) { } @@ -251,15 +271,21 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { springAnimation.setStartVelocity(velocityY); springAnimation.start(); } - if (getScrollY() < AndroidUtilities.dp(2)) { + if (getScrollY() < dp(2)) { collapse(); } } @@ -468,7 +494,7 @@ public class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } } + 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 StoryCaptionView extends NestedScrollView { 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 StoryCaptionView extends NestedScrollView { 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 StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { } 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 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { @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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { @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 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 90000e988..c0ff28159 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 class StoryViewer implements NotificationCenter.NotificationCenterDelegat transitionViewHolder.storyImage = null; transitionViewHolder.avatarImage = null; containerView.disableHwAcceleration(); - checkNavBarColor(); locker.unlock(); if (currentPlayerScope != null) { currentPlayerScope.invalidate(); @@ -2222,6 +2224,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat 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 64520608b..b0f56f9ac 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.messenger.AndroidUtilities; 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 class UploadingDotsSpannable extends ReplacementSpan { 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 b45faddfd..c58074d03 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.AnimatorListenerAdapter; 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 android.widget.FrameLayout; 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 class ButtonWithCounterView extends FrameLayout { 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 class ButtonWithCounterView extends FrameLayout { 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 class ButtonWithCounterView extends FrameLayout { 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 class ButtonWithCounterView extends FrameLayout { 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 class ButtonWithCounterView extends FrameLayout { @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 @@ public class ButtonWithCounterView extends FrameLayout { private CircularProgressDrawable loadingDrawable; private int globalAlpha = 255; + private final int subTextAlpha = 200; @Override protected void onDraw(Canvas canvas) { @@ -303,10 +377,30 @@ public class ButtonWithCounterView extends FrameLayout { (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 df224c8c0..684395903 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.ColorFilter; 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.NonNull; 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.LayoutHelper; 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { } }); 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { } 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 class CaptionContainerView extends FrameLayout { 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 @@ public class CaptionContainerView extends FrameLayout { } 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 @@ public class CaptionContainerView extends FrameLayout { } } + 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 @@ public class CaptionContainerView extends FrameLayout { 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 d9642cae3..82dd9c7f1 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 class CaptionStory extends CaptionContainerView { } 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 class CaptionStory extends CaptionContainerView { 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 @@ public class CaptionStory extends CaptionContainerView { 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 15fb236dc..1b689d2b7 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.MessageObject; 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 class DownloadButton extends ImageView { 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 abe8e175c..876204da0 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 848269d9e..4ced1ab84 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 class DualCameraView extends CameraView implements CameraController.Error 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 6daf24ffd..25ef77662 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.PaintTypefaceListView; 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai private AnimatorSet keyboardAnimator; public final KeyboardNotifier keyboardNotifier; + private StoryEntry initialEntry; private ArrayList initialEntities; private int w, h; @@ -272,7 +274,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai }; // addView(entitiesView); + this.initialEntry = entry; this.initialEntities = entities; if (w > 0 && h > 0) { setupEntities(); @@ -1252,7 +1255,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } } - private boolean selectEntity(EntityView entityView) { + public boolean selectEntity(EntityView entityView) { return selectEntity(entityView, true); } @@ -1328,6 +1331,8 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai AndroidUtilities.hideKeyboard(((TextPaintView) currentEntityView).getFocusedView()); hideEmojiPopup(false); } + } else if (currentEntityView instanceof RoundView) { + onDeselectRound((RoundView) currentEntityView); } } changed = true; @@ -1341,6 +1346,9 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai removeEntity(oldEntity); } } + if (oldEntity != currentEntityView && currentEntityView instanceof RoundView) { + onSelectRound((RoundView) currentEntityView); + } if (currentEntityView != null) { currentEntityView.select(selectionContainerView); @@ -2095,6 +2103,8 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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); @@ -3877,6 +3921,63 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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); @@ -3980,6 +4081,10 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai weightChooserView.setShowPreview(true); colorSwatch.brushWeight = weightDefaultValueOverride.get(); setCurrentSwatch(colorSwatch, true); + + if (!creatingNewRound && entityView instanceof RoundView) { + onDeleteRound(); + } } private void registerRemovalUndo(final EntityView entityView) { @@ -4517,4 +4622,19 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 99d4bdb02..509d073e2 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 @@ package org.telegram.ui.Stories.recorder; 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 @@ public class PreviewHighlightView extends FrameLayout { } }; 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 class PreviewHighlightView extends FrameLayout { 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 060bf8efc..7000412b2 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.BlurringShader; 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 class PreviewView extends FrameLayout { setupParts(null); gradientPaint.setShader(null); setupAudio((StoryEntry) null, false); + setupRound(null, null, false); return; } if (entry.isVideo) { @@ -128,6 +134,7 @@ public class PreviewView extends FrameLayout { setupParts(entry); applyMatrix(); setupAudio(entry, false); + setupRound(entry, null, false); } public void setupAudio(StoryEntry entry, boolean animated) { @@ -180,7 +187,7 @@ public class PreviewView extends FrameLayout { } }); 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 class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { } } + @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 class PreviewView extends FrameLayout { } 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 @@ public class PreviewView extends FrameLayout { }).start(); } if (timelineView != null) { - timelineView.setVideo(null, 1); + timelineView.setVideo(null, 1, 0); } AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (whenReady != null) { @@ -539,10 +622,6 @@ public class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { } } + 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 class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { }; 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 class PreviewView extends FrameLayout { } }; + 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 @@ public class PreviewView extends FrameLayout { 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 @@ public class PreviewView extends FrameLayout { } } + 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 class PreviewView extends FrameLayout { 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 753887802..6081706dd 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 class RecordControl extends View implements FlashViews.Invertable { 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 @@ public class RecordControl extends View implements FlashViews.Invertable { } 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 000000000..526926326 --- /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 ef432b18e..eaf72d6aa 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 class SliderView extends View { 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 class SliderView extends View { 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 class SliderView extends View { 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 @@ public class SliderView extends View { @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 e46654cb1..a06875614 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { clearFilter(); if (file != null) { if (fileDeletable && (!isEdit || editedMedia)) { - file.delete(); + file.delete(); } file = null; } @@ -501,6 +519,16 @@ public class StoryEntry extends IStoryPart { } 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { 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 df3a45a14..574ce1168 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.LinearLayoutManager; 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.EditTextBoldCursor; 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 538e0c0c9..d7f2d7507 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 @@ public class StoryPrivacySelector extends View { } 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 5b11bd555..7163aaac3 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.SpannableStringBuilder; 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.AndroidUtilities; 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.SharedConfig; 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.AlertDialog; 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.GestureDetectorFixDoubleTap; 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.SizeNotifierFrameLayout; 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg int iconSize; View view; - protected void show() {} protected void hide() {} protected void drawAbove(Canvas canvas, float alpha) {} @@ -389,6 +396,20 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } prepareClosing = false; -// privacySelectorHintOpened = false; forceBackgroundVisible = false; if (windowManager != null && windowView != null && windowView.getParent() == null) { @@ -472,7 +492,60 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg onClosePrepareListener = null; prepareClosing = false; close(animated); - }, wasSend); + }, wasSend, wasSendPeer); return; } @@ -533,7 +606,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } animateOpenTo(0, animated, this::onCloseDone); - if (openType == 1) { + if (openType == 1 || openType == 0) { windowView.setBackgroundColor(0x00000000); previewButtons.appear(false, true); } @@ -570,6 +643,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg public void onAnimationEnd(Animator animation) { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -606,6 +680,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } else { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -633,6 +708,12 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } else { onResumeInternal(); } + + if (outputEntry != null && outputEntry.isRepost) { + createPhotoPaintView(); + hidePhotoPaintView(); + createFilterPhotoView(); + } } private void onCloseDone() { @@ -694,8 +775,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private int insetLeft, insetTop, insetRight, insetBottom; + private final RectF rectF = new RectF(), fullRectF = new RectF(); + private final Path clipPath = new Path(); + private final Rect rect = new Rect(); + private void applyOpenProgress() { + if (openType != 1) return; + fullRectF.set(previewContainer.getLeft(), previewContainer.getTop(), previewContainer.getMeasuredWidth(), previewContainer.getMeasuredHeight()); + fullRectF.offset(containerView.getX(), containerView.getY()); + AndroidUtilities.lerp(fromRect, fullRectF, openProgress, rectF); + previewContainer.setAlpha(openProgress); + previewContainer.setTranslationX(rectF.left - previewContainer.getLeft() - containerView.getX()); + previewContainer.setTranslationY(rectF.top - previewContainer.getTop() - containerView.getY()); + if (fromSourceView != null && fromSourceView.view != null) { + fromSourceView.view.setTranslationX((fullRectF.left - fromRect.left) * openProgress); + fromSourceView.view.setTranslationY((fullRectF.top - fromRect.top) * openProgress); + } + previewContainer.setScaleX(rectF.width() / previewContainer.getMeasuredWidth()); + previewContainer.setScaleY(rectF.height() / previewContainer.getMeasuredHeight()); + actionBarContainer.setAlpha(openProgress); + controlContainer.setAlpha(openProgress); + captionContainer.setAlpha(openProgress); + } + public class WindowView extends SizeNotifierFrameLayout { private GestureDetectorFixDoubleTap gestureDetector; private ScaleGestureDetector scaleGestureDetector; - public WindowView(Context context) { + public WindowView(Context context) { super(context); gestureDetector = new GestureDetectorFixDoubleTap(context, new GestureListener()); scaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener()); } - private RectF rectF = new RectF(), fullRectF = new RectF(); - private Path clipPath = new Path(); - private Rect rect = new Rect(); private int lastKeyboardHeight; @Override @@ -761,21 +861,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg canvas.scale(s, s); restore = true; } else if (openType == 1) { - fullRectF.set(previewContainer.getLeft(), previewContainer.getTop(), previewContainer.getMeasuredWidth(), previewContainer.getMeasuredHeight()); - fullRectF.offset(containerView.getX(), containerView.getY()); - AndroidUtilities.lerp(fromRect, fullRectF, openProgress, rectF); - previewContainer.setAlpha(openProgress); - previewContainer.setTranslationX(rectF.left - previewContainer.getLeft() - containerView.getX()); - previewContainer.setTranslationY(rectF.top - previewContainer.getTop() - containerView.getY()); - if (fromSourceView != null && fromSourceView.view != null) { - fromSourceView.view.setTranslationX((fullRectF.left - fromRect.left) * openProgress); - fromSourceView.view.setTranslationY((fullRectF.top - fromRect.top) * openProgress); - } - previewContainer.setScaleX(rectF.width() / previewContainer.getMeasuredWidth()); - previewContainer.setScaleY(rectF.height() / previewContainer.getMeasuredHeight()); - actionBarContainer.setAlpha(openProgress); - controlContainer.setAlpha(openProgress); - captionContainer.setAlpha(openProgress); + applyOpenProgress(); } } if (paintView != null) { @@ -1329,6 +1415,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg controlContainer.layout(0, previewH - controlContainer.getMeasuredHeight(), previewW, previewH); navbarContainer.layout(0, previewH, previewW, previewH + navbarContainer.getMeasuredHeight()); captionContainer.layout(0, 0, previewW, previewH); + if (captionEditOverlay != null) { + captionEditOverlay.layout(0, 0, w, h); + } flashViews.foregroundView.layout(0, 0, w, h); if (captionEdit.mentionContainer != null) { @@ -1366,6 +1455,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg measureChildExactly(navbarContainer, previewW, underControls); measureChildExactly(captionContainer, previewW, previewH); measureChildExactly(flashViews.foregroundView, W, H); + if (captionEditOverlay != null) { + measureChildExactly(captionEditOverlay, W, H); + } if (captionEdit.mentionContainer != null) { measureChildExactly(captionEdit.mentionContainer, previewW, previewH); @@ -1431,6 +1523,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private SimpleTextView titleTextView; private StoryPrivacyBottomSheet privacySheet; private BlurringShader.BlurManager blurManager; + private View captionEditOverlay; /* PAGE_CAMERA */ private ImageView cameraViewThumb; @@ -1469,6 +1562,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg // private StoryPrivacySelector.StoryPrivacyHint privacySelectorHint; private PreviewHighlightView previewHighlight; private TrashView trash; + private RoundVideoRecorder currentRoundRecorder; /* EDIT_MODE_PAINT */ private PaintView paintView; @@ -1634,7 +1728,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg cameraViewThumb.setClickable(true); previewContainer.addView(cameraViewThumb, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { previewContainer.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -1648,6 +1742,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg outputEntry = null; wasSend = true; + wasSendPeer = sendAsDialogId; forceBackgroundVisible = true; checkBackgroundVisibility(); @@ -2297,7 +2539,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } public boolean onBackPressed() { + if (captionEdit != null && captionEdit.stopRecording()) { + return false; + } if (takingVideo) { recordControl.stopRecording(); return false; @@ -2942,10 +3190,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg // 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (currentEditMode == editMode) { return; } + if (editMode != EDIT_MODE_NONE && (captionEdit != null && captionEdit.isRecording())) { + return; + } final int oldEditMode = currentEditMode; currentEditMode = editMode; @@ -3717,6 +4027,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg null, previewView.getOrientation(), outputEntry == null ? null : outputEntry.mediaEntities, + outputEntry, w, h, new MediaController.CropState(), null, @@ -3865,6 +4176,64 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (previewHighlight != null) { previewHighlight.bringToFront(); } + if (currentRoundRecorder != null) { + currentRoundRecorder.bringToFront(); + } } private void destroyPhotoPaintView() { @@ -4042,7 +4414,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }); } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 e80473070..8c138ccce 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { } }); 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 class TimelineView extends View { }) .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 class TimelineView extends View { 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 class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 class TimelineView extends View { } 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 @@ public class TimelineView extends View { } 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { } 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { @Override public boolean onTouchEvent(MotionEvent event) { - if (!hasVideo && !hasAudio) { + if (!hasVideo && !hasAudio && !hasRound) { return false; } - if (hasVideo && !hasAudio && event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < h - py - getVideoHeight() - py) { - 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 class TimelineView extends View { } 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 class TimelineView extends View { 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 class TimelineView extends View { } 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 class TimelineView extends View { 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 class TimelineView extends View { delegate.onProgressDragChange(true); } } - if (!hasVideo) { + if (!hasVideo && !hasRound) { progress = (long) (audioLeft * audioDuration); if (delegate != null) { delegate.onProgressDragChange(true); @@ -651,11 +868,90 @@ public class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { } 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { } 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 @@ public class TimelineView extends View { } } + 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 class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { } // 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 @@ public class TimelineView extends View { // 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 @@ public class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 class TimelineView extends View { 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 9fa7630ba..b1f5f1190 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 1c5ab42f4..1f9e60c88 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -2192,7 +2192,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No 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 49a5c3768..ede8d96a5 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.StateListAnimator; 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.Drawable; 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.ApplicationLoader; 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.SendMessagesHelper; 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.ActionBarMenuItem; 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.Cells.PatternCell; 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro scroller.abortAnimation(); } currentScrollOffset = Utilities.clamp(currentScrollOffset + distanceX, maxScrollOffset, 0); + invalidateBlur(); backgroundImage.invalidate(); return true; } @@ -425,9 +466,9 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } @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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } hintView.setBackgroundColor(0xea272f38, 0xffffffff); hintView.showForView(dayNightItem, true); - hintView.setExtraTranslationY(-AndroidUtilities.dp(14)); + hintView.setExtraTranslationY(-dp(14)); }, 2000); } @@ -647,7 +689,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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.MULTIPLY)); 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro updateBlurred(); } } + + @Override + public boolean allowCaption() { + return false; + } }, null); // AndroidUtilities.runOnUIThread(() -> { // PhotoViewer.getInstance().switchToEditMode(PhotoViewer.EDIT_MODE_FILTER); @@ -959,31 +1034,18 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } } } - 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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); + 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; + } + 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))); + } + + 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(); } - canvas.save(); - canvas.clipRect(0, offset, getMeasuredWidth(), getMeasuredHeight()); + super.dispatchDraw(canvas); - canvas.restore(); + } + + @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)); + } + } } }; 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)); + 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)); - - 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)); + applyButton1 = new BlurButton(context); + ScaleStateListAnimator.apply(applyButton1, 0.033f, 1.2f); if (dialogId != 0) { - bottomOverlayChatText.setText(LocaleController.getString("ApplyBackgroundForThisChat", R.string.ApplyBackgroundForThisChat)); + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaperForMe)); } else { - bottomOverlayChatText.setText(LocaleController.getString("SetBackground", R.string.SetBackground)); + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaper)); } - FrameLayout textContainer = new FrameLayout(getContext()); + applyButton1.setOnClickListener(view -> applyWallpaperBackground(false)); - 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); - } - } 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 (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); } - 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; - } - } - 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, () -> { - - }); - } - 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(); - } - }); - - AndroidUtilities.updateViewVisibilityAnimated(buttonProgressView, false, 0.5f, false); - AndroidUtilities.updateViewVisibilityAnimated(bottomOverlayChatText, true, 0.8f, false); + 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)); + } if (shouldShowBrightnessControll) { - dimmingHeaderCell = new HeaderCell(getContext(), getResourceProvider()); - dimmingHeaderCell.setText(LocaleController.getString("BackgroundDimming", R.string.BackgroundDimming)); - brightnessControlCell = new BrightnessControlCell(getContext(), BrightnessControlCell.TYPE_WALLPAPER_DIM, getResourceProvider()) { + 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 didChangedValue(float value) { - dimAmount = value; - backgroundImage.invalidate(); + 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); + } + + dimPaint.setColor(0x1effffff); + dimPaint.setAlpha((int) (0x1e * dimmingSlider.getAlpha())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + + super.dispatchDraw(canvas); } }; - 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)); + 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 + public boolean dispatchTouchEvent(MotionEvent event) { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return super.dispatchTouchEvent(event); + } + }; + 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro @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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro @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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro @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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } else { layoutParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? 273 : 316, Gravity.LEFT | Gravity.BOTTOM); } - if (a == 0) { - layoutParams.height += AndroidUtilities.dp(12) + paddings.top; - patternLayout[a].setPadding(0, AndroidUtilities.dp(12) + paddings.top, 0, 0); + layoutParams.height = dp(a == 0 ? (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 321 : 273) : 316); + if (insideBottomSheet()) { + layoutParams.height += AndroidUtilities.navigationBarHeight; } + if (a == 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } }; 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro @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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } else { messagesAdapter.notifyItemChanged(0); } - listView2.smoothScrollBy(0, AndroidUtilities.dp(60)); + listView2.smoothScrollBy(0, dp(60)); break; } case 3: { @@ -2720,7 +2910,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro @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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro }); } 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro ChatActionCell actionCell = (ChatActionCell) view; actionCell.setMessageObject(message); actionCell.setAlpha(1.0f); + invalidateBlur(); } } } @@ -5138,13 +5455,12 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro } } - 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro maxScrollOffset = currentScrollOffset * 2f; setSize(scaledWidth, getMeasuredHeight()); drawFromStart = true; + invalidateBlur(); } } if (!hasScrollingBackground) { @@ -5361,8 +5677,12 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 7abc7d5cf..892f20b1e 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.LinearLayoutManager; 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.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.concurrent.CountDownLatch; public class TopicsFragment extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ChatActivityInterface, RightSlidingDialogContainer.BaseFragmentWithFullscreen { @@ -193,6 +192,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; @@ -289,6 +289,32 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N 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; @@ -509,7 +535,13 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N 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); @@ -1395,7 +1427,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N 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); @@ -3788,10 +3820,19 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N 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 e06ad05e3..ffcf9a5ee 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 @@ public class WallpapersListActivity extends BaseFragment implements Notification 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 @@ public class WallpapersListActivity extends BaseFragment implements Notification } 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/res/drawable-hdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png new file mode 100644 index 000000000..1f844a273 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 000000000..03b2d45ef 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 000000000..2245861dc 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 000000000..355c4f13f 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 000000000..808f9ae3c 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 000000000..709571fa6 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 000000000..c47e4e9e6 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 000000000..99bccfe6f 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 000000000..be789e65a 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 000000000..6f5e67b25 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 000000000..d40990d27 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 000000000..1036f8920 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 000000000..e803328fb 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 000000000..d4deca8d7 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 000000000..de4e490c9 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 000000000..d64b98a4b 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 000000000..8dc4d326d 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 000000000..07bb83dbb 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 000000000..af6140b39 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 000000000..73c8be7f1 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 000000000..14365619c 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 000000000..df8e932c5 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 000000000..29916aec8 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 000000000..efa599654 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 000000000..dff98af83 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 000000000..a6abb3cc0 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 000000000..4b8689ba0 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 000000000..035182d87 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 000000000..d33496c22 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 000000000..2685bf33f 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 000000000..f80c8f39d 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 000000000..3b8ad4a6e 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 000000000..8efc78de4 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 000000000..44e726d83 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 000000000..bd39b06b3 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 000000000..9f4714673 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 000000000..f2491c413 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 000000000..7e8c3c573 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 000000000..fb85886d3 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 000000000..4c3f94c91 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 000000000..b4e6d2248 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 000000000..ae3a4f79f 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 000000000..b19cf84b3 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 000000000..f8ddf1bd8 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 000000000..d6367f326 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 000000000..7072f8380 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 000000000..6f541d8aa 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 000000000..9a2a0eebf 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 000000000..6eff47a6b 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 000000000..657125f35 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 000000000..bdb88fd40 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 000000000..76d338c6f 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 000000000..ab5f7e90e 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 000000000..7b120b70b 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 000000000..f5a7aa28d 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 000000000..4fa0ca759 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 000000000..76c7f87e7 --- /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 cbba96099..c0ded6827 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 000000000..673fc165d --- /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 000000000..5065c247d --- /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 321a62bc1..7cd65a063 100644 --- a/TMessagesProj/src/main/res/values/ids.xml +++ b/TMessagesProj/src/main/res/values/ids.xml @@ -9,6 +9,7 @@ + diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 621f9e89f..f2c3d2f8a 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 @@ -5923,6 +5957,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. @@ -6030,6 +6066,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 @@ -6270,17 +6310,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 @@ -6589,10 +6629,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 @@ -6714,6 +6757,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 @@ -6759,6 +6803,8 @@ Couldn’t upload Try Again Story + Story Statistics + Post Statistics Message sent. Just now Expired story @@ -7171,11 +7217,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 @@ -7206,6 +7265,7 @@ list of viewers. Photo Send reaction as a private message Remove Audio + Remove Video Publish story as Who can view your story Style @@ -7248,6 +7308,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 @@ -7668,8 +7733,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 @@ -7680,7 +7747,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. @@ -7697,6 +7769,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 @@ -7704,5 +7777,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. diff --git a/gradle.properties b/gradle.properties index b03f11abb..ff409bf10 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Mar 12 05:53:50 MSK 2016 -APP_VERSION_CODE=4087 -APP_VERSION_NAME=10.2.9 +APP_VERSION_CODE=4145 +APP_VERSION_NAME=10.3.2 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey