diff --git a/TMessagesProj/jni/tgnet/ApiScheme.cpp b/TMessagesProj/jni/tgnet/ApiScheme.cpp index 9093b19c8..923bfbaa7 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.cpp +++ b/TMessagesProj/jni/tgnet/ApiScheme.cpp @@ -1210,21 +1210,30 @@ UserStatus *UserStatus::TLdeserialize(NativeByteBuffer *stream, uint32_t constru case 0x8c703f: result = new TL_userStatusOffline(); break; - case 0x7bf09fc: - result = new TL_userStatusLastWeek(); - break; case 0x9d05049: result = new TL_userStatusEmpty(); break; - case 0x77ebc742: - result = new TL_userStatusLastMonth(); - break; case 0xedb93949: result = new TL_userStatusOnline(); break; - case 0xe26f42f1: + case 0x7b197dc8: result = new TL_userStatusRecently(); break; + case 0x541a1d1a: + result = new TL_userStatusLastWeek(); + break; + case 0x65899777: + result = new TL_userStatusLastMonth(); + break; + case 0xe26f42f1: + result = new TL_userStatusRecently_layer171(); + break; + case 0x7bf09fc: + result = new TL_userStatusLastWeek_layer171(); + break; + case 0x77ebc742: + result = new TL_userStatusLastMonth_layer171(); + break; default: error = true; if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in UserStatus", constructor); @@ -1243,8 +1252,19 @@ void TL_userStatusOffline::serializeToStream(NativeByteBuffer *stream) { stream->writeInt32(expires); } +void TL_userStatusLastWeek_layer171::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + void TL_userStatusLastWeek::serializeToStream(NativeByteBuffer *stream) { stream->writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream->writeInt32(flags); +} + +void TL_userStatusLastWeek::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) { + flags = stream->readInt32(&error); + by_me = (flags & 1) != 0; } void TL_userStatusEmpty::serializeToStream(NativeByteBuffer *stream) { @@ -1253,6 +1273,17 @@ void TL_userStatusEmpty::serializeToStream(NativeByteBuffer *stream) { void TL_userStatusLastMonth::serializeToStream(NativeByteBuffer *stream) { stream->writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream->writeInt32(flags); +} + +void TL_userStatusLastMonth::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) { + flags = stream->readInt32(&error); + by_me = (flags & 1) != 0; +} + +void TL_userStatusLastMonth_layer171::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); } void TL_userStatusOnline::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) { @@ -1266,6 +1297,21 @@ void TL_userStatusOnline::serializeToStream(NativeByteBuffer *stream) { void TL_userStatusRecently::serializeToStream(NativeByteBuffer *stream) { stream->writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream->writeInt32(flags); +} + +void TL_userStatusRecently::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) { + flags = stream->readInt32(&error); + by_me = (flags & 1) != 0; +} + +void TL_userStatusRecently_layer171::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_userStatusHidden::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); } FileLocation *FileLocation::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) { diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index edee2074f..e2d682076 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -203,6 +203,18 @@ public: class TL_userStatusLastWeek : public UserStatus { +public: + static const uint32_t constructor = 0x7bf09fc; + + uint32_t flags; + bool by_me; + + void serializeToStream(NativeByteBuffer *stream); + void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); +}; + +class TL_userStatusLastWeek_layer171 : public UserStatus { + public: static const uint32_t constructor = 0x7bf09fc; @@ -219,6 +231,19 @@ public: class TL_userStatusLastMonth : public UserStatus { +public: + static const uint32_t constructor = 0x65899777; + + uint32_t flags; + bool by_me; + + void serializeToStream(NativeByteBuffer *stream); + + void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); +}; + +class TL_userStatusLastMonth_layer171 : public UserStatus { + public: static const uint32_t constructor = 0x77ebc742; @@ -236,12 +261,32 @@ public: class TL_userStatusRecently : public UserStatus { +public: + static const uint32_t constructor = 0x7b197dc8; + + uint32_t flags; + bool by_me; + + void serializeToStream(NativeByteBuffer *stream); + void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); +}; + +class TL_userStatusRecently_layer171 : public UserStatus { + public: static const uint32_t constructor = 0xe26f42f1; void serializeToStream(NativeByteBuffer *stream); }; +class TL_userStatusHidden : public UserStatus { + +public: + static const uint32_t constructor = 0xcf7d64b1; + + void serializeToStream(NativeByteBuffer *stream); +}; + class FileLocation : public TLObject { public: diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index fded91118..63066e626 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -569,15 +569,13 @@ - - + + - - diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java index 66516c7b0..765c7c3cf 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java @@ -5,6 +5,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.util.Log; import android.util.LongSparseArray; import android.view.View; import android.view.ViewPropertyAnimator; @@ -51,6 +52,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator { private ArrayList willChangedGroups = new ArrayList<>(); HashMap animators = new HashMap<>(); + ArrayList thanosViews = new ArrayList<>(); ArrayList runOnAnimationsEnd = new ArrayList<>(); HashMap groupIdToEnterDelay = new HashMap<>(); @@ -925,7 +927,12 @@ public class ChatListItemAnimator extends DefaultItemAnimator { animator.removeAllListeners(); restoreTransitionParams(holder.itemView); if (holder.itemView instanceof ChatMessageCell) { - MessageObject.GroupedMessages group = ((ChatMessageCell) view).getCurrentMessagesGroup(); + ChatMessageCell cell = (ChatMessageCell) holder.itemView; + if (cell.makeVisibleAfterChange) { + cell.makeVisibleAfterChange = false; + cell.setVisibility(View.VISIBLE); + } + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); if (group != null) { group.transitionParams.reset(); } @@ -1092,6 +1099,12 @@ public class ChatListItemAnimator extends DefaultItemAnimator { animator.cancel(); } } + if (!thanosViews.isEmpty()) { + ThanosEffect thanosEffect = getThanosEffectContainer.run(); + if (thanosEffect != null) { + thanosEffect.kill(); + } + } } @Override @@ -1100,6 +1113,12 @@ public class ChatListItemAnimator extends DefaultItemAnimator { if (animator != null) { animator.cancel(); } + if (thanosViews.contains(item.itemView)) { + ThanosEffect thanosEffect = getThanosEffectContainer.run(); + if (thanosEffect != null) { + thanosEffect.cancel(item.itemView); + } + } super.endAnimation(item); restoreTransitionParams(item.itemView); } @@ -1230,6 +1249,12 @@ public class ChatListItemAnimator extends DefaultItemAnimator { if (a != null) { a.cancel(); } + if (thanosViews.contains(item.itemView)) { + ThanosEffect thanosEffect = getThanosEffectContainer.run(); + if (thanosEffect != null) { + thanosEffect.cancel(item.itemView); + } + } boolean oldItem = false; if (changeInfo.newHolder == item) { @@ -1447,7 +1472,9 @@ public class ChatListItemAnimator extends DefaultItemAnimator { dispatchRemoveFinished(holder); dispatchFinishedWhenDone(); } + thanosViews.remove(view); }); + thanosViews.add(view); } else { ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), 0f); dispatchRemoveStarting(holder); @@ -1497,7 +1524,9 @@ public class ChatListItemAnimator extends DefaultItemAnimator { } dispatchFinishedWhenDone(); } + thanosViews.removeAll(views); }); + thanosViews.add(views.get(0)); recyclerListView.stopScroll(); } diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/GridLayoutManagerFixed.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/GridLayoutManagerFixed.java index 265c55aad..06b9b0c10 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/GridLayoutManagerFixed.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/GridLayoutManagerFixed.java @@ -11,6 +11,10 @@ import android.content.Context; import android.graphics.Rect; import android.view.View; +import com.google.android.exoplayer2.util.Log; + +import org.telegram.ui.Cells.ChatMessageCell; + import java.util.ArrayList; import java.util.Arrays; @@ -68,8 +72,9 @@ public class GridLayoutManagerFixed extends GridLayoutManager { } else { for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (mOrientationHelper.getDecoratedEnd(child) > scrollingOffset - || mOrientationHelper.getTransformedEndWithDecoration(child) > scrollingOffset) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + if (child.getBottom() + params.bottomMargin > scrollingOffset + || child.getTop() + child.getHeight() > scrollingOffset) { // stop here recycleChildren(recycler, 0, i); return; @@ -115,12 +120,15 @@ public class GridLayoutManagerFixed extends GridLayoutManager { final int otherDirSpecMode = mOrientationHelper.getModeInOther(); final boolean layingOutInPrimaryDirection = layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL; - boolean working = true; result.mConsumed = 0; - int yOffset = 0; int startPosition = layoutState.mCurrentPosition; - if (layoutState.mLayoutDirection != LayoutState.LAYOUT_START && hasSiblingChild(layoutState.mCurrentPosition) && findViewByPosition(layoutState.mCurrentPosition + 1) == null) { + if ( + mShouldReverseLayout && + layoutState.mLayoutDirection != LayoutState.LAYOUT_START && + hasSiblingChild(layoutState.mCurrentPosition) && + findViewByPosition(layoutState.mCurrentPosition + 1) == null + ) { if (hasSiblingChild(layoutState.mCurrentPosition + 1)) { layoutState.mCurrentPosition += 3; } else { @@ -144,18 +152,14 @@ public class GridLayoutManagerFixed extends GridLayoutManager { layoutState.mCurrentPosition = backupPosition; } + boolean working = true; while (working) { int count = 0; - int consumedSpanCount = 0; int remainingSpan = mSpanCount; - working = !additionalViews.isEmpty(); - int firstPositionStart = layoutState.mCurrentPosition; - while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) { int pos = layoutState.mCurrentPosition; final int spanSize = getSpanSize(recycler, state, pos); - remainingSpan -= spanSize; if (remainingSpan < 0) { break; @@ -171,7 +175,6 @@ public class GridLayoutManagerFixed extends GridLayoutManager { if (view == null) { break; } - consumedSpanCount += spanSize; mSet[count] = view; count++; if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START && remainingSpan <= 0 && hasSiblingChild(pos)) { @@ -236,9 +239,11 @@ public class GridLayoutManagerFixed extends GridLayoutManager { } int left, right, top, bottom; - - boolean fromOpositeSide = shouldLayoutChildFromOpositeSide(mSet[0]); - if (fromOpositeSide && layoutState.mLayoutDirection == LayoutState.LAYOUT_START || !fromOpositeSide && layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { + boolean fromOppositeSide = shouldLayoutChildFromOpositeSide(mSet[0]); + if ( + fromOppositeSide && layoutState.mLayoutDirection == LayoutState.LAYOUT_START || + !fromOppositeSide && layoutState.mLayoutDirection == LayoutState.LAYOUT_END + ) { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { bottom = layoutState.mOffset - result.mConsumed; top = bottom - maxSize; @@ -284,7 +289,7 @@ public class GridLayoutManagerFixed extends GridLayoutManager { left -= right; } layoutDecoratedWithMargins(view, left, top, left + right, bottom); - if (layoutState.mLayoutDirection != LayoutState.LAYOUT_START) { + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { left += right; } if (params.isItemRemoved() || params.isItemChanged()) { diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java index 3ada48885..40b1145a8 100755 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java @@ -10,6 +10,8 @@ package org.telegram.SQLite; import android.os.SystemClock; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; import org.telegram.tgnet.NativeByteBuffer; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 1b0801312..a09a3d127 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -153,6 +153,8 @@ import org.telegram.ui.Components.HideViewAfterAnimation; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.PickerBottomLayout; +import org.telegram.ui.Components.PipRoundVideoView; +import org.telegram.ui.Components.PipVideoOverlay; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ShareAlert; import org.telegram.ui.Components.TypefaceSpan; @@ -5225,6 +5227,9 @@ public class AndroidUtilities { int[] location = new int[2]; for (int i = 0; i < finalViews.size(); ++i) { View view = finalViews.get(i); + if (view instanceof PipRoundVideoView.PipFrameLayout || view instanceof PipRoundVideoView.PipFrameLayout) { + continue; + } ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); if (layoutParams instanceof WindowManager.LayoutParams) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java index 8e2b38007..92e45c323 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimatedFileDrawableStream.java @@ -27,14 +27,14 @@ public class AnimatedFileDrawableStream implements FileLoadOperationStream { private int debugCanceledCount; private boolean debugReportSend; - public AnimatedFileDrawableStream(TLRPC.Document d, ImageLocation l, Object p, int a, boolean prev, int loadingPriority) { + public AnimatedFileDrawableStream(TLRPC.Document d, ImageLocation l, Object p, int a, boolean prev, int loadingPriority, int cacheType) { document = d; location = l; parentObject = p; currentAccount = a; preview = prev; this.loadingPriority = loadingPriority; - loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, location, parentObject, 0, preview, loadingPriority); + loadOperation = FileLoader.getInstance(currentAccount).loadStreamFile(this, document, location, parentObject, 0, preview, loadingPriority, cacheType); } public boolean isFinishedLoadingFile() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java index 3a2d60869..8a4ae4192 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChannelBoostsController.java @@ -5,12 +5,19 @@ import com.google.android.exoplayer2.util.Consumer; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.Premium.boosts.BoostRepository; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class ChannelBoostsController { @@ -27,7 +34,6 @@ public class ChannelBoostsController { connectionsManager = ConnectionsManager.getInstance(currentAccount); } - public void getBoostsStats(long dialogId, Consumer consumer) { TL_stories.TL_premium_getBoostsStatus req = new TL_stories.TL_premium_getBoostsStatus(); req.peer = messagesController.getInputPeer(dialogId); @@ -35,7 +41,22 @@ public class ChannelBoostsController { if (response != null) { consumer.accept((TL_stories.TL_premium_boostsStatus) response); } else { - BulletinFactory.showForError(error); + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (error != null && fragment != null && "CHANNEL_PRIVATE".equals(error.text)) { + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getContext(), fragment.getResourceProvider()); + builder.setTitle(LocaleController.getString(R.string.AppName)); + Map colorsReplacement = new HashMap<>(); + colorsReplacement.put("info1.**", Theme.getColor(Theme.key_dialogTopBackground)); + colorsReplacement.put("info2.**", Theme.getColor(Theme.key_dialogTopBackground)); + builder.setTopAnimation(R.raw.not_available, AlertsCreator.NEW_DENY_DIALOG_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground), colorsReplacement); + builder.setTopAnimationIsNew(true); + builder.setTitle(LocaleController.getString(R.string.ChannelPrivate)); + builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate2", R.string.ChannelCantOpenPrivate2)); + builder.setPositiveButton(LocaleController.getString(R.string.Close), null); + builder.show(); + } else { + BulletinFactory.global().showForError(error); + } consumer.accept(null); } })); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index d3891b270..1113b1c70 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -1826,11 +1826,11 @@ public class ChatObject { public static boolean canManageTopic(int currentAccount, TLRPC.Chat chat, TLRPC.TL_forumTopic topic) { return canManageTopics(chat) || isMyTopic(currentAccount, topic); } - public static boolean canManageTopic(int currentAccount, TLRPC.Chat chat, int topicId) { + public static boolean canManageTopic(int currentAccount, TLRPC.Chat chat, long topicId) { return canManageTopics(chat) || isMyTopic(currentAccount, chat, topicId); } - public static boolean canDeleteTopic(int currentAccount, TLRPC.Chat chat, int topicId) { + public static boolean canDeleteTopic(int currentAccount, TLRPC.Chat chat, long topicId) { if (topicId == 1) { // general topic can't be deleted return false; @@ -1849,11 +1849,11 @@ public class ChatObject { return topic != null && (topic.my || topic.from_id instanceof TLRPC.TL_peerUser && topic.from_id.user_id == UserConfig.getInstance(currentAccount).clientUserId); } - public static boolean isMyTopic(int currentAccount, TLRPC.Chat chat, int topicId) { + public static boolean isMyTopic(int currentAccount, TLRPC.Chat chat, long topicId) { return chat != null && chat.forum && isMyTopic(currentAccount, chat.id, topicId); } - public static boolean isMyTopic(int currentAccount, long chatId, int topicId) { + public static boolean isMyTopic(int currentAccount, long chatId, long topicId) { return isMyTopic(currentAccount, MessagesController.getInstance(currentAccount).getTopicsController().findTopic(chatId, topicId)); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index e9be41659..2c6bfd3eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -93,6 +93,7 @@ public class ContactsController extends BaseController { public final static int PRIVACY_RULES_TYPE_ADDED_BY_PHONE = 7; public final static int PRIVACY_RULES_TYPE_VOICE_MESSAGES = 8; public final static int PRIVACY_RULES_TYPE_BIO = 9; + public final static int PRIVACY_RULES_TYPE_MESSAGES = 10; public final static int PRIVACY_RULES_TYPE_COUNT = 10; @@ -221,6 +222,7 @@ public class ContactsController extends BaseController { public ArrayList phoneBookContacts = new ArrayList<>(); public HashMap> phoneBookSectionsDict = new HashMap<>(); public ArrayList phoneBookSectionsArray = new ArrayList<>(); + public HashMap phoneBookByShortPhones = new HashMap<>(); public ArrayList contacts = new ArrayList<>(); public ConcurrentHashMap contactsDict = new ConcurrentHashMap<>(20, 1.0f, 2); @@ -306,6 +308,7 @@ public class ContactsController extends BaseController { contactsByShortPhone.clear(); phoneBookSectionsDict.clear(); phoneBookSectionsArray.clear(); + phoneBookByShortPhones.clear(); loadingContacts = false; contactsSyncInProgress = false; @@ -528,6 +531,7 @@ public class ContactsController extends BaseController { sortedUsersSectionsArray.clear(); phoneBookSectionsDict.clear(); phoneBookSectionsArray.clear(); + phoneBookByShortPhones.clear(); delayedContactsUpdate.clear(); sortedUsersMutualSectionsArray.clear(); contactsByPhone.clear(); @@ -1717,7 +1721,7 @@ public class ContactsController extends BaseController { if (from != 1 && !isEmpty) { saveContactsLoadTime(); } else { - reloadContactsStatusesMaybe(); + reloadContactsStatusesMaybe(false); } if (finalReloadContacts) { loadContacts(false, 0); @@ -1752,11 +1756,11 @@ public class ContactsController extends BaseController { return contactsDict.get(userId) != null; } - public void reloadContactsStatusesMaybe() { + public void reloadContactsStatusesMaybe(boolean force) { try { SharedPreferences preferences = MessagesController.getMainSettings(currentAccount); long lastReloadStatusTime = preferences.getLong("lastReloadStatusTime", 0); - if (lastReloadStatusTime < System.currentTimeMillis() - 1000 * 60 * 60 * 3) { + if (lastReloadStatusTime < System.currentTimeMillis() - 1000 * 60 * 60 * 3 || force) { reloadContactsStatuses(); } } catch (Exception e) { @@ -1774,29 +1778,35 @@ public class ContactsController extends BaseController { } private void mergePhonebookAndTelegramContacts(final HashMap> phoneBookSectionsDictFinal, final ArrayList phoneBookSectionsArrayFinal, final HashMap phoneBookByShortPhonesFinal) { + mergePhonebookAndTelegramContacts(phoneBookSectionsDictFinal, phoneBookSectionsArrayFinal,phoneBookByShortPhonesFinal, true); + } + + private void mergePhonebookAndTelegramContacts(final HashMap> phoneBookSectionsDictFinal, final ArrayList phoneBookSectionsArrayFinal, final HashMap phoneBookByShortPhonesFinal, boolean needUpdateLists) { final ArrayList contactsCopy = new ArrayList<>(contacts); Utilities.globalQueue.postRunnable(() -> { - for (int a = 0, size = contactsCopy.size(); a < size; a++) { - TLRPC.TL_contact value = contactsCopy.get(a); - TLRPC.User user = getMessagesController().getUser(value.user_id); - if (user == null || TextUtils.isEmpty(user.phone)) { - continue; - } - String phone = user.phone.substring(Math.max(0, user.phone.length() - 7)); - Contact contact = phoneBookByShortPhonesFinal.get(phone); - if (contact != null) { - if (contact.user == null) { - contact.user = user; + if(needUpdateLists) { + for (int a = 0, size = contactsCopy.size(); a < size; a++) { + TLRPC.TL_contact value = contactsCopy.get(a); + TLRPC.User user = getMessagesController().getUser(value.user_id); + if (user == null || TextUtils.isEmpty(user.phone)) { + continue; } - } else { - String key = Contact.getLetter(user.first_name, user.last_name); - ArrayList arrayList = phoneBookSectionsDictFinal.get(key); - if (arrayList == null) { - arrayList = new ArrayList<>(); - phoneBookSectionsDictFinal.put(key, arrayList); - phoneBookSectionsArrayFinal.add(key); + String phone = user.phone.substring(Math.max(0, user.phone.length() - 7)); + Contact contact = phoneBookByShortPhonesFinal.get(phone); + if (contact != null) { + if (contact.user == null) { + contact.user = user; + } + } else { + String key = Contact.getLetter(user.first_name, user.last_name); + ArrayList arrayList = phoneBookSectionsDictFinal.get(key); + if (arrayList == null) { + arrayList = new ArrayList<>(); + phoneBookSectionsDictFinal.put(key, arrayList); + phoneBookSectionsArrayFinal.add(key); + } + arrayList.add(user); } - arrayList.add(user); } } final Collator collator = getLocaleCollator(); @@ -1847,6 +1857,7 @@ public class ContactsController extends BaseController { }); AndroidUtilities.runOnUIThread(() -> { phoneBookSectionsArray = phoneBookSectionsArrayFinal; + phoneBookByShortPhones = phoneBookByShortPhonesFinal; phoneBookSectionsDict = phoneBookSectionsDictFinal; }); }); @@ -2386,8 +2397,46 @@ public class ContactsController extends BaseController { } AndroidUtilities.runOnUIThread(() -> { + boolean needResort = false; for (int a = 0; a < res.users.size(); a++) { TLRPC.User u = res.users.get(a); + if (u.contact) { + Contact phoneBookContact = contactsBookSPhones.get(u.phone); + if (phoneBookContact != null) { + String oldKey = phoneBookContact.getLetter(); + String newKey = Contact.getLetter(user.first_name, user.last_name); + if (phoneBookContact.user == null) { + phoneBookContact.user = user; + if (!oldKey.equals(newKey)) { + ArrayList arrayList = phoneBookSectionsDict.get(newKey); + if (arrayList == null) { + arrayList = new ArrayList<>(); + phoneBookSectionsDict.put(newKey, arrayList); + phoneBookSectionsArray.add(newKey); + } + arrayList.add(phoneBookContact); + + arrayList = phoneBookSectionsDict.get(oldKey); + if (arrayList != null) { + for (Object obj : arrayList) { + if (obj instanceof Contact) { + Contact oldContact = (Contact) obj; + if (oldContact.contact_id == phoneBookContact.contact_id) { + boolean removed = arrayList.remove(oldContact); + if (removed && arrayList.isEmpty()) { + phoneBookSectionsDict.remove(oldKey); + phoneBookSectionsArray.remove(oldKey); + } + break; + } + } + } + } + } + needResort = true; + } + } + } if (!u.contact || contactsDict.get(u.id) != null) { continue; } @@ -2397,6 +2446,9 @@ public class ContactsController extends BaseController { contactsDict.put(newContact.user_id, newContact); } buildContactsSectionsArrays(true); + if (needResort) { + mergePhonebookAndTelegramContacts(phoneBookSectionsDict, phoneBookSectionsArray, phoneBookByShortPhones, false); + } getNotificationCenter().postNotificationName(NotificationCenter.contactsDidLoad); }); }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagCanCompress); @@ -2491,11 +2543,11 @@ public class ContactsController extends BaseController { continue; } if (status.status instanceof TLRPC.TL_userStatusRecently) { - status.status.expires = -100; + status.status.expires = status.status.by_me ? -1000 : -100; } else if (status.status instanceof TLRPC.TL_userStatusLastWeek) { - status.status.expires = -101; + status.status.expires = status.status.by_me ? -1001 : -101; } else if (status.status instanceof TLRPC.TL_userStatusLastMonth) { - status.status.expires = -102; + status.status.expires = status.status.by_me ? -1002 : -102; } TLRPC.User user = getMessagesController().getUser(status.user_id); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 2945860ea..497231fe7 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1392,6 +1392,29 @@ public class DatabaseMigrationHelper { version = 136; } + if (version == 136) { + database.executeFast("CREATE TABLE saved_dialogs(did INTEGER PRIMARY KEY, date INTEGER, last_mid INTEGER, pinned INTEGER, flags INTEGER, folder_id INTEGER, last_mid_group INTEGER, count INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON saved_dialogs(date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON saved_dialogs(last_mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS folder_id_idx_dialogs ON saved_dialogs(folder_id);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS flags_idx_dialogs ON saved_dialogs(flags);").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 137").stepThis().dispose(); + version = 137; + } + + if (version == 137) { + database.executeFast("ALTER TABLE unread_push_messages ADD COLUMN is_reaction INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 138").stepThis().dispose(); + version = 138; + } + + if (version == 138) { + database.executeFast("CREATE TABLE IF NOT EXISTS saved_reaction_tags (data BLOB);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 139").stepThis().dispose(); + version = 139; + } + return version; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java index f19eecc69..5b09b9333 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java @@ -452,8 +452,10 @@ public class Emoji { } else if (emojiCode.length() >= 2 && emojiCode.charAt(0) == 0xD83C && emojiCode.charAt(1) == 0xDFF4 && next == 0xDB40) { i++; while (true) { - emojiCode.append(cs.charAt(i)); - if (i + 1 >= cs.length()) { + if (i < cs.length()) { + emojiCode.append(cs.charAt(i)); + } + if (i + 1 < cs.length()) { emojiCode.append(cs.charAt(i + 1)); } startLength += 2; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 0ba4d9047..0fe68a6fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -1077,10 +1077,14 @@ public class FileLoader extends BaseController { } protected FileLoadOperation loadStreamFile(final FileLoadOperationStream stream, final TLRPC.Document document, final ImageLocation location, final Object parentObject, final long offset, final boolean priority, int loadingPriority) { + return loadStreamFile(stream, document, location, parentObject, offset, priority, loadingPriority, document == null ? 1 : 0); + } + + protected FileLoadOperation loadStreamFile(final FileLoadOperationStream stream, final TLRPC.Document document, final ImageLocation location, final Object parentObject, final long offset, final boolean priority, int loadingPriority, int cacheType) { final CountDownLatch semaphore = new CountDownLatch(1); final FileLoadOperation[] result = new FileLoadOperation[1]; fileLoaderQueue.postRunnable(() -> { - result[0] = loadFileInternal(document, null, null, document == null && location != null ? location.location : null, location, parentObject, document == null && location != null ? "mp4" : null, document == null && location != null ? location.currentSize : 0, loadingPriority, stream, offset, priority, document == null ? 1 : 0); + result[0] = loadFileInternal(document, null, null, document == null && location != null ? location.location : null, location, parentObject, document == null && location != null ? "mp4" : null, document == null && location != null ? location.currentSize : 0, loadingPriority, stream, offset, priority, cacheType); semaphore.countDown(); }); awaitFileLoadOperation(semaphore, true); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index 32682a310..63cd043c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -1081,13 +1081,13 @@ public class FileRefController extends BaseController { TL_stories.StoryItem storyItem = stories.stories.get(0); if (storyItem.media != null) { newStoryItem = storyItem; - if (storyItem.media.photo != null) { + if (result == null && storyItem.media.photo != null) { result = getFileReference(storyItem.media.photo, requester.location, needReplacement, locationReplacement); } - if (storyItem.media.document != null) { + if (result == null && storyItem.media.document != null) { result = getFileReference(storyItem.media.document, requester.location, needReplacement, locationReplacement); } - if (storyItem.media.alt_document != null) { + if (result == null && storyItem.media.alt_document != null) { result = getFileReference(storyItem.media.alt_document, requester.location, needReplacement, locationReplacement); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 653409b0b..04c2b17c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -1115,7 +1115,12 @@ public class ImageLoader { } } boolean createDecoder = fistFrame || (cacheImage.filter != null && ("d".equals(cacheImage.filter) || cacheImage.filter.contains("_d"))); - fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, createDecoder, 0, cacheImage.priority, notCreateStream ? null : cacheImage.imageLocation.document, null, null, seekTo, cacheImage.currentAccount, false, w, h, cacheOptions); + TLRPC.Document document = notCreateStream ? null : cacheImage.imageLocation.document; + int cacheType = document != null ? 1 : 0; + if (cacheImage.cacheType > 1) { + cacheType = cacheImage.cacheType; + } + fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, createDecoder, 0, cacheImage.priority, notCreateStream ? null : cacheImage.imageLocation.document, null, null, seekTo, cacheImage.currentAccount, false, w, h, cacheOptions, cacheType); fileDrawable.setIsWebmSticker(MessageObject.isWebM(cacheImage.imageLocation.document) || MessageObject.isVideoSticker(cacheImage.imageLocation.document) || isAnimatedAvatar(cacheImage.filter)); } if (fistFrame) { @@ -1229,7 +1234,9 @@ public class ImageLoader { w_filter = Float.parseFloat(args[0]) * AndroidUtilities.density; h_filter = Float.parseFloat(args[1]) * AndroidUtilities.density; } - if (cacheImage.filter.contains("b2")) { + if (cacheImage.filter.contains("b2r")) { + blurType = 4; + } else if (cacheImage.filter.contains("b2")) { blurType = 3; } else if (cacheImage.filter.contains("b1")) { blurType = 2; @@ -1430,8 +1437,23 @@ public class ImageLoader { if (image.getConfig() == Bitmap.Config.ARGB_8888) { Utilities.blurBitmap(image, 1, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); } - } else if (blurType == 3) { + } else if (blurType == 3 || blurType == 4) { if (image.getConfig() == Bitmap.Config.ARGB_8888) { + if (blurType == 4) { + Bitmap nbitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), image.getConfig()); + Canvas canvas = new Canvas(nbitmap); + canvas.save(); + final float s = 1.2f; + canvas.scale(s, s, image.getWidth() / 2f, image.getHeight() / 2f); + canvas.drawBitmap(image, 0, 0, null); + canvas.restore(); + android.graphics.Path path = new android.graphics.Path(); + path.addCircle(image.getWidth() / 2f, image.getHeight() / 2f, Math.min(image.getWidth(), image.getHeight()) / 2f, android.graphics.Path.Direction.CW); + canvas.clipPath(path); + canvas.drawBitmap(image, 0, 0, null); + image.recycle(); + image = nbitmap; + } Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); @@ -1829,8 +1851,24 @@ public class ImageLoader { data[166] = photoBytes[2]; BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = SharedConfig.deviceIsHigh() ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; + final boolean isRound = !TextUtils.isEmpty(filter) && filter.contains("r"); + options.inPreferredConfig = SharedConfig.deviceIsHigh() || isRound ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, len, options); + if (isRound) { + Bitmap nbitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); + Canvas canvas = new Canvas(nbitmap); + canvas.save(); + final float s = 1.2f; + canvas.scale(s, s, bitmap.getWidth() / 2f, bitmap.getHeight() / 2f); + canvas.drawBitmap(bitmap, 0, 0, null); + canvas.restore(); + android.graphics.Path path = new android.graphics.Path(); + path.addCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2f, android.graphics.Path.Direction.CW); + canvas.clipPath(path); + canvas.drawBitmap(bitmap, 0, 0, null); + bitmap.recycle(); + bitmap = nbitmap; + } if (bitmap != null && !TextUtils.isEmpty(filter) && filter.contains("b")) { Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); } @@ -1852,6 +1890,7 @@ public class ImageLoader { protected long size; protected int imageType; protected int type; + protected int cacheType; protected int currentAccount; @@ -2274,6 +2313,7 @@ public class ImageLoader { cacheImage.cacheTask = new CacheOutTask(cacheImage); cacheImage.filter = filter; cacheImage.imageType = img.imageType; + cacheImage.cacheType = img.cacheType; imageLoadingByKeys.put(key, cacheImage); tasks.add(cacheImage.cacheTask); } @@ -3212,6 +3252,7 @@ public class ImageLoader { img.type = type; img.key = key; + img.cacheType = cacheType; img.filter = filter; img.imageLocation = imageLocation; img.ext = ext; @@ -3727,6 +3768,7 @@ public class ImageLoader { cacheImage.parentObject = img.parentObject; cacheImage.isPFrame = img.isPFrame; cacheImage.key = key; + cacheImage.cacheType = img.cacheType; cacheImage.imageLocation = img.imageLocation; cacheImage.type = type; cacheImage.ext = img.ext; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 50c45f8c0..e5529442f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -2212,11 +2212,11 @@ public class LocaleController { public static String formatUserStatus(int currentAccount, TLRPC.User user, boolean[] isOnline, boolean[] madeShorter) { if (user != null && user.status != null && user.status.expires == 0) { if (user.status instanceof TLRPC.TL_userStatusRecently) { - user.status.expires = -100; + user.status.expires = user.status.by_me ? -1000 : -100; } else if (user.status instanceof TLRPC.TL_userStatusLastWeek) { - user.status.expires = -101; + user.status.expires = user.status.by_me ? -1001 : -101; } else if (user.status instanceof TLRPC.TL_userStatusLastMonth) { - user.status.expires = -102; + user.status.expires = user.status.by_me ? -1002 : -102; } } if (user != null && user.status != null && user.status.expires <= 0) { @@ -2239,11 +2239,11 @@ public class LocaleController { } else { if (user.status.expires == -1) { return getString("Invisible", R.string.Invisible); - } else if (user.status.expires == -100) { + } else if (user.status.expires == -100 || user.status.expires == -1000) { return getString("Lately", R.string.Lately); - } else if (user.status.expires == -101) { + } else if (user.status.expires == -101 || user.status.expires == -1001) { return getString("WithinAWeek", R.string.WithinAWeek); - } else if (user.status.expires == -102) { + } else if (user.status.expires == -102 || user.status.expires == -1002) { return getString("WithinAMonth", R.string.WithinAMonth); } else { return formatDateOnline(user.status.expires, madeShorter); @@ -2616,7 +2616,7 @@ public class LocaleController { } if (translitChars == null) { - translitChars = new HashMap<>(487); + translitChars = new HashMap<>(488); translitChars.put("ȼ", "c"); translitChars.put("ᶇ", "n"); translitChars.put("ɖ", "d"); @@ -3103,6 +3103,8 @@ public class LocaleController { translitChars.put("ő", "o"); translitChars.put("ꜩ", "tz"); translitChars.put("ẻ", "e"); + translitChars.put("і", "i"); + translitChars.put("ї", "i"); } StringBuilder dst = new StringBuilder(src.length()); int len = src.length(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 5911e3704..6bf995be4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -54,6 +54,7 @@ import android.provider.OpenableColumns; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.HapticFeedbackConstants; @@ -121,8 +122,6 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, public native byte[] getWaveform2(short[] array, int length); - public static native byte[] getMp3Waveform(String path, int samplesCount); - public boolean isBuffering() { if (audioPlayer != null) { return audioPlayer.isBuffering(); @@ -754,6 +753,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } }; + private boolean audioRecorderPaused; private AudioRecord audioRecorder; private TLRPC.TL_document recordingAudio; private int recordingGuid = -1; @@ -867,7 +867,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordProgressChanged, recordingGuid, amplitude)); } else { recordBuffers.add(buffer); - if (sendAfterDone != 3) { + if (sendAfterDone != 3 && sendAfterDone != 4) { stopRecordingInternal(sendAfterDone, sendAfterDoneNotify, sendAfterDoneScheduleDate, sendAfterDoneOnce); } } @@ -1860,16 +1860,16 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } if (proximityTouched && wakelockAllowed) { - if (allowRecording && recordStartRunnable == null && recordingAudio == null) { + if (allowRecording && recordStartRunnable == null) { if (!raiseToEarRecord) { if (BuildVars.LOGS_ENABLED) { FileLog.d("start record"); } useFrontSpeaker = true; - if (!raiseChat.playFirstUnreadVoiceMessage()) { + if (recordingAudio != null || !raiseChat.playFirstUnreadVoiceMessage()) { raiseToEarRecord = true; useFrontSpeaker = false; - startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false); + raiseToSpeakUpdated(true); } if (useFrontSpeaker) { setUseFrontSpeaker(true); @@ -1915,7 +1915,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (BuildVars.LOGS_ENABLED) { FileLog.d("stop record"); } - stopRecording(2, false, 0, false); + raiseToSpeakUpdated(false); raiseToEarRecord = false; ignoreOnPause = false; // if (!ignoreAccelerometerGestures() && proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { @@ -1942,6 +1942,16 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } + private void raiseToSpeakUpdated(boolean raised) { + if (recordingAudio != null) { + toggleRecordingPause(); + } else if (raised) { + startRecording(raiseChat.getCurrentAccount(), raiseChat.getDialogId(), null, raiseChat.getThreadMessage(), null, raiseChat.getClassGuid(), false); + } else { + stopRecording(2, false, 0, false); + } + } + private void setUseFrontSpeaker(boolean value) { useFrontSpeaker = value; AudioManager audioManager = NotificationsController.audioManager; @@ -2633,7 +2643,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, final File cacheFile = file != null ? file : FileLoader.getInstance(currentAccount).getPathToMessage(nextAudio.messageOwner); boolean exist = cacheFile.exists(); if (cacheFile != file && !cacheFile.exists()) { - FileLoader.getInstance(currentAccount).loadFile(nextAudio.getDocument(), nextAudio, FileLoader.PRIORITY_LOW, 0); + FileLoader.getInstance(currentAccount).loadFile(nextAudio.getDocument(), nextAudio, FileLoader.PRIORITY_LOW, nextAudio.shouldEncryptPhotoOrVideo() ? 2 : 0); } } @@ -2672,7 +2682,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, final File cacheFile = file != null ? file : FileLoader.getInstance(currentAccount).getPathToMessage(nextAudio.messageOwner); boolean exist = cacheFile.exists(); if (cacheFile != file && !cacheFile.exists() && nextAudio.isMusic()) { - FileLoader.getInstance(currentAccount).loadFile(nextAudio.getDocument(), nextAudio, FileLoader.PRIORITY_LOW, 0); + FileLoader.getInstance(currentAccount).loadFile(nextAudio.getDocument(), nextAudio, FileLoader.PRIORITY_LOW, nextAudio.shouldEncryptPhotoOrVideo() ? 2 : 0); } } @@ -3210,9 +3220,9 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } final File cacheFile = file != null ? file : FileLoader.getInstance(messageObject.currentAccount).getPathToMessage(messageObject.messageOwner); - boolean canStream = SharedConfig.streamMedia && (messageObject.isMusic() || messageObject.isRoundVideo() || messageObject.isVideo() && messageObject.canStreamVideo()) && !DialogObject.isEncryptedDialog(messageObject.getDialogId()); + boolean canStream = SharedConfig.streamMedia && (messageObject.isMusic() || messageObject.isRoundVideo() || messageObject.isVideo() && messageObject.canStreamVideo()) && !messageObject.shouldEncryptPhotoOrVideo() && !DialogObject.isEncryptedDialog(messageObject.getDialogId()); if (cacheFile != file && !(exists = cacheFile.exists()) && !canStream) { - FileLoader.getInstance(messageObject.currentAccount).loadFile(messageObject.getDocument(), messageObject, FileLoader.PRIORITY_LOW, 0); + FileLoader.getInstance(messageObject.currentAccount).loadFile(messageObject.getDocument(), messageObject, FileLoader.PRIORITY_LOW, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); downloadingCurrentMessage = true; isPaused = false; lastProgress = 0; @@ -3814,6 +3824,55 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } + public void toggleRecordingPause() { + recordQueue.postRunnable(() -> { + if (recordingAudio == null || recordingAudioFile == null) { + return; + } + audioRecorderPaused = !audioRecorderPaused; + final boolean isPaused = audioRecorderPaused; + if (isPaused) { + sendAfterDone = 4; + audioRecorder.stop(); + audioRecorder.release(); + audioRecorder = null; + + final TLRPC.TL_document audioToSend = recordingAudio; + final File recordingAudioFileToSend = recordingAudioFile; + AndroidUtilities.runOnUIThread(() -> { + boolean fileExist = recordingAudioFileToSend.exists(); + if (!fileExist && BuildVars.DEBUG_VERSION) { + FileLog.e(new RuntimeException("file not found :( recordTimeCount " + recordTimeCount + " writedFrames" + writedFrame)); + } + audioToSend.date = ConnectionsManager.getInstance(recordingCurrentAccount).getCurrentTime(); + audioToSend.size = (int) recordingAudioFileToSend.length(); + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.voice = true; + attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); + if (attributeAudio.waveform != null) { + attributeAudio.flags |= 4; + } + attributeAudio.duration = recordTimeCount / 1000.0; + audioToSend.attributes.clear(); + audioToSend.attributes.add(attributeAudio); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordPaused); + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, audioToSend, recordingAudioFileToSend.getAbsolutePath()); + }); + } else { + recordQueue.cancelRunnable(recordRunnable); + audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize); + recordStartTime = System.currentTimeMillis(); + fileBuffer.rewind(); + audioRecorder.startRecording(); + recordQueue.postRunnable(recordRunnable); + + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.recordResumed); + }); + } + }); + } + public void startRecording(int currentAccount, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, TL_stories.StoryItem replyStory, int guid, boolean manual) { boolean paused = false; if (playingMessageObject != null && isPlayingMessage(playingMessageObject) && !isMessagePaused()) { @@ -3877,6 +3936,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, return; } + audioRecorderPaused = false; audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize); recordStartTime = System.currentTimeMillis(); recordTimeCount = 0; @@ -3951,7 +4011,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); messagesRes.messages.add(messageObject1.messageOwner); - MessagesStorage.getInstance(messageObject1.currentAccount).putMessages(messagesRes, messageObject1.getDialogId(), -1, 0, false, messageObject.scheduled, 0); + MessagesStorage.getInstance(messageObject1.currentAccount).putMessages(messagesRes, messageObject1.getDialogId(), -1, 0, false, messageObject.scheduled ? 1 : 0, 0); ArrayList arrayList = new ArrayList<>(); arrayList.add(messageObject1); NotificationCenter.getInstance(messageObject1.currentAccount).postNotificationName(NotificationCenter.replaceMessagesObjects, messageObject1.getDialogId(), arrayList); @@ -3989,7 +4049,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, attributeAudio.flags |= 4; } long duration = recordTimeCount; - attributeAudio.duration = (int) (recordTimeCount / 1000); + attributeAudio.duration = recordTimeCount / 1000.0; + audioToSend.attributes.clear(); audioToSend.attributes.add(attributeAudio); if (duration > 700) { if (send == 1) { @@ -4024,6 +4085,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, recordingAudio = null; recordingAudioFile = null; manualRecording = false; + raiseToEarRecord = false; + ignoreOnPause = false; } public void stopRecording(final int send, boolean notify, int scheduleDate, boolean once) { @@ -4038,6 +4101,10 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, return; } if (audioRecorder == null) { + recordingAudio = null; + manualRecording = false; + raiseToEarRecord = false; + ignoreOnPause = false; return; } try { @@ -4236,7 +4303,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } String fileName = FileLoader.getAttachFileName(document); loadingMessageObjects.put(fileName, messageObject); - currentAccount.getFileLoader().loadFile(document, messageObject, FileLoader.PRIORITY_LOW, 0); + currentAccount.getFileLoader().loadFile(document, messageObject, FileLoader.PRIORITY_LOW, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 7b597bcab..0db5b6b0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -34,7 +34,6 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.URLSpan; import android.text.util.Linkify; -import android.util.Log; import android.util.Pair; import android.util.SparseArray; @@ -68,6 +67,7 @@ import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.ChatThemeBottomSheet; import org.telegram.ui.Components.QuoteSpan; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.StickerSetBulletinLayout; import org.telegram.ui.Components.StickersArchiveAlert; import org.telegram.ui.Components.TextStyleSpan; @@ -157,9 +157,9 @@ public class MediaDataController extends BaseController { TLRPC.Message message = TLRPC.Message.TLdeserialize(serializedData, serializedData.readInt32(true), true); if (message != null) { message.readAttachPath(serializedData, getUserConfig().clientUserId); - SparseArray threads = draftMessages.get(did); + LongSparseArray threads = draftMessages.get(did); if (threads == null) { - threads = new SparseArray<>(); + threads = new LongSparseArray<>(); draftMessages.put(did, threads); } int threadId = isThread ? Utilities.parseInt(key.substring(key.lastIndexOf('_') + 1)) : 0; @@ -171,12 +171,12 @@ public class MediaDataController extends BaseController { } else { TLRPC.DraftMessage draftMessage = TLRPC.DraftMessage.TLdeserialize(serializedData, serializedData.readInt32(true), true); if (draftMessage != null) { - SparseArray threads = drafts.get(did); + LongSparseArray threads = drafts.get(did); if (threads == null) { - threads = new SparseArray<>(); + threads = new LongSparseArray<>(); drafts.put(did, threads); } - int threadId = key.startsWith("t_") ? Utilities.parseInt(key.substring(key.lastIndexOf('_') + 1)) : 0; + long threadId = key.startsWith("t_") ? Utilities.parseInt(key.substring(key.lastIndexOf('_') + 1)) : 0; threads.put(threadId, draftMessage); } } @@ -2189,9 +2189,9 @@ public class MediaDataController extends BaseController { } public static long calcHash(long hash, long id) { - hash ^= hash >> 21; + hash ^= hash >>> 21; hash ^= hash << 35; - hash ^= hash >> 4; + hash ^= hash >>> 4; return hash + id; } @@ -3337,8 +3337,9 @@ public class MediaDataController extends BaseController { private int reqId; private int mergeReqId; private long lastMergeDialogId; - private int lastReplyMessageId; + private long lastReplyMessageId; private long lastDialogId; + private ReactionsLayoutInBubble.VisibleReaction lastReaction; private int lastReqId; private int lastGuid; private TLRPC.User lastSearchUser; @@ -3374,8 +3375,8 @@ public class MediaDataController extends BaseController { return searchResultMessagesMap[mergeDialog ? 1 : 0].indexOfKey(messageId) >= 0; } - public void searchMessagesInChat(String query, long dialogId, long mergeDialogId, int guid, int direction, int replyMessageId, TLRPC.User user, TLRPC.Chat chat) { - searchMessagesInChat(query, dialogId, mergeDialogId, guid, direction, replyMessageId, false, user, chat, true); + public void searchMessagesInChat(String query, long dialogId, long mergeDialogId, int guid, int direction, long replyMessageId, TLRPC.User user, TLRPC.Chat chat, ReactionsLayoutInBubble.VisibleReaction reaction) { + searchMessagesInChat(query, dialogId, mergeDialogId, guid, direction, replyMessageId, false, user, chat, true, reaction); } public void jumpToSearchedMessage(int guid, int index) { @@ -3387,18 +3388,22 @@ public class MediaDataController extends BaseController { getNotificationCenter().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId(), lastReturnedNum, messagesSearchCount[0] + messagesSearchCount[1], true); } + public boolean searchEndReached() { + return messagesSearchEndReached[0] && lastMergeDialogId == 0 && messagesSearchEndReached[1]; + } + public void loadMoreSearchMessages() { if (loadingMoreSearchMessages || messagesSearchEndReached[0] && lastMergeDialogId == 0 && messagesSearchEndReached[1]) { return; } int temp = searchResultMessages.size(); lastReturnedNum = searchResultMessages.size(); - searchMessagesInChat(null, lastDialogId, lastMergeDialogId, lastGuid, 1, lastReplyMessageId, false, lastSearchUser, lastSearchChat, false); + searchMessagesInChat(null, lastDialogId, lastMergeDialogId, lastGuid, 1, lastReplyMessageId, false, lastSearchUser, lastSearchChat, false, lastReaction); lastReturnedNum = temp; loadingMoreSearchMessages = true; } - private void searchMessagesInChat(String query, long dialogId, long mergeDialogId, int guid, int direction, int replyMessageId, boolean internal, TLRPC.User user, TLRPC.Chat chat, boolean jumpToMessage) { + private void searchMessagesInChat(String query, long dialogId, long mergeDialogId, int guid, int direction, long replyMessageId, boolean internal, TLRPC.User user, TLRPC.Chat chat, boolean jumpToMessage, ReactionsLayoutInBubble.VisibleReaction reaction) { int max_id = 0; long queryWithDialog = dialogId; boolean firstQuery = !internal; @@ -3484,8 +3489,17 @@ public class MediaDataController extends BaseController { req.flags |= 1; } if (replyMessageId != 0) { - req.top_msg_id = replyMessageId; - req.flags |= 2; + if (dialogId == getUserConfig().getClientUserId()) { + req.saved_peer_id = getMessagesController().getInputPeer(replyMessageId); + req.flags |= 4; + } else { + req.top_msg_id = (int) replyMessageId; + req.flags |= 2; + } + } + if (reaction != null) { + req.saved_reaction.add(reaction.toTLReaction()); + req.flags |= 8; } req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); mergeReqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { @@ -3495,11 +3509,11 @@ public class MediaDataController extends BaseController { TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; messagesSearchEndReached[1] = res.messages.isEmpty(); messagesSearchCount[1] = res instanceof TLRPC.TL_messages_messagesSlice ? res.count : res.messages.size(); - searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, chat, jumpToMessage); + searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, chat, jumpToMessage, reaction); } else { messagesSearchEndReached[1] = true; messagesSearchCount[1] = 0; - searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, chat, jumpToMessage); + searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, chat, jumpToMessage, reaction); } } }), ConnectionsManager.RequestFlagFailOnServerErrors); @@ -3520,6 +3534,7 @@ public class MediaDataController extends BaseController { lastSearchUser = user; lastSearchChat = chat; lastReplyMessageId = replyMessageId; + lastReaction = reaction; req.limit = 21; req.q = query != null ? query : ""; req.offset_id = max_id; @@ -3531,8 +3546,17 @@ public class MediaDataController extends BaseController { req.flags |= 1; } if (lastReplyMessageId != 0) { - req.top_msg_id = lastReplyMessageId; - req.flags |= 2; + if (queryWithDialog == getUserConfig().getClientUserId()) { + req.saved_peer_id = getMessagesController().getInputPeer(lastReplyMessageId); + req.flags |= 4; + } else { + req.top_msg_id = (int) lastReplyMessageId; + req.flags |= 2; + } + } + if (reaction != null) { + req.saved_reaction.add(reaction.toTLReaction()); + req.flags |= 8; } req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); int currentReqId = ++lastReqId; @@ -3587,7 +3611,7 @@ public class MediaDataController extends BaseController { searchResultMessages.add(messageObject); searchResultMessagesMap[queryWithDialogFinal == dialogId ? 0 : 1].put(messageObject.getId(), messageObject); } - messagesSearchEndReached[queryWithDialogFinal == dialogId ? 0 : 1] = res.messages.size() < 21; + messagesSearchEndReached[queryWithDialogFinal == dialogId ? 0 : 1] = res.messages.size() < req.limit; messagesSearchCount[queryWithDialogFinal == dialogId ? 0 : 1] = res instanceof TLRPC.TL_messages_messagesSlice || res instanceof TLRPC.TL_messages_channelMessages ? res.count : res.messages.size(); if (searchResultMessages.isEmpty()) { getNotificationCenter().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, 0, getMask(), (long) 0, 0, 0, jumpToMessage); @@ -3601,7 +3625,7 @@ public class MediaDataController extends BaseController { } } if (queryWithDialogFinal == dialogId && messagesSearchEndReached[0] && mergeDialogId != 0 && !messagesSearchEndReached[1]) { - searchMessagesInChat(lastSearchQuery, dialogId, mergeDialogId, guid, 0, replyMessageId, true, user, chat, jumpToMessage); + searchMessagesInChat(lastSearchQuery, dialogId, mergeDialogId, guid, 0, replyMessageId, true, user, chat, jumpToMessage, lastReaction); } } } @@ -3627,7 +3651,7 @@ public class MediaDataController extends BaseController { public final static int MEDIA_STORIES = 8; - public void loadMedia(long dialogId, int count, int max_id, int min_id, int type, int topicId, int fromCache, int classGuid, int requestIndex) { + public void loadMedia(long dialogId, int count, int max_id, int min_id, int type, long topicId, int fromCache, int classGuid, int requestIndex) { boolean isChannel = DialogObject.isChatDialog(dialogId) && ChatObject.isChannel(-dialogId, currentAccount); if (BuildVars.LOGS_ENABLED) { @@ -3665,8 +3689,13 @@ public class MediaDataController extends BaseController { req.q = ""; req.peer = getMessagesController().getInputPeer(dialogId); if (topicId != 0) { - req.top_msg_id = topicId; - req.flags |= 2; + if (dialogId == getUserConfig().getClientUserId()) { + req.saved_peer_id = getMessagesController().getInputPeer(topicId); + req.flags |= 4; + } else { + req.top_msg_id = (int) topicId; + req.flags |= 2; + } } if (req.peer == null) { return; @@ -3689,7 +3718,7 @@ public class MediaDataController extends BaseController { } } - public void getMediaCounts(long dialogId, int topicId, int classGuid) { + public void getMediaCounts(long dialogId, long topicId, int classGuid) { getMessagesStorage().getStorageQueue().postRunnable(() -> { try { int[] counts = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1}; @@ -3728,8 +3757,13 @@ public class MediaDataController extends BaseController { TLRPC.TL_messages_getSearchCounters req = new TLRPC.TL_messages_getSearchCounters(); req.peer = getMessagesController().getInputPeer(dialogId); if (topicId != 0) { - req.top_msg_id = topicId; - req.flags |= 1; + if (dialogId == getUserConfig().getClientUserId()) { + req.saved_peer_id = getMessagesController().getInputPeer(topicId); + req.flags |= 4; + } else { + req.top_msg_id = (int) topicId; + req.flags |= 1; + } } for (int a = 0; a < counts.length; a++) { if (req.peer == null) { @@ -3810,7 +3844,7 @@ public class MediaDataController extends BaseController { }); } - public void getMediaCount(long dialogId, int topicId, int type, int classGuid, boolean fromCache) { + public void getMediaCount(long dialogId, long topicId, int type, int classGuid, boolean fromCache) { if (fromCache || DialogObject.isEncryptedDialog(dialogId)) { getMediaCountDatabase(dialogId, topicId, type, classGuid); } else { @@ -3829,8 +3863,13 @@ public class MediaDataController extends BaseController { req.filters.add(new TLRPC.TL_inputMessagesFilterGif()); } if (topicId != 0) { - req.top_msg_id = topicId; - req.flags |= 1; + if (dialogId == getUserConfig().getClientUserId()) { + req.saved_peer_id = getMessagesController().getInputPeer(dialogId); + req.flags |= 4; + } else { + req.top_msg_id = (int) topicId; + req.flags |= 1; + } } req.peer = getMessagesController().getInputPeer(dialogId); if (req.peer == null) { @@ -3916,7 +3955,7 @@ public class MediaDataController extends BaseController { } } - private void processLoadedMedia(TLRPC.messages_Messages res, long dialogId, int count, int max_id, int min_id, int type, int topicId, int fromCache, int classGuid, boolean isChannel, boolean topReached, int requestIndex) { + private void processLoadedMedia(TLRPC.messages_Messages res, long dialogId, int count, int max_id, int min_id, int type, long topicId, int fromCache, int classGuid, boolean isChannel, boolean topReached, int requestIndex) { if (BuildVars.LOGS_ENABLED) { int messagesCount = 0; if (res != null && res.messages != null) { @@ -3978,7 +4017,7 @@ public class MediaDataController extends BaseController { } } - private void processLoadedMediaCount(int count, long dialogId, int topicId, int type, int classGuid, boolean fromCache, int old) { + private void processLoadedMediaCount(int count, long dialogId, long topicId, int type, int classGuid, boolean fromCache, int old) { AndroidUtilities.runOnUIThread(() -> { boolean isEncryptedDialog = DialogObject.isEncryptedDialog(dialogId); boolean reload = fromCache && (count == -1 || count == 0 && type == 2) && !isEncryptedDialog; @@ -3994,7 +4033,7 @@ public class MediaDataController extends BaseController { }); } - private void putMediaCountDatabase(long uid, int topicId, int type, int count) { + private void putMediaCountDatabase(long uid, long topicId, int type, int count) { getMessagesStorage().getStorageQueue().postRunnable(() -> { try { SQLitePreparedStatement state2; @@ -4007,7 +4046,7 @@ public class MediaDataController extends BaseController { state2.requery(); state2.bindLong(pointer++, uid); if (topicId != 0) { - state2.bindInteger(pointer++, topicId); + state2.bindLong(pointer++, topicId); } state2.bindInteger(pointer++, type); state2.bindInteger(pointer++, count); @@ -4020,7 +4059,7 @@ public class MediaDataController extends BaseController { }); } - private void getMediaCountDatabase(long dialogId, int topicId, int type, int classGuid) { + private void getMediaCountDatabase(long dialogId, long topicId, int type, int classGuid) { getMessagesStorage().getStorageQueue().postRunnable(() -> { try { int count = -1; @@ -4054,7 +4093,7 @@ public class MediaDataController extends BaseController { }); } - private void loadMediaDatabase(long uid, int count, int max_id, int min_id, int type, int topicId, int classGuid, boolean isChannel, int fromCache, int requestIndex) { + private void loadMediaDatabase(long uid, int count, int max_id, int min_id, int type, long topicId, int classGuid, boolean isChannel, int fromCache, int requestIndex) { Runnable runnable = new Runnable() { @Override public void run() { @@ -4099,7 +4138,7 @@ public class MediaDataController extends BaseController { state.requery(); state.bindLong(pointer++, uid); if (topicId != 0) { - state.bindInteger(pointer++, topicId); + state.bindLong(pointer++, topicId); } state.bindInteger(pointer++, type); state.bindInteger(pointer++, 0); @@ -4269,7 +4308,7 @@ public class MediaDataController extends BaseController { messagesStorage.bindTaskToGuid(runnable, classGuid); } - private void putMediaDatabase(long uid, int topicId, int type, ArrayList messages, int max_id, int min_id, boolean topReached) { + private void putMediaDatabase(long uid, long topicId, int type, ArrayList messages, int max_id, int min_id, boolean topReached) { getMessagesStorage().getStorageQueue().postRunnable(() -> { try { if (min_id == 0 && (messages.isEmpty() || topReached)) { @@ -4296,7 +4335,7 @@ public class MediaDataController extends BaseController { state2.bindInteger(pointer++, message.id); state2.bindLong(pointer++, uid); if (topicId != 0) { - state2.bindInteger(pointer++, topicId); + state2.bindLong(pointer++, topicId); } state2.bindInteger(pointer++, message.date); state2.bindInteger(pointer++, type); @@ -5429,7 +5468,7 @@ public class MediaDataController extends BaseController { } } - public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, boolean scheduled, int threadMessageId, Runnable callback, int classGuid) { + public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, boolean scheduled, long threadMessageId, Runnable callback, int classGuid) { if (DialogObject.isEncryptedDialog(dialogId)) { ArrayList replyMessages = new ArrayList<>(); LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); @@ -5573,7 +5612,7 @@ public class MediaDataController extends BaseController { } } - if (channelId != 0 && messageObject.getDialogId() != -channelId) { + if (dialogId != UserObject.REPLY_BOT && channelId != 0 && messageObject.getDialogId() != -channelId) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(channelId); if (chat != null && !ChatObject.isPublic(chat)) { continue; @@ -6591,8 +6630,8 @@ public class MediaDataController extends BaseController { //---------------- MESSAGES END ---------------- private LongSparseArray draftsFolderIds = new LongSparseArray<>(); - private LongSparseArray> drafts = new LongSparseArray<>(); - private LongSparseArray> draftMessages = new LongSparseArray<>(); + private LongSparseArray> drafts = new LongSparseArray<>(); + private LongSparseArray> draftMessages = new LongSparseArray<>(); private boolean inTransaction; private SharedPreferences draftPreferences; private boolean loadingDrafts; @@ -6629,28 +6668,28 @@ public class MediaDataController extends BaseController { draftsFolderIds.clear(); } - public LongSparseArray> getDrafts() { + public LongSparseArray> getDrafts() { return drafts; } - public TLRPC.DraftMessage getDraft(long dialogId, int threadId) { - SparseArray threads = drafts.get(dialogId); + public TLRPC.DraftMessage getDraft(long dialogId, long threadId) { + LongSparseArray threads = drafts.get(dialogId); if (threads == null) { return null; } return threads.get(threadId); } - public Pair getOneThreadDraft(long dialogId) { - SparseArray threads = drafts.get(dialogId); + public Pair getOneThreadDraft(long dialogId) { + LongSparseArray threads = drafts.get(dialogId); if (threads == null || threads.size() <= 0) { return null; } return new Pair(threads.keyAt(0), threads.valueAt(0)); } - public TLRPC.Message getDraftMessage(long dialogId, int threadId) { - SparseArray threads = draftMessages.get(dialogId); + public TLRPC.Message getDraftMessage(long dialogId, long threadId) { + LongSparseArray threads = draftMessages.get(dialogId); if (threads == null) { return null; } @@ -6661,7 +6700,7 @@ public class MediaDataController extends BaseController { saveDraft(dialogId, threadId, message, entities, replyToMessage, null, noWebpage, false); } - public void saveDraft(long dialogId, int threadId, CharSequence message, ArrayList entities, TLRPC.Message replyToMessage, ChatActivity.ReplyQuote quote, boolean noWebpage, boolean clean) { + public void saveDraft(long dialogId, long threadId, CharSequence message, ArrayList entities, TLRPC.Message replyToMessage, ChatActivity.ReplyQuote quote, boolean noWebpage, boolean clean) { TLRPC.DraftMessage draftMessage; if (getMessagesController().isForum(dialogId) && threadId == 0) { replyToMessage = null; @@ -6708,7 +6747,7 @@ public class MediaDataController extends BaseController { draftMessage.flags |= 8; } - SparseArray threads = drafts.get(dialogId); + LongSparseArray threads = drafts.get(dialogId); TLRPC.DraftMessage currentDraft = threads == null ? null : threads.get(threadId); if (!clean) { boolean sameDraft; @@ -6811,7 +6850,7 @@ public class MediaDataController extends BaseController { return null; } - public void saveDraft(long dialogId, int threadId, TLRPC.DraftMessage draft, TLRPC.Message replyToMessage, boolean fromServer) { + public void saveDraft(long dialogId, long threadId, TLRPC.DraftMessage draft, TLRPC.Message replyToMessage, boolean fromServer) { if (getMessagesController().isForum(dialogId) && threadId == 0 && TextUtils.isEmpty(draft.message)) { if (draft.reply_to instanceof TLRPC.TL_inputReplyToMessage) { ((TLRPC.TL_inputReplyToMessage) draft.reply_to).reply_to_msg_id = 0; @@ -6821,7 +6860,7 @@ public class MediaDataController extends BaseController { MessagesController messagesController = getMessagesController(); if (draft == null || draft instanceof TLRPC.TL_draftMessageEmpty) { { - SparseArray threads = drafts.get(dialogId); + LongSparseArray threads = drafts.get(dialogId); if (threads != null) { threads.remove(threadId); if (threads.size() == 0) { @@ -6830,7 +6869,7 @@ public class MediaDataController extends BaseController { } } { - SparseArray threads = draftMessages.get(dialogId); + LongSparseArray threads = draftMessages.get(dialogId); if (threads != null) { threads.remove(threadId); if (threads.size() == 0) { @@ -6845,9 +6884,9 @@ public class MediaDataController extends BaseController { } messagesController.removeDraftDialogIfNeed(dialogId); } else { - SparseArray threads = drafts.get(dialogId); + LongSparseArray threads = drafts.get(dialogId); if (threads == null) { - threads = new SparseArray<>(); + threads = new LongSparseArray<>(); drafts.put(dialogId, threads); } threads.put(threadId, draft); @@ -6863,7 +6902,7 @@ public class MediaDataController extends BaseController { FileLog.e(e); } } - SparseArray threads = draftMessages.get(dialogId); + LongSparseArray threads = draftMessages.get(dialogId); if (replyToMessage == null && draft != null && draft.reply_to != null) { if (threads != null) { replyToMessage = threads.get(threadId); @@ -6888,7 +6927,7 @@ public class MediaDataController extends BaseController { } } else { if (threads == null) { - threads = new SparseArray<>(); + threads = new LongSparseArray<>(); draftMessages.put(dialogId, threads); } threads.put(threadId, replyToMessage); @@ -6991,17 +7030,17 @@ public class MediaDataController extends BaseController { } } - private void saveDraftReplyMessage(long dialogId, int threadId, TLRPC.Message message) { + private void saveDraftReplyMessage(long dialogId, long threadId, TLRPC.Message message) { if (message == null) { return; } AndroidUtilities.runOnUIThread(() -> { - SparseArray threads = drafts.get(dialogId); + LongSparseArray threads = drafts.get(dialogId); TLRPC.DraftMessage draftMessage = threads != null ? threads.get(threadId) : null; if (draftMessage != null && draftMessage.reply_to != null && draftMessage.reply_to.reply_to_msg_id == message.id) { - SparseArray threads2 = draftMessages.get(dialogId); + LongSparseArray threads2 = draftMessages.get(dialogId); if (threads2 == null) { - threads2 = new SparseArray<>(); + threads2 = new LongSparseArray<>(); draftMessages.put(dialogId, threads2); } threads2.put(threadId, message); @@ -7025,15 +7064,15 @@ public class MediaDataController extends BaseController { } } - public void cleanDraft(long dialogId, int threadId, boolean replyOnly) { - SparseArray threads2 = drafts.get(dialogId); + public void cleanDraft(long dialogId, long threadId, boolean replyOnly) { + LongSparseArray threads2 = drafts.get(dialogId); TLRPC.DraftMessage draftMessage = threads2 != null ? threads2.get(threadId) : null; if (draftMessage == null) { return; } if (!replyOnly) { { - SparseArray threads = drafts.get(dialogId); + LongSparseArray threads = drafts.get(dialogId); if (threads != null) { threads.remove(threadId); if (threads.size() == 0) { @@ -7042,7 +7081,7 @@ public class MediaDataController extends BaseController { } } { - SparseArray threads = draftMessages.get(dialogId); + LongSparseArray threads = draftMessages.get(dialogId); if (threads != null) { threads.remove(threadId); if (threads.size() == 0) { @@ -7120,7 +7159,7 @@ public class MediaDataController extends BaseController { if (dialogMessages != null) { for (int i = 0; i < dialogMessages.size(); ++i) { TLRPC.Message msg = dialogMessages.get(i); - int topicId = MessageObject.getTopicId(msg, ChatObject.isForum(currentAccount, dialogId)); + long topicId = MessageObject.getTopicId(currentAccount, msg, ChatObject.isForum(currentAccount, dialogId)); MessagesStorage.TopicKey topicKey = MessagesStorage.TopicKey.of(dialogId, topicId); botKeyboards.remove(topicKey); getNotificationCenter().postNotificationName(NotificationCenter.botKeyboardDidLoad, null, topicKey); @@ -7238,7 +7277,7 @@ public class MediaDataController extends BaseController { message.serializeToStream(data); if (topicKey.topicId != 0) { state.bindLong(1, topicKey.dialogId); - state.bindInteger(2, topicKey.topicId); + state.bindLong(2, topicKey.topicId); state.bindInteger(3, message.id); state.bindByteBuffer(4, data); } else { @@ -8343,7 +8382,9 @@ public class MediaDataController extends BaseController { ArrayList recentReactions = new ArrayList<>(); ArrayList topReactions = new ArrayList<>(); - boolean loadingRecentReactions; + ArrayList savedReactions = new ArrayList<>(); + boolean loadingRecentReactions, loadedRecentReactions; + boolean loadingSavedReactions, loadedSavedReactions; public ArrayList getRecentReactions() { return recentReactions; @@ -8367,7 +8408,7 @@ public class MediaDataController extends BaseController { } public void loadRecentAndTopReactions(boolean force) { - if (loadingRecentReactions || !recentReactions.isEmpty() || force) { + if (loadingRecentReactions || loadedRecentReactions && !force) { return; } SharedPreferences recentReactionsPref = ApplicationLoader.applicationContext.getSharedPreferences("recent_reactions_" + currentAccount, Context.MODE_PRIVATE); @@ -8378,14 +8419,17 @@ public class MediaDataController extends BaseController { recentReactions.addAll(loadReactionsFromPref(recentReactionsPref)); topReactions.addAll(loadReactionsFromPref(topReactionsPref)); loadingRecentReactions = true; + loadedRecentReactions = true; boolean loadFromServer = true; if (loadFromServer) { + boolean[] loaded = new boolean[2]; + TLRPC.TL_messages_getRecentReactions recentReactionsRequest = new TLRPC.TL_messages_getRecentReactions(); recentReactionsRequest.hash = recentReactionsPref.getLong("hash", 0); recentReactionsRequest.limit = 50; - ConnectionsManager.getInstance(currentAccount).sendRequest(recentReactionsRequest, (response, error) -> { + ConnectionsManager.getInstance(currentAccount).sendRequest(recentReactionsRequest, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { if (response instanceof TLRPC.TL_messages_reactions) { TLRPC.TL_messages_reactions reactions = (TLRPC.TL_messages_reactions) response; @@ -8398,12 +8442,17 @@ public class MediaDataController extends BaseController { } } - }); + + loaded[0] = true; + if (loaded[1]) { + loadingRecentReactions = false; + } + })); TLRPC.TL_messages_getTopReactions topReactionsRequest = new TLRPC.TL_messages_getTopReactions(); topReactionsRequest.hash = topReactionsPref.getLong("hash", 0); topReactionsRequest.limit = 100; - ConnectionsManager.getInstance(currentAccount).sendRequest(topReactionsRequest, (response, error) -> { + ConnectionsManager.getInstance(currentAccount).sendRequest(topReactionsRequest, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { if (response instanceof TLRPC.TL_messages_reactions) { TLRPC.TL_messages_reactions reactions = (TLRPC.TL_messages_reactions) response; @@ -8417,7 +8466,51 @@ public class MediaDataController extends BaseController { } } - }); + + loaded[1] = true; + if (loaded[0]) { + loadingRecentReactions = false; + } + })); + } + } + + public ArrayList getSavedReactions() { + return savedReactions; + } + public void loadSavedReactions(boolean force) { + if (loadingSavedReactions || loadedSavedReactions && !force) { + return; + } + SharedPreferences savedReactionsPref = ApplicationLoader.applicationContext.getSharedPreferences("saved_reactions_" + currentAccount, Context.MODE_PRIVATE); + + savedReactions.clear(); + savedReactions.addAll(loadReactionsFromPref(savedReactionsPref)); + loadingSavedReactions = true; + loadedSavedReactions = true; + + boolean loadFromServer = true; + if (loadFromServer) { + TLRPC.TL_messages_getDefaultTagReactions recentReactionsRequest = new TLRPC.TL_messages_getDefaultTagReactions(); + recentReactionsRequest.hash = savedReactionsPref.getLong("hash", 0); + ConnectionsManager.getInstance(currentAccount).sendRequest(recentReactionsRequest, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + if (response instanceof TLRPC.TL_messages_reactions) { + TLRPC.TL_messages_reactions reactions = (TLRPC.TL_messages_reactions) response; + savedReactions.clear(); + savedReactions.addAll(reactions.reactions); + + saveReactionsToPref(savedReactionsPref, reactions.hash, reactions.reactions); + + getNotificationCenter().postNotificationName(NotificationCenter.savedReactionTagsUpdate); + } + if (response instanceof TLRPC.TL_messages_reactionsNotModified) { + + } + } + + loadingSavedReactions = false; + })); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 5f4165cc8..b84d23fc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -33,6 +33,7 @@ import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.Base64; +import android.util.Log; import androidx.annotation.NonNull; import androidx.collection.LongSparseArray; @@ -57,6 +58,7 @@ import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.QuoteSpan; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.Reactions.ReactionsUtils; +import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TranscribeButton; @@ -236,6 +238,7 @@ public class MessageObject { public boolean cancelEditing; public boolean scheduled; + public boolean scheduledSent; public boolean preview; public boolean previewForward; @@ -311,6 +314,7 @@ public class MessageObject { public boolean isRepostVideoPreview; public boolean forceAvatar; public Drawable customAvatarDrawable; + public boolean isSaved; private byte[] randomWaveform; public boolean drawServiceWithDefaultTypeface; @@ -346,11 +350,23 @@ public class MessageObject { return false; } - private static int getTopicId(TLRPC.Message message) { - return getTopicId(message, false); + private static long getTopicId(MessageObject message) { + if (message == null) { + return 0; + } + return getTopicId(message.currentAccount, message.messageOwner, false); } - public static int getTopicId(TLRPC.Message message, boolean sureIsForum) { + private static long getTopicId(int currentAccount, TLRPC.Message message) { + return getTopicId(currentAccount, message, false); + } + + public static long getTopicId(int currentAccount, TLRPC.Message message, boolean sureIsForum) { + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + if (!sureIsForum && message != null && currentAccount >= 0 && DialogObject.getPeerDialogId(message.peer_id) == selfId) { + return getSavedDialogId(selfId, message); + } + if (message != null && message.action instanceof TLRPC.TL_messageActionTopicCreate) { return message.id; } @@ -478,7 +494,7 @@ public class MessageObject { } } if (changed) { - MessagesStorage.getInstance(currentAccount).markMessageReactionsAsRead(messageOwner.dialog_id, getTopicId(messageOwner), messageOwner.id, true); + MessagesStorage.getInstance(currentAccount).markMessageReactionsAsRead(messageOwner.dialog_id, getTopicId(currentAccount, messageOwner), messageOwner.id, true); } } @@ -946,6 +962,8 @@ public class MessageObject { return maxSizeWidth / sum; } + public boolean reversed; + public void calculate() { posArray.clear(); positions.clear(); @@ -975,9 +993,9 @@ public class MessageObject { hasCaption = false; boolean checkCaption = true; - for (int a = 0; a < count; a++) { + for (int a = (reversed ? count - 1 : 0); (reversed ? a >= 0 : a < count);) { MessageObject messageObject = messages.get(a); - if (a == 0) { + if (a == (reversed ? count - 1 : 0)) { isOut = messageObject.isOutOwner(); needShare = !isOut && ( messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.saved_from_peer != null || @@ -990,7 +1008,7 @@ public class MessageObject { } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); GroupedMessagePosition position = new GroupedMessagePosition(); - position.last = a == count - 1; + position.last = (reversed ? a == 0 : a == count - 1); position.aspectRatio = photoSize == null ? 1.0f : photoSize.w / (float) photoSize.h; if (position.aspectRatio > 1.2f) { @@ -1019,14 +1037,21 @@ public class MessageObject { } hasCaption = true; } + + if (reversed) { + a--; + } else { + a++; + } } if (isDocuments) { for (int a = 0; a < count; a++) { GroupedMessagePosition pos = posArray.get(a); - pos.flags |= POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT; - if (a == 0) { + pos.flags = POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT; + if (!reversed && a == 0 || reversed && a == count - 1) { pos.flags |= POSITION_FLAG_TOP; - } else if (a == count - 1) { + pos.last = false; + } else if (reversed && a == 0 || !reversed && a == count - 1) { pos.flags |= POSITION_FLAG_BOTTOM; pos.last = true; } @@ -1034,8 +1059,8 @@ public class MessageObject { pos.aspectRatio = 1.0f; pos.minX = 0; pos.maxX = 0; - pos.minY = (byte) a; - pos.maxY = (byte) a; + pos.minY = (byte) (reversed ? count - 1 - a : a); + pos.maxY = (byte) (reversed ? count - 1 - a : a); pos.spanSize = 1000; pos.pw = maxSizeWidth; pos.ph = 100; @@ -1490,7 +1515,11 @@ public class MessageObject { } public MessageObject(int accountNum, TLRPC.Message message, LongSparseArray users, LongSparseArray chats, boolean generateLayout, boolean checkMediaExists) { - this(accountNum, message, null, null, null, users, chats, generateLayout, checkMediaExists, 0); + this(accountNum, message, null, null, null, users, chats, generateLayout, checkMediaExists, 0, false, false, false); + } + + public MessageObject(int accountNum, TLRPC.Message message, LongSparseArray users, LongSparseArray chats, boolean generateLayout, boolean checkMediaExists, boolean isSavedMessages) { + this(accountNum, message, null, null, null, users, chats, generateLayout, checkMediaExists, 0, false, false, isSavedMessages); } public MessageObject(int accountNum, TLRPC.Message message, AbstractMap users, AbstractMap chats, boolean generateLayout, boolean checkMediaExists, long eid) { @@ -1498,14 +1527,15 @@ public class MessageObject { } public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap users, AbstractMap chats, LongSparseArray sUsers, LongSparseArray sChats, boolean generateLayout, boolean checkMediaExists, long eid) { - this(accountNum, message, replyToMessage, users, chats, sUsers, sChats, generateLayout, checkMediaExists, eid, false, false); + this(accountNum, message, replyToMessage, users, chats, sUsers, sChats, generateLayout, checkMediaExists, eid, false, false, false); } - public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap users, AbstractMap chats, LongSparseArray sUsers, LongSparseArray sChats, boolean generateLayout, boolean checkMediaExists, long eid, boolean isRepostPreview, boolean isRepostVideoPreview) { + public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyToMessage, AbstractMap users, AbstractMap chats, LongSparseArray sUsers, LongSparseArray sChats, boolean generateLayout, boolean checkMediaExists, long eid, boolean isRepostPreview, boolean isRepostVideoPreview, boolean isSavedMessages) { Theme.createCommonMessageResources(); this.isRepostPreview = isRepostPreview; this.isRepostVideoPreview = isRepostVideoPreview; + this.isSaved = isSavedMessages; currentAccount = accountNum; messageOwner = message; @@ -1633,10 +1663,14 @@ public class MessageObject { return; } try { + String filter = "b"; + if (isRoundVideo()) { + filter += "r"; + } for (int a = 0, N = photoThumbs.size(); a < N; a++) { TLRPC.PhotoSize photoSize = photoThumbs.get(a); if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - strippedThumb = new BitmapDrawable(ApplicationLoader.applicationContext.getResources(), ImageLoader.getStrippedPhotoBitmap(photoSize.bytes, "b")); + strippedThumb = new BitmapDrawable(ApplicationLoader.applicationContext.getResources(), ImageLoader.getStrippedPhotoBitmap(photoSize.bytes, filter)); break; } } @@ -3557,6 +3591,7 @@ public class MessageObject { } public void createMessageSendInfo() { + boolean notReadyYet = videoEditedInfo != null && videoEditedInfo.notReadyYet; if (messageOwner.message != null && (messageOwner.id < 0 || isEditing()) && messageOwner.params != null) { String param; if ((param = messageOwner.params.get("ve")) != null && (isVideo() || isNewGif() || isRoundVideo())) { @@ -3565,6 +3600,7 @@ public class MessageObject { videoEditedInfo = null; } else { videoEditedInfo.roundVideo = isRoundVideo(); + videoEditedInfo.notReadyYet = notReadyYet; } } if (messageOwner.send_state == MESSAGE_SEND_STATE_EDITING && (param = messageOwner.params.get("prevMedia")) != null) { @@ -4339,6 +4375,9 @@ public class MessageObject { messageText = LocaleController.getString(R.string.ActionBotAllowedWebapp); } else if (botApp != null) { String botAppTitle = botApp.title; + if (botAppTitle == null) { + botAppTitle = ""; + } String text = LocaleController.getString("ActionBotAllowedApp", R.string.ActionBotAllowedApp); int start = text.indexOf("%1$s"); SpannableString str = new SpannableString(String.format(text, botAppTitle)); @@ -4473,6 +4512,10 @@ public class MessageObject { } else { messageText = LocaleController.getString("Poll", R.string.Poll); } + } else if (isVoiceOnce()) { + messageText = LocaleController.getString(R.string.AttachOnceAudio); + } else if (isRoundOnce()) { + messageText = LocaleController.getString(R.string.AttachOnceRound); } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto) { if (getMedia(messageOwner).ttl_seconds != 0 && !(messageOwner instanceof TLRPC.TL_message_secret)) { messageText = LocaleController.getString("AttachDestructingPhoto", R.string.AttachDestructingPhoto); @@ -4483,7 +4526,13 @@ public class MessageObject { } } else if (isVideo() || getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument && (getDocument() instanceof TLRPC.TL_documentEmpty || getDocument() == null) && getMedia(messageOwner).ttl_seconds != 0) { if (getMedia(messageOwner).ttl_seconds != 0 && !(messageOwner instanceof TLRPC.TL_message_secret)) { - messageText = LocaleController.getString("AttachDestructingVideo", R.string.AttachDestructingVideo); + if (getMedia(messageOwner).voice) { + messageText = LocaleController.getString(R.string.AttachVoiceExpired); + } else if (getMedia(messageOwner).round) { + messageText = LocaleController.getString(R.string.AttachRoundExpired); + } else { + messageText = LocaleController.getString(R.string.AttachDestructingVideo); + } } else { messageText = LocaleController.getString("AttachVideo", R.string.AttachVideo); } @@ -4563,7 +4612,7 @@ public class MessageObject { } if (link != null) { SpannableString str = new SpannableString(link); - ((SpannableString) str).setSpan(new URLSpanReplacement("https://" + link, new TextStyleSpan.TextStyleRun()), 0, messageText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ((SpannableString) str).setSpan(new URLSpanReplacement("https://" + link, new TextStyleSpan.TextStyleRun()), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return str; } else { return ""; @@ -4589,7 +4638,13 @@ public class MessageObject { } } else if (media != null && (isVideoDocument(media.document) || media instanceof TLRPC.TL_messageMediaDocument && (media.document instanceof TLRPC.TL_documentEmpty || media.document == null) && media.ttl_seconds != 0)) { if (media.ttl_seconds != 0 && !(messageOwner instanceof TLRPC.TL_message_secret)) { - return LocaleController.getString("AttachDestructingVideo", R.string.AttachDestructingVideo); + if (media.voice) { + return LocaleController.getString(R.string.AttachVoiceExpired); + } else if (media.round) { + return LocaleController.getString(R.string.AttachRoundExpired); + } else { + return LocaleController.getString(R.string.AttachDestructingVideo); + } } else { return LocaleController.getString("AttachVideo", R.string.AttachVideo); } @@ -6134,6 +6189,11 @@ public class MessageObject { if (isRepostPreview) { return false; } + if (isSaved) { + long selfId = UserConfig.getInstance(currentAccount).clientUserId; + long dialogId = MessageObject.getSavedDialogId(selfId, messageOwner); + return dialogId != selfId && dialogId != UserObject.ANONYMOUS; + } if (type == TYPE_JOINED_CHANNEL) { return false; } else if (isSponsored()) { @@ -6197,7 +6257,7 @@ public class MessageObject { generatedWithMinSize = AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() : getParentWidth(); } generatedWithDensity = AndroidUtilities.density; - if (hasCode) { + if (hasCode && !isSaved) { maxWidth = generatedWithMinSize - dp(45 + 15); if (needDrawAvatarInternal() && !isOutOwner() && !messageOwner.isThreadMessage) { maxWidth -= dp(52); @@ -6303,6 +6363,50 @@ public class MessageObject { return addEntitiesToText(messageText, useManualParse); } + private static StaticLayout makeStaticLayout(CharSequence text, TextPaint paint, int width, float lineSpacingMult, float lineSpacingAdd, boolean dontIncludePad) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + StaticLayout.Builder builder = + StaticLayout.Builder.obtain(text, 0, text.length(), paint, width) + .setLineSpacing(lineSpacingAdd, lineSpacingMult) + .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) + .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) + .setAlignment(Layout.Alignment.ALIGN_NORMAL); + if (dontIncludePad) { + builder.setIncludePad(false); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + builder.setUseLineSpacingFromFallbacks(false); + } + } + StaticLayout layout = builder.build(); + + boolean realWidthLarger = false; + for (int l = 0; l < layout.getLineCount(); ++l) { + if (layout.getLineRight(l) > width) { + realWidthLarger = true; + break; + } + } + if (realWidthLarger) { + builder = StaticLayout.Builder.obtain(text, 0, text.length(), paint, width) + .setLineSpacing(lineSpacingAdd, lineSpacingMult) + .setBreakStrategy(StaticLayout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) + .setAlignment(Layout.Alignment.ALIGN_NORMAL); + if (dontIncludePad) { + builder.setIncludePad(false); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + builder.setUseLineSpacingFromFallbacks(false); + } + } + layout = builder.build(); + } + + return layout; + } else { + return new StaticLayout(text, paint, width, Layout.Alignment.ALIGN_NORMAL, lineSpacingMult, lineSpacingAdd, false); + } + } + public void generateLayout(TLRPC.User fromUser) { if (type != TYPE_TEXT && type != TYPE_EMOJIS && type != TYPE_STORY_MENTION || messageOwner.peer_id == null || TextUtils.isEmpty(messageText)) { return; @@ -6352,28 +6456,9 @@ public class MessageObject { paint = Theme.chat_msgTextPaint; } - final float lineSpacing = 1f; - final float lineAdd = totalAnimatedEmojiCount >= 4 ? -1 : 0; - Layout.Alignment align = Layout.Alignment.ALIGN_NORMAL; //type == TYPE_EMOJIS && isOut() ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL; CharSequence text = messageText; try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(text, 0, text.length(), paint, maxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - if (emojiOnlyCount > 0) { - builder.setIncludePad(false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - builder.setUseLineSpacingFromFallbacks(false); - } - } - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(text, paint, maxWidth, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(text, paint, maxWidth, 1f, totalAnimatedEmojiCount >= 4 ? -1 : 0, emojiOnlyCount > 0); } catch (Exception e) { FileLog.e(e); return; @@ -6418,23 +6503,7 @@ public class MessageObject { }, text.length() - readMore.length(), text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(text, 0, text.length(), paint, maxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - if (emojiOnlyCount > 0) { - builder.setIncludePad(false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - builder.setUseLineSpacingFromFallbacks(false); - } - } - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(text, paint, maxWidth, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(text, paint, maxWidth, 1f, totalAnimatedEmojiCount >= 4 ? -1 : 0, emojiOnlyCount > 0); } catch (Exception e) { FileLog.e(e); return; @@ -6557,23 +6626,7 @@ public class MessageObject { } else { sb = new SpannableString(blockText.toString()); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, blockMaxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - if (emojiOnlyCount > 0) { - builder.setIncludePad(false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - builder.setUseLineSpacingFromFallbacks(false); - } - } - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, totalAnimatedEmojiCount >= 4 ? -1 : 0, emojiOnlyCount > 0); } block.textLayout = textLayout; @@ -6614,17 +6667,7 @@ public class MessageObject { } else { sb = SpannableString.valueOf(blockText); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, blockMaxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - block.textLayout = builder.build(); - } else { - block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); - } + block.textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, totalAnimatedEmojiCount >= 4 ? -1 : 0, false); block.textYOffset = offset; if (a != 0 && emojiOnlyCount <= 0) { @@ -6838,17 +6881,7 @@ public class MessageObject { final float lineAdd = 0; Layout.Alignment align = Layout.Alignment.ALIGN_NORMAL; //type == TYPE_EMOJIS && isOut() ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL; try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, width) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(text, textPaint, width, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(text, textPaint, width, 1f, 0f, false); } catch (Exception e) { FileLog.e(e); return; @@ -6892,17 +6925,7 @@ public class MessageObject { }, text.length() - readMore.length(), text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, width) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(text, textPaint, width, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(text, textPaint, width, 1f, 0f, false); } catch (Exception e) { FileLog.e(e); return; @@ -7017,17 +7040,7 @@ public class MessageObject { } else { sb = new SpannableString(text.subSequence(range.start, range.end)); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, text.length(), layoutPaint, blockMaxWidth) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - textLayout = builder.build(); - } else { - textLayout = new StaticLayout(sb, layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); - } + textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, 0f, false); } block.textLayout = textLayout; @@ -7052,7 +7065,7 @@ public class MessageObject { } else { sb = SpannableString.valueOf(text.subSequence(startCharacter, endCharacter)); } - block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); + block.textLayout = makeStaticLayout(sb, layoutPaint, blockMaxWidth, 1f, 0f, false); block.textYOffset = offset; if (a != 0) { @@ -7225,6 +7238,10 @@ public class MessageObject { if (isOutOwnerCached != null) { return isOutOwnerCached; } + long selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); + if (isSaved && messageOwner.fwd_from != null) { + return isOutOwnerCached = messageOwner.fwd_from.from_id != null && messageOwner.fwd_from.from_id.user_id == selfUserId || messageOwner.fwd_from.saved_out; + } TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(null, null, messageOwner.peer_id.channel_id) : null; if (!messageOwner.out || !(messageOwner.from_id instanceof TLRPC.TL_peerUser) && (!(messageOwner.from_id instanceof TLRPC.TL_peerChannel) || ChatObject.isChannel(chat) && !chat.megagroup) || messageOwner.post) { return isOutOwnerCached = false; @@ -7232,7 +7249,6 @@ public class MessageObject { if (messageOwner.fwd_from == null) { return isOutOwnerCached = true; } - long selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); if (getDialogId() == selfUserId) { return isOutOwnerCached = messageOwner.fwd_from.from_id instanceof TLRPC.TL_peerUser && messageOwner.fwd_from.from_id.user_id == selfUserId && (messageOwner.fwd_from.saved_from_peer == null || messageOwner.fwd_from.saved_from_peer.user_id == selfUserId) || messageOwner.fwd_from.saved_from_peer != null && messageOwner.fwd_from.saved_from_peer.user_id == selfUserId && (messageOwner.fwd_from.from_id == null || messageOwner.fwd_from.from_id.user_id == selfUserId); @@ -7244,6 +7260,9 @@ public class MessageObject { if (isRepostPreview) { return true; } + if (isSaved) { + return getSavedDialogId() < 0 || getSavedDialogId() == UserObject.ANONYMOUS; + } if (forceAvatar || customAvatarDrawable != null) { return true; } @@ -7254,6 +7273,9 @@ public class MessageObject { if (isRepostPreview) { return true; } + if (isSaved) { + return getSavedDialogId() < 0 || getSavedDialogId() == UserObject.ANONYMOUS; + } if (forceAvatar || customAvatarDrawable != null) { return true; } @@ -7541,9 +7563,12 @@ public class MessageObject { } public static boolean shouldEncryptPhotoOrVideo(int currentAccount, TLRPC.Message message) { - if (MessagesController.getInstance(currentAccount).isChatNoForwards(getChatId(message)) || message != null && message.noforwards) { + if (message != null && message.media != null && (isVoiceDocument(getDocument(message)) || isRoundVideoMessage(message)) && message.media.ttl_seconds == 0x7FFFFFFF) { return true; } +// if (MessagesController.getInstance(currentAccount).isChatNoForwards(getChatId(message)) || message != null && message.noforwards) { +// return true; +// } if (message instanceof TLRPC.TL_message_secret) { return (getMedia(message) instanceof TLRPC.TL_messageMediaPhoto || isVideoMessage(message)) && message.ttl > 0 && message.ttl <= 60; } else { @@ -7661,6 +7686,58 @@ public class MessageObject { return message.dialog_id; } + public long getSavedDialogId() { + return getSavedDialogId(UserConfig.getInstance(currentAccount).getClientUserId(), messageOwner); + } + + public static long getSavedDialogId(long self, TLRPC.Message message) { + if (message.saved_peer_id != null) { + if (message.saved_peer_id.chat_id != 0) { + return -message.saved_peer_id.chat_id; + } else if (message.saved_peer_id.channel_id != 0) { + return -message.saved_peer_id.channel_id; + } else { + return message.saved_peer_id.user_id; + } + } + if (message.from_id.user_id == self) { + if (message.fwd_from != null && message.fwd_from.saved_from_peer != null) { + return DialogObject.getPeerDialogId(message.fwd_from.saved_from_peer); + } else if (message.fwd_from != null && message.fwd_from.from_id != null) { + return self; + } else if (message.fwd_from != null) { + return UserObject.ANONYMOUS; + } else { + return self; + } + } + return 0; + } + + public static TLRPC.Peer getSavedDialogPeer(long self, TLRPC.Message message) { + if (message.saved_peer_id != null) { + return message.saved_peer_id; + } + if (message.peer_id != null && message.peer_id.user_id == self && message.from_id != null && message.from_id.user_id == self) { + if (message.fwd_from != null && message.fwd_from.saved_from_peer != null) { + return message.fwd_from.saved_from_peer; + } else if (message.fwd_from != null && message.fwd_from.from_id != null) { + TLRPC.Peer peer = new TLRPC.TL_peerUser(); + peer.user_id = self; + return peer; + } else if (message.fwd_from != null) { + TLRPC.Peer peer = new TLRPC.TL_peerUser(); + peer.user_id = 2666000L; + return peer; + } else { + TLRPC.Peer peer = new TLRPC.TL_peerUser(); + peer.user_id = self; + return peer; + } + } + return null; + } + public boolean isSending() { return messageOwner.send_state == MESSAGE_SEND_STATE_SENDING && messageOwner.id < 0; } @@ -8460,7 +8537,7 @@ public class MessageObject { public boolean isRoundVideo() { if (isRoundVideoCached == 0) { - isRoundVideoCached = type == TYPE_ROUND_VIDEO || isRoundVideoMessage(messageOwner) ? TYPE_PHOTO : TYPE_VOICE; + isRoundVideoCached = type == TYPE_ROUND_VIDEO || isRoundVideoMessage(messageOwner) ? 1 : 2; } return isRoundVideoCached == 1; } @@ -8700,6 +8777,17 @@ public class MessageObject { } public boolean needDrawForwarded() { + if (isSaved) { + if (messageOwner == null || messageOwner.fwd_from == null) return false; + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + final long savedId = getSavedDialogId(selfId, messageOwner); + long fromId = DialogObject.getPeerDialogId(messageOwner.fwd_from.saved_from_peer); + if (fromId >= 0) { + fromId = DialogObject.getPeerDialogId(messageOwner.fwd_from.from_id); + } + if (fromId == 0) return savedId != UserObject.ANONYMOUS; + return savedId != fromId && fromId != selfId; + } if (type == MessageObject.TYPE_STORY && !isExpiredStory()) { return true; } @@ -9078,7 +9166,7 @@ public class MessageObject { } if (!attachPathExists) { File file = FileLoader.getInstance(currentAccount).getPathToMessage(messageOwner, useFileDatabaseQueue); - if (type == TYPE_VIDEO && needDrawBluredPreview()) { + if (type == TYPE_VIDEO && needDrawBluredPreview() || isVoiceOnce() || isRoundOnce()) { mediaExists = new File(file.getAbsolutePath() + ".enc").exists(); } if (!mediaExists) { @@ -9328,6 +9416,7 @@ public class MessageObject { public boolean selectReaction(ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean big, boolean fromDoubleTap) { if (messageOwner.reactions == null) { messageOwner.reactions = new TLRPC.TL_messageReactions(); + messageOwner.reactions.reactions_as_tags = MessageObject.getDialogId(messageOwner) == UserConfig.getInstance(currentAccount).getClientUserId(); messageOwner.reactions.can_see_list = isFromGroup() || isFromUser(); } @@ -9373,6 +9462,9 @@ public class MessageObject { if (newReaction.count <= 0) { messageOwner.reactions.results.remove(newReaction); } + if (messageOwner.reactions.reactions_as_tags) { + MessagesController.getInstance(currentAccount).updateSavedReactionTags(visibleReaction, false); + } } if (messageOwner.reactions.can_see_list) { for (int i = 0; i < messageOwner.reactions.recent_reactions.size(); i++) { @@ -9399,6 +9491,9 @@ public class MessageObject { if (choosenReaction.count <= 0) { messageOwner.reactions.results.remove(choosenReaction); } + if (messageOwner.reactions.reactions_as_tags) { + MessagesController.getInstance(currentAccount).updateSavedReactionTags(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(choosenReaction.reaction), false); + } choosenReactions.remove(choosenReaction); if (messageOwner.reactions.can_see_list) { @@ -9412,20 +9507,16 @@ public class MessageObject { } if (newReaction == null) { newReaction = new TLRPC.TL_reactionCount(); - if (visibleReaction.emojicon != null) { - newReaction.reaction = new TLRPC.TL_reactionEmoji(); - ((TLRPC.TL_reactionEmoji) newReaction.reaction).emoticon = visibleReaction.emojicon; - messageOwner.reactions.results.add(newReaction); - } else { - newReaction.reaction = new TLRPC.TL_reactionCustomEmoji(); - ((TLRPC.TL_reactionCustomEmoji) newReaction.reaction).document_id = visibleReaction.documentId; - messageOwner.reactions.results.add(newReaction); - } + newReaction.reaction = visibleReaction.toTLReaction(); + messageOwner.reactions.results.add(newReaction); } newReaction.chosen = true; newReaction.count++; newReaction.chosen_order = maxChoosenOrder + 1; + if (messageOwner.reactions.reactions_as_tags) { + MessagesController.getInstance(currentAccount).updateSavedReactionTags(visibleReaction, true); + } if (messageOwner.reactions.can_see_list || (messageOwner.dialog_id > 0 && maxReactionsCount > 1)) { TLRPC.TL_messagePeerReaction action = new TLRPC.TL_messagePeerReaction(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 2ecc71924..03faf00fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -40,6 +40,8 @@ import androidx.core.app.NotificationManagerCompat; import androidx.core.graphics.ColorUtils; import androidx.core.util.Consumer; +import com.google.android.exoplayer2.util.Log; + import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; @@ -69,6 +71,7 @@ import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.JoinCallAlert; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.SwipeGestureSettingsView; import org.telegram.ui.Components.TranscribeButton; import org.telegram.ui.DialogsActivity; @@ -81,6 +84,8 @@ import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.TopicsFragment; import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -133,9 +138,9 @@ public class MessagesController extends BaseController implements NotificationCe public LongSparseIntArray deletedHistory = new LongSparseIntArray(); public SparseArray dialogMessagesByIds = new SparseArray<>(); public ConcurrentHashMap>> printingUsers = new ConcurrentHashMap<>(20, 1.0f, 2); - public LongSparseArray> printingStrings = new LongSparseArray<>(); - public LongSparseArray> printingStringsTypes = new LongSparseArray<>(); - public LongSparseArray>[] sendingTypings = new LongSparseArray[12]; + public LongSparseArray> printingStrings = new LongSparseArray<>(); + public LongSparseArray> printingStringsTypes = new LongSparseArray<>(); + public LongSparseArray>[] sendingTypings = new LongSparseArray[12]; public ConcurrentHashMap onlinePrivacy = new ConcurrentHashMap<>(20, 1.0f, 2); private LongSparseIntArray pendingUnreadCounter = new LongSparseIntArray(); private int lastPrintingStringCount; @@ -146,6 +151,7 @@ public class MessagesController extends BaseController implements NotificationCe public int stealthModePast; public int stealthModeCooldown; public StoriesController storiesController; + public SavedMessagesController savedMessagesController; public UnconfirmedAuthController unconfirmedAuthController; private boolean hasArchivedChats; private boolean hasStories; @@ -276,8 +282,11 @@ public class MessagesController extends BaseController implements NotificationCe private LongSparseArray> reloadingWebpagesPending = new LongSparseArray<>(); private HashMap> reloadingScheduledWebpages = new HashMap<>(); private LongSparseArray> reloadingScheduledWebpagesPending = new LongSparseArray<>(); + private HashMap> reloadingSavedWebpages = new HashMap<>(); + private LongSparseArray> reloadingSavedWebpagesPending = new LongSparseArray<>(); private LongSparseArray lastScheduledServerQueryTime = new LongSparseArray<>(); + private LongSparseArray lastSavedServerQueryTime = new LongSparseArray<>(); private LongSparseArray lastServerQueryTime = new LongSparseArray<>(); private LongSparseArray> reloadingMessages = new LongSparseArray<>(); @@ -469,6 +478,7 @@ public class MessagesController extends BaseController implements NotificationCe public int updateCheckDelay; public int chatReadMarkSizeThreshold; public int chatReadMarkExpirePeriod; + public int pmReadDateExpirePeriod; public String mapKey; public int maxMessageLength; public int maxCaptionLength; @@ -571,6 +581,8 @@ public class MessagesController extends BaseController implements NotificationCe public int channelEmojiStatusLevelMin; public int channelWallpaperLevelMin; public int channelCustomWallpaperLevelMin; + public int savedDialogsPinnedLimitDefault; + public int savedDialogsPinnedLimitPremium; public int uploadMaxFileParts; public int uploadMaxFilePartsPremium; @@ -616,7 +628,7 @@ public class MessagesController extends BaseController implements NotificationCe public int checkResetLangpack; - public void getNextReactionMention(long dialogId, int topicId, int count, Consumer callback) { + public void getNextReactionMention(long dialogId, long topicId, int count, Consumer callback) { final MessagesStorage messagesStorage = getMessagesStorage(); messagesStorage.getStorageQueue().postRunnable(() -> { boolean needRequest = true; @@ -949,6 +961,7 @@ public class MessagesController extends BaseController implements NotificationCe public void clearQueryTime() { lastServerQueryTime.clear(); lastScheduledServerQueryTime.clear(); + lastSavedServerQueryTime.clear(); } public static class DiceFrameSuccess { @@ -1364,7 +1377,7 @@ public class MessagesController extends BaseController implements NotificationCe chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); ringtoneDurationMax = mainPreferences.getInt("ringtoneDurationMax", 5); ringtoneSizeMax = mainPreferences.getInt("ringtoneSizeMax", 1024_00); - chatReadMarkExpirePeriod = mainPreferences.getInt("chatReadMarkExpirePeriod", 7 * 86400); + pmReadDateExpirePeriod = mainPreferences.getInt("pmReadDateExpirePeriod", 7 * 86400); suggestStickersApiOnly = mainPreferences.getBoolean("suggestStickersApiOnly", false); roundVideoSize = mainPreferences.getInt("roundVideoSize", 384); roundVideoBitrate = mainPreferences.getInt("roundVideoBitrate", 1000); @@ -1457,6 +1470,8 @@ public class MessagesController extends BaseController implements NotificationCe recommendedChannelsLimitDefault = mainPreferences.getInt("recommendedChannelsLimitDefault", 10); recommendedChannelsLimitPremium = mainPreferences.getInt("recommendedChannelsLimitPremium", 100); boostsChannelLevelMax = mainPreferences.getInt("boostsChannelLevelMax", 100); + savedDialogsPinnedLimitDefault = mainPreferences.getInt("savedDialogsPinnedLimitDefault", 4); + savedDialogsPinnedLimitPremium = mainPreferences.getInt("savedDialogsPinnedLimitPremium", 6); scheduleTranscriptionUpdate(); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); if (mainPreferences.contains("dcDomainName2")) { @@ -2721,6 +2736,17 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "pm_read_date_expire_period": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != pmReadDateExpirePeriod) { + pmReadDateExpirePeriod = (int) number.value; + editor.putInt("pmReadDateExpirePeriod", pmReadDateExpirePeriod); + changed = true; + } + } + break; + } case "inapp_update_check_delay": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; @@ -3655,6 +3681,28 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "saved_dialogs_pinned_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != savedDialogsPinnedLimitDefault) { + savedDialogsPinnedLimitDefault = (int) num.value; + editor.putInt("savedDialogsPinnedLimitDefault", savedDialogsPinnedLimitDefault); + changed = true; + } + } + break; + } + case "saved_dialogs_pinned_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != savedDialogsPinnedLimitPremium) { + savedDialogsPinnedLimitPremium = (int) num.value; + editor.putInt("savedDialogsPinnedLimitPremium", savedDialogsPinnedLimitPremium); + changed = true; + } + } + break; + } } } @@ -4870,6 +4918,7 @@ public class MessagesController extends BaseController implements NotificationCe } } else if (id == NotificationCenter.currentUserPremiumStatusChanged) { loadAppConfig(false); + getContactsController().reloadContactsStatusesMaybe(true); } } @@ -4883,6 +4932,7 @@ public class MessagesController extends BaseController implements NotificationCe getMediaDataController().cleanup(); getColorPalette().cleanup(); getTranslateController().cleanup(); + getSavedMessagesController().cleanup(); if (storiesController != null) { storiesController.cleanup(); } @@ -4947,11 +4997,14 @@ public class MessagesController extends BaseController implements NotificationCe } lastScheduledServerQueryTime.clear(); + lastSavedServerQueryTime.clear(); lastServerQueryTime.clear(); reloadingWebpages.clear(); reloadingWebpagesPending.clear(); reloadingScheduledWebpages.clear(); reloadingScheduledWebpagesPending.clear(); + reloadingSavedWebpages.clear(); + reloadingSavedWebpagesPending.clear(); sponsoredMessages.clear(); sendAsPeers.clear(); dialogs_dict.clear(); @@ -5334,6 +5387,24 @@ public class MessagesController extends BaseController implements NotificationCe return false; } + public void reloadUser(long userId) { + TLRPC.TL_users_getUsers req = new TLRPC.TL_users_getUsers(); + TLRPC.InputUser inputPeer = getInputUser(userId); + if (inputPeer == null) return; + req.id.add(inputPeer); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.Vector) { + ArrayList objects = ((TLRPC.Vector) res).objects; + ArrayList users = new ArrayList<>(); + for (int i = 0; i < objects.size(); ++i) { + if (objects.get(i) instanceof TLRPC.User) { + users.add((TLRPC.User) objects.get(i)); + } + } + getMessagesController().putUsers(users, false); + } + }); + } public void putUsers(ArrayList users, boolean fromCache) { if (users == null || users.isEmpty()) { return; @@ -6034,10 +6105,12 @@ public class MessagesController extends BaseController implements NotificationCe getConnectionsManager().bindRequestToGuid(reqId, classGuid); } - private void reloadMessages(ArrayList mids, long dialogId, boolean scheduled) { + private void reloadMessages(ArrayList mids, long dialogId, int mode) { if (mids.isEmpty()) { return; } + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean saved = mode == ChatActivity.MODE_SAVED; TLObject request; ArrayList result = new ArrayList<>(); TLRPC.Chat chat; @@ -6110,7 +6183,7 @@ public class MessagesController extends BaseController implements NotificationCe } ImageLoader.saveMessagesThumbs(messagesRes.messages); - getMessagesStorage().putMessages(messagesRes, dialogId, -1, 0, false, scheduled, 0); + getMessagesStorage().putMessages(messagesRes, dialogId, -1, 0, false, mode, 0); AndroidUtilities.runOnUIThread(() -> { ArrayList arrayList1 = reloadingMessages.get(dialogId); @@ -7679,9 +7752,9 @@ public class MessagesController extends BaseController implements NotificationCe } public void putAllNeededDraftDialogs() { - LongSparseArray> drafts = getMediaDataController().getDrafts(); + LongSparseArray> drafts = getMediaDataController().getDrafts(); for (int i = 0, size = drafts.size(); i < size; i++) { - SparseArray threads = drafts.valueAt(i); + LongSparseArray threads = drafts.valueAt(i); TLRPC.DraftMessage draftMessage = threads.get(0); if (draftMessage == null) { continue; @@ -7954,7 +8027,7 @@ public class MessagesController extends BaseController implements NotificationCe ArrayList arr = new ArrayList<>(); arr.add(message); updateInterfaceWithMessages(did, objArr, false); - getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0, 0); } else { dialog.top_message = 0; } @@ -8076,6 +8149,51 @@ public class MessagesController extends BaseController implements NotificationCe } } + public void deleteSavedDialog(long did) { + deleteSavedDialog(did, 0); + } + + protected void deleteSavedDialog(long did, int input_max_id) { + int[] max_id = new int[] { input_max_id }; + Runnable perform = () -> { + getMessagesStorage().deleteSavedDialog(did); + TLRPC.TL_messages_deleteSavedHistory req = new TLRPC.TL_messages_deleteSavedHistory(); + req.peer = getInputPeer(did); + if (input_max_id == 0) { + SavedMessagesController.SavedDialog dialog = null; + for (int i = 0; i < getSavedMessagesController().allDialogs.size(); ++i) { + if (getSavedMessagesController().allDialogs.get(i).dialogId == did) { + dialog = getSavedMessagesController().allDialogs.get(i); + break; + } + } + if (dialog != null) { + max_id[0] = Math.max(max_id[0], dialog.top_message_id); + getSavedMessagesController().deleteDialog(did); + } + req.max_id = max_id[0] <= 0 ? Integer.MAX_VALUE : max_id[0]; + } + getConnectionsManager().sendRequest(req, (response, error) -> { + if (error == null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (res.offset > 0) { + deleteSavedDialog(did, max_id[0]); + } + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + getMessagesStorage().onDeleteQueryComplete(did); + } + }, ConnectionsManager.RequestFlagInvokeAfter); + }; + if (max_id[0] <= 0) { + getMessagesStorage().getSavedDialogMaxMessageId(did, (param) -> { + max_id[0] = param; + perform.run(); + }); + } else { + perform.run(); + } + } + public void saveGif(Object parentObject, TLRPC.Document document) { if (parentObject == null || !MessageObject.isGifDocument(document)) { return; @@ -8863,8 +8981,8 @@ public class MessagesController extends BaseController implements NotificationCe } private void updatePrintingStrings() { - LongSparseArray> newStrings = new LongSparseArray<>(); - LongSparseArray> newTypes = new LongSparseArray<>(); + LongSparseArray> newStrings = new LongSparseArray<>(); + LongSparseArray> newTypes = new LongSparseArray<>(); for (HashMap.Entry>> dialogEntry : printingUsers.entrySet()) { Long key = dialogEntry.getKey(); @@ -8875,8 +8993,8 @@ public class MessagesController extends BaseController implements NotificationCe Integer threadId = threadEntry.getKey(); ArrayList arr = threadEntry.getValue(); - SparseArray newPrintingStrings = new SparseArray<>(); - SparseArray newPrintingStringsTypes = new SparseArray<>(); + LongSparseArray newPrintingStrings = new LongSparseArray<>(); + LongSparseArray newPrintingStringsTypes = new LongSparseArray<>(); newStrings.put(key, newPrintingStrings); newTypes.put(key, newPrintingStringsTypes); @@ -9045,12 +9163,12 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void cancelTyping(int action, long dialogId, int threadMsgId) { + public void cancelTyping(int action, long dialogId, long threadMsgId) { if (action < 0 || action >= sendingTypings.length || sendingTypings[action] == null) { return; } - LongSparseArray> dialogs = sendingTypings[action]; - SparseArray threads = dialogs.get(dialogId); + LongSparseArray> dialogs = sendingTypings[action]; + LongSparseArray threads = dialogs.get(dialogId); if (threads == null) { return; } @@ -9060,16 +9178,20 @@ public class MessagesController extends BaseController implements NotificationCe } } - public boolean sendTyping(long dialogId, int threadMsgId, int action, int classGuid) { + public boolean sendTyping(long dialogId, long threadMsgId, int action, int classGuid) { return sendTyping(dialogId, threadMsgId, action, null, classGuid); } - public boolean sendTyping(long dialogId, int threadMsgId, int action, String emojicon, int classGuid) { + public boolean sendTyping(long dialogId, long threadMsgId, int action, String emojicon, int classGuid) { if (action < 0 || action >= sendingTypings.length || dialogId == 0) { return false; } + final long selfId = UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId(); + if (dialogId == selfId) { + return false; + } if (dialogId < 0) { - if (ChatObject.getSendAsPeerId(getChat(-dialogId), getChatFull(-dialogId)) != UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId()) { + if (ChatObject.getSendAsPeerId(getChat(-dialogId), getChatFull(-dialogId)) != selfId) { return false; } } else { @@ -9086,13 +9208,13 @@ public class MessagesController extends BaseController implements NotificationCe } } } - LongSparseArray> dialogs = sendingTypings[action]; + LongSparseArray> dialogs = sendingTypings[action]; if (dialogs == null) { dialogs = sendingTypings[action] = new LongSparseArray<>(); } - SparseArray threads = dialogs.get(dialogId); + LongSparseArray threads = dialogs.get(dialogId); if (threads == null) { - dialogs.put(dialogId, threads = new SparseArray<>()); + dialogs.put(dialogId, threads = new LongSparseArray<>()); } if (threads.get(threadMsgId) != null) { return false; @@ -9100,7 +9222,7 @@ public class MessagesController extends BaseController implements NotificationCe if (!DialogObject.isEncryptedDialog(dialogId)) { TLRPC.TL_messages_setTyping req = new TLRPC.TL_messages_setTyping(); if (threadMsgId != 0) { - req.top_msg_id = threadMsgId; + req.top_msg_id = (int) threadMsgId; req.flags |= 1; } req.peer = getInputPeer(dialogId); @@ -9181,29 +9303,84 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, int mode, int threadMessageId, int replyFirstUnread, int loadIndex, boolean isTopic) { + public final static int LOAD_BACKWARD = 0; + public final static int LOAD_FORWARD = 1; + public final static int LOAD_FROM_UNREAD = 2; + public final static int LOAD_AROUND_MESSAGE = 3; + public final static int LOAD_AROUND_DATE = 4; + + public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, int mode, long threadMessageId, int replyFirstUnread, int loadIndex, boolean isTopic) { loadMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, mode, threadMessageId, loadIndex, threadMessageId != 0 ? replyFirstUnread : 0, 0, 0, false, 0, isTopic); } - public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, int mode, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean isTopic) { - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true, true, isTopic, null); + public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, int mode, long threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean isTopic) { + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true, true, isTopic, null, 0L); } - private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int minDate, int classGuid, int load_type, int last_message_id, int mode, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean loadDialog, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger) { + private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int minDate, int classGuid, int load_type, int last_message_id, int mode, long threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean loadDialog, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger, long hash) { if (BuildVars.LOGS_ENABLED) { FileLog.d("load messages in chat " + dialogId + " topic_id " + threadMessageId + " count " + count + " max_id " + max_id + " cache " + fromCache + " mindate = " + minDate + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " mode " + mode + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer + " isTopic " + isTopic); } if (BuildVars.LOGS_ENABLED && loaderLogger == null && mode == 0) { loaderLogger = new MessageLoaderLogger(dialogId, loadIndex, count); } - if ((threadMessageId == 0 || isTopic) && mode != 2 && (fromCache || DialogObject.isEncryptedDialog(dialogId))) { - getMessagesStorage().getMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, minDate, classGuid, load_type, mode == 1, threadMessageId, loadIndex, processMessages, isTopic, loaderLogger); + if ((threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED) && mode != ChatActivity.MODE_PINNED && (fromCache || DialogObject.isEncryptedDialog(dialogId))) { + getMessagesStorage().getMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, minDate, classGuid, load_type, mode, threadMessageId, loadIndex, processMessages, isTopic, loaderLogger); } else { if (threadMessageId != 0) { + if (mode == ChatActivity.MODE_SAVED) { + TLRPC.TL_messages_getSavedHistory req = new TLRPC.TL_messages_getSavedHistory(); + req.peer = getInputPeer(threadMessageId); + if (load_type == 4) { + req.add_offset = -count + 5; + } else if (load_type == 3) { + req.add_offset = -count / 2; + } else if (load_type == 1) { + req.add_offset = -count - 1; + } else if (load_type == 2 && max_id != 0) { + req.add_offset = -count + 6; + } else { + if (dialogId < 0 && max_id != 0) { + TLRPC.Chat chat = getChat(-dialogId); + if (ChatObject.isChannel(chat)) { + req.add_offset = -1; + req.limit += 1; + } + } + } + req.limit = count; + req.offset_id = max_id; + req.offset_date = offset_date; + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + removeDeletedMessagesFromArray(dialogId, res.messages); + if (res.messages.size() > count) { + res.messages.remove(0); + } + int mid = max_id; + if (offset_date != 0 && !res.messages.isEmpty()) { + mid = res.messages.get(res.messages.size() - 1).id; + for (int a = res.messages.size() - 1; a >= 0; a--) { + TLRPC.Message message = res.messages.get(a); + if (message.date > offset_date) { + mid = message.id; + break; + } + } + } + processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); + } else { + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); + } + }); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + return; + } if (loadDialog && isTopic && load_type == 2 && last_message_id == 0) { TLRPC.TL_forumTopic topic = topicsController.findTopic(-dialogId, threadMessageId); if (topic != null) { - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, topic.top_message, 0, threadMessageId, loadIndex, first_unread, topic.unread_count, last_date, queryFromServer, topic.unread_mentions_count, false, processMessages, isTopic, loaderLogger); + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, topic.top_message, 0, threadMessageId, loadIndex, first_unread, topic.unread_count, last_date, queryFromServer, topic.unread_mentions_count, false, processMessages, isTopic, loaderLogger, 0L); return; } } @@ -9212,7 +9389,7 @@ public class MessagesController extends BaseController implements NotificationCe } TLRPC.TL_messages_getReplies req = new TLRPC.TL_messages_getReplies(); req.peer = getInputPeer(dialogId); - req.msg_id = threadMessageId; + req.msg_id = (int) threadMessageId; req.offset_date = offset_date; if (load_type == 4) { req.add_offset = -count + 5; @@ -9233,6 +9410,7 @@ public class MessagesController extends BaseController implements NotificationCe } req.limit = count; req.offset_id = max_id; + req.hash = hash; long time = System.currentTimeMillis(); int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { @@ -9262,17 +9440,17 @@ public class MessagesController extends BaseController implements NotificationCe } } } - processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, fnid, last_message_id, unread_count, last_date, load_type, false, 0, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); + processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, fnid, last_message_id, unread_count, last_date, load_type, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); } }); getConnectionsManager().bindRequestToGuid(reqId, classGuid); - } else if (mode == 2) { - } else if (mode == 1) { + } else if (mode == ChatActivity.MODE_PINNED) { + } else if (mode == ChatActivity.MODE_SCHEDULED) { TLRPC.TL_messages_getScheduledHistory req = new TLRPC.TL_messages_getScheduledHistory(); req.peer = getInputPeer(dialogId); - req.hash = minDate; + req.hash = hash; int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; @@ -9295,7 +9473,7 @@ public class MessagesController extends BaseController implements NotificationCe }); getConnectionsManager().bindRequestToGuid(reqId, classGuid); } else { - if (loadDialog && (load_type == 3 || load_type == 2) && last_message_id == 0) { + if (loadDialog && (load_type == LOAD_AROUND_MESSAGE || load_type == LOAD_FROM_UNREAD) && last_message_id == 0) { TLRPC.TL_messages_getPeerDialogs req = new TLRPC.TL_messages_getPeerDialogs(); TLRPC.InputPeer inputPeer = getInputPeer(dialogId); TLRPC.TL_inputDialogPeer inputDialogPeer = new TLRPC.TL_inputDialogPeer(); @@ -9317,7 +9495,7 @@ public class MessagesController extends BaseController implements NotificationCe getMessagesStorage().putDialogs(dialogs, 2); } - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, dialog.top_message, 0, threadMessageId, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false, processMessages, isTopic, null); + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, dialog.top_message, 0, threadMessageId, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false, processMessages, isTopic, null, 0L); } } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); @@ -9347,6 +9525,7 @@ public class MessagesController extends BaseController implements NotificationCe req.limit = count; req.offset_id = max_id; req.offset_date = offset_date; +// req.hash = hash; int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; @@ -9365,7 +9544,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } - processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, false, 0, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); + processLoadedMessages(res, res.messages.size(), dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount, processMessages, isTopic, null); } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); } @@ -9375,9 +9554,21 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void reloadWebPages(final long dialogId, HashMap> webpagesToReload, boolean scheduled) { - HashMap> map = scheduled ? reloadingScheduledWebpages : reloadingWebpages; - LongSparseArray> array = scheduled ? reloadingScheduledWebpagesPending : reloadingWebpagesPending; + public void reloadWebPages(final long dialogId, HashMap> webpagesToReload, int mode) { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean saved = mode == ChatActivity.MODE_SAVED; + HashMap> map; + LongSparseArray> array; + if (scheduled) { + map = reloadingScheduledWebpages; + array = reloadingScheduledWebpagesPending; + } else if (saved) { + map = reloadingSavedWebpages; + array = reloadingSavedWebpagesPending; + } else { + map = reloadingWebpages; + array = reloadingWebpagesPending; + } for (HashMap.Entry> entry : webpagesToReload.entrySet()) { String url = entry.getKey(); @@ -9416,7 +9607,7 @@ public class MessagesController extends BaseController implements NotificationCe } } if (!messagesRes.messages.isEmpty()) { - getMessagesStorage().putMessages(messagesRes, dialogId, -2, 0, false, scheduled, 0); + getMessagesStorage().putMessages(messagesRes, dialogId, -2, 0, false, mode, 0); getNotificationCenter().postNotificationName(NotificationCenter.replaceMessagesObjects, dialogId, arrayList1); } })); @@ -9424,9 +9615,9 @@ public class MessagesController extends BaseController implements NotificationCe } public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCount, long dialogId, long mergeDialogId, int count, int max_id, int offset_date, boolean isCache, int classGuid, - int first_unread, int last_message_id, int unread_count, int last_date, int load_type, boolean isEnd, int mode, int threadMessageId, int loadIndex, boolean queryFromServer, int mentionsCount, boolean needProcess, boolean isTopic, MessageLoaderLogger loaderLogger) { + int first_unread, int last_message_id, int unread_count, int last_date, int load_type, boolean isEnd, int mode, long threadMessageId, int loadIndex, boolean queryFromServer, int mentionsCount, boolean needProcess, boolean isTopic, MessageLoaderLogger loaderLogger) { if (BuildVars.LOGS_ENABLED) { - FileLog.d("processLoadedMessages size " + messagesRes.messages.size() + " in chat " + dialogId + " topic_id " + threadMessageId + " count " + count + " max_id " + max_id + " cache " + isCache + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer + " isTopic" + isTopic); + FileLog.d("processLoadedMessages size " + messagesRes.messages.size() + " in chat " + dialogId + " topic_id " + threadMessageId + " count " + count + " max_id " + max_id + " cache " + isCache + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer + " isTopic " + isTopic); } long startProcessTime = SystemClock.elapsedRealtime(); @@ -9464,36 +9655,58 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.Chat c = messagesRes.chats.get(a); chatsDict.put(c.id, c); } - if (mode == 1) { + if (mode == ChatActivity.MODE_SCHEDULED) { reload = ((SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000); + } else if (mode == ChatActivity.MODE_SAVED) { + reload = resCount == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastSavedServerQueryTime.get(threadMessageId, 0L)) > 60 * 1000 || isCache); } else { reload = resCount == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 60 * 1000 || (isCache && isTopic)); } if (!DialogObject.isEncryptedDialog(dialogId) && isCache && reload) { - int hash; - if (mode == 2) { - hash = 0; - } else if (mode == 1) { + if (mode == ChatActivity.MODE_SCHEDULED) { lastScheduledServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); - long h = 0; + } else if (mode == ChatActivity.MODE_SAVED) { + lastSavedServerQueryTime.put(threadMessageId, SystemClock.elapsedRealtime()); + } else if (mode == ChatActivity.MODE_DEFAULT) { + lastServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); + } + long hash = 0; + if (mode == ChatActivity.MODE_SCHEDULED) { for (int a = 0, N = messagesRes.messages.size(); a < N; a++) { TLRPC.Message message = messagesRes.messages.get(a); if (message.id < 0) { continue; } - h = MediaDataController.calcHash(h, message.id); - h = MediaDataController.calcHash(h, message.edit_date); - h = MediaDataController.calcHash(h, message.date); + hash = MediaDataController.calcHash(hash, message.id); + hash = MediaDataController.calcHash(hash, message.edit_date); + hash = MediaDataController.calcHash(hash, message.date); + } + } else if (mode == ChatActivity.MODE_DEFAULT || mode == ChatActivity.MODE_SAVED) { + final boolean includePeers = true; + for (int a = 0, N = messagesRes.messages.size(); a < N; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (message.id < 0) { + continue; + } + if (includePeers) { + hash = MediaDataController.calcHash(hash, Math.abs(DialogObject.getPeerDialogId(message.peer_id))); + } + hash = MediaDataController.calcHash(hash, message.id); + if (message.pinned) { + hash = MediaDataController.calcHash(hash, 1); + } + int date = message.date; + if ((message.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0) { + date = message.edit_date; + } + hash = MediaDataController.calcHash(hash, date); } - hash = (int) h - 1; - } else { - lastServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); - hash = 0; } if (loaderLogger != null) { loaderLogger.reload(); } - AndroidUtilities.runOnUIThread(() -> loadMessagesInternal(dialogId, mergeDialogId, false, count, load_type == 2 && queryFromServer ? first_unread : max_id, offset_date, false, hash, classGuid, load_type, last_message_id, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true, needProcess, isTopic, loaderLogger)); + final long finalHash = hash; + AndroidUtilities.runOnUIThread(() -> loadMessagesInternal(dialogId, mergeDialogId, false, count, load_type == LOAD_FROM_UNREAD && queryFromServer ? first_unread : max_id, offset_date, false, 0, classGuid, load_type, last_message_id, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true, needProcess, isTopic, loaderLogger, finalHash)); if (messagesRes.messages.isEmpty()) { return; } @@ -9534,8 +9747,11 @@ public class MessagesController extends BaseController implements NotificationCe } } } - if (threadMessageId == 0 || isTopic) { - getMessagesStorage().putMessages(messagesRes, dialogId, load_type, max_id, createDialog, mode == 1, threadMessageId); + if (threadMessageId == 0 || isTopic || mode == ChatActivity.MODE_SAVED) { + getMessagesStorage().putMessages(messagesRes, dialogId, load_type, max_id, createDialog, mode, threadMessageId); + } + if (mode == ChatActivity.MODE_SAVED) { + getSavedMessagesController().update(threadMessageId, messagesRes); } } @@ -9552,7 +9768,7 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.Message message = messagesRes.messages.get(a); message.dialog_id = dialogId; long checkFileTime = SystemClock.elapsedRealtime(); - MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, true, false); + MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, true, false, mode == ChatActivity.MODE_SAVED); messageObject.scheduled = mode == 1; objects.add(messageObject); if (isCache) { @@ -9612,7 +9828,7 @@ public class MessagesController extends BaseController implements NotificationCe first_unread_final = 0; } else { first_unread_final = Integer.MAX_VALUE; - if (queryFromServer && load_type == 2) { + if (queryFromServer && load_type == LOAD_FROM_UNREAD) { for (int a = 0; a < messagesRes.messages.size(); a++) { TLRPC.Message message = messagesRes.messages.get(a); if ((!message.out || message.from_scheduled) && message.id > first_unread && message.id < first_unread_final) { @@ -9642,10 +9858,10 @@ public class MessagesController extends BaseController implements NotificationCe } if (!messagesToReload.isEmpty()) { - reloadMessages(messagesToReload, dialogId, mode == 1); + reloadMessages(messagesToReload, dialogId, mode); } if (!webpagesToReload.isEmpty()) { - reloadWebPages(dialogId, webpagesToReload, mode == 1); + reloadWebPages(dialogId, webpagesToReload, mode); } }); } @@ -11151,7 +11367,7 @@ public class MessagesController extends BaseController implements NotificationCe }); } - private void applyDialogNotificationsSettings(long dialogId, int topicId, TLRPC.PeerNotifySettings notify_settings) { + private void applyDialogNotificationsSettings(long dialogId, long topicId, TLRPC.PeerNotifySettings notify_settings) { getNotificationsController().getNotificationsSettingsFacade().applyDialogNotificationsSettings(dialogId, topicId, notify_settings); } @@ -11272,7 +11488,7 @@ public class MessagesController extends BaseController implements NotificationCe if (currentDialog != null) { currentDialog.unread_mentions_count = dialogsMentionsToUpdate.valueAt(a); if (createdDialogMainThreadIds.contains(currentDialog.id)) { - getNotificationCenter().postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, 0, currentDialog.unread_mentions_count); + getNotificationCenter().postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, 0L, currentDialog.unread_mentions_count); } if (!filterDialogsChanged) { for (int b = 0; b < selectedDialogFilter.length; b++) { @@ -11371,7 +11587,7 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.messages.addAll(res.messages); dialogs.count = 1; processDialogsUpdate(dialogs, null, false); - getMessagesStorage().putMessages(res.messages, true, true, false, getDownloadController().getAutodownloadMask(), true, false, 0); + getMessagesStorage().putMessages(res.messages, true, true, false, getDownloadController().getAutodownloadMask(), true, 0, 0); } else { AndroidUtilities.runOnUIThread(() -> { if (BuildVars.LOGS_ENABLED) { @@ -11556,12 +11772,12 @@ public class MessagesController extends BaseController implements NotificationCe if (currentDialog.unread_mentions_count != value.unread_mentions_count) { currentDialog.unread_mentions_count = value.unread_mentions_count; if (createdDialogMainThreadIds.contains(currentDialog.id)) { - getNotificationCenter().postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, 0, currentDialog.unread_mentions_count); + getNotificationCenter().postNotificationName(NotificationCenter.updateMentionsCount, currentDialog.id, 0L, currentDialog.unread_mentions_count); } } if (currentDialog.unread_reactions_count != value.unread_reactions_count) { currentDialog.unread_reactions_count = value.unread_reactions_count; - getNotificationCenter().postNotificationName(NotificationCenter.dialogsUnreadReactionsCounterChanged, currentDialog.id, 0, currentDialog.unread_reactions_count, null); + getNotificationCenter().postNotificationName(NotificationCenter.dialogsUnreadReactionsCounterChanged, currentDialog.id, 0L, currentDialog.unread_reactions_count, null); } ArrayList oldMsgs = dialogMessage.get(key); boolean oldMsgsDeleted = false; @@ -11691,6 +11907,7 @@ public class MessagesController extends BaseController implements NotificationCe } public void addToViewsQueue(MessageObject messageObject) { + if (messageObject == null) return; Utilities.stageQueue.postRunnable(() -> { long peer = messageObject.getDialogId(); int id = messageObject.getId(); @@ -11982,7 +12199,7 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void markDialogAsReadNow(long dialogId, int replyId) { + public void markDialogAsReadNow(long dialogId, long replyId) { Utilities.stageQueue.postRunnable(() -> { if (replyId != 0) { String key = dialogId + "_" + replyId; @@ -12005,15 +12222,15 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void markMentionsAsRead(long dialogId, int topicId) { - if (DialogObject.isEncryptedDialog(dialogId)) { + public void markMentionsAsRead(long dialogId, long topicId) { + if (DialogObject.isEncryptedDialog(dialogId) || dialogId == getUserConfig().getClientUserId()) { return; } getMessagesStorage().resetMentionsCount(dialogId, topicId, 0); TLRPC.TL_messages_readMentions req = new TLRPC.TL_messages_readMentions(); req.peer = getInputPeer(dialogId); if (topicId != 0) { - req.top_msg_id = topicId; + req.top_msg_id = (int) topicId; req.flags |= 1; } getConnectionsManager().sendRequest(req, (response, error) -> { @@ -12021,7 +12238,7 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void markDialogAsRead(long dialogId, int maxPositiveId, int maxNegativeId, int maxDate, boolean popup, int threadId, int countDiff, boolean readNow, int scheduledCount) { + public void markDialogAsRead(long dialogId, int maxPositiveId, int maxNegativeId, int maxDate, boolean popup, long threadId, int countDiff, boolean readNow, int scheduledCount) { boolean createReadTask; if (threadId != 0) { @@ -13715,7 +13932,7 @@ public class MessagesController extends BaseController implements NotificationCe if (!pushMessages.isEmpty()) { AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, true, false, null)); } - getMessagesStorage().putMessages(res.new_messages, true, false, false, getDownloadController().getAutodownloadMask(), false, 0); + getMessagesStorage().putMessages(res.new_messages, true, false, false, getDownloadController().getAutodownloadMask(), 0, 0); }); } @@ -13984,7 +14201,7 @@ public class MessagesController extends BaseController implements NotificationCe if (!pushMessages.isEmpty()) { AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, !(res instanceof TLRPC.TL_updates_differenceSlice), false, null)); } - getMessagesStorage().putMessages(res.new_messages, true, false, false, getDownloadController().getAutodownloadMask(), false, 0); + getMessagesStorage().putMessages(res.new_messages, true, false, false, getDownloadController().getAutodownloadMask(), 0, 0); for (int a = 0; a < messages.size(); a++) { long dialogId = messages.keyAt(a); @@ -14505,8 +14722,7 @@ public class MessagesController extends BaseController implements NotificationCe MessageObject obj = new MessageObject(currentAccount, message, 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); + getMessagesStorage().putMessages(messagesArr, true, true, false, 0, 0, 0); AndroidUtilities.runOnUIThread(() -> { updateInterfaceWithMessages(-chatId, pushMessages, false); @@ -14604,7 +14820,7 @@ public class MessagesController extends BaseController implements NotificationCe 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); + getMessagesStorage().putMessages(messagesArr, true, true, false, 0, 0, 0); } else { pushMessages = null; } @@ -14949,7 +15165,7 @@ public class MessagesController extends BaseController implements NotificationCe if (!obj.isOut()) { getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(objArr, true, false, null))); } - getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, 0, 0); } else if (getMessagesStorage().getLastPtsValue() != updates.pts) { if (BuildVars.LOGS_ENABLED) { FileLog.d("need get diff short message, pts: " + getMessagesStorage().getLastPtsValue() + " " + updates.pts + " count = " + updates.pts_count); @@ -16402,12 +16618,12 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updateLangPackTooLong) { TLRPC.TL_updateLangPackTooLong update = (TLRPC.TL_updateLangPackTooLong) baseUpdate; LocaleController.getInstance().reloadCurrentRemoteLocale(currentAccount, update.lang_code, false, null); - } else if (baseUpdate instanceof TLRPC.TL_updateRecentReactions) { + } else if (baseUpdate instanceof TLRPC.TL_updateRecentReactions || baseUpdate instanceof TLRPC.TL_updateSavedReactionTags) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); - }if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { + } else if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); } @@ -16579,6 +16795,16 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new ArrayList<>(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updatePinnedSavedDialogs) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateSavedDialogPinned) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -16608,12 +16834,12 @@ public class MessagesController extends BaseController implements NotificationCe } if (scheduledMessagesArr != null) { - getMessagesStorage().putMessages(scheduledMessagesArr, true, true, false, getDownloadController().getAutodownloadMask(), true, 0); + getMessagesStorage().putMessages(scheduledMessagesArr, true, true, false, getDownloadController().getAutodownloadMask(), 1, 0); } if (messagesArr != null) { getStatsController().incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_MESSAGES, messagesArr.size()); - getMessagesStorage().putMessages(messagesArr, true, true, false, getDownloadController().getAutodownloadMask(), false, 0); + getMessagesStorage().putMessages(messagesArr, true, true, false, getDownloadController().getAutodownloadMask(), 0, 0); } if (editingMessages != null) { for (int b = 0, size = editingMessages.size(); b < size; b++) { @@ -16622,7 +16848,7 @@ public class MessagesController extends BaseController implements NotificationCe for (int a = 0, size2 = messageObjects.size(); a < size2; a++) { messagesRes.messages.add(messageObjects.get(a).messageOwner); } - getMessagesStorage().putMessages(messagesRes, editingMessages.keyAt(b), -2, 0, false, false, 0); + getMessagesStorage().putMessages(messagesRes, editingMessages.keyAt(b), -2, 0, false, 0, 0); } LongSparseArray> editingMessagesFinal = editingMessages; getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { @@ -16870,7 +17096,7 @@ public class MessagesController extends BaseController implements NotificationCe int currentTime1 = getConnectionsManager().getCurrentTime(); if (update.peer instanceof TLRPC.TL_notifyPeer || update.peer instanceof TLRPC.TL_notifyForumTopic) { long dialogId; - int topicId = 0; + long topicId = 0; if (update.peer instanceof TLRPC.TL_notifyPeer) { TLRPC.TL_notifyPeer notifyPeer = (TLRPC.TL_notifyPeer) update.peer; if (notifyPeer.peer.user_id != 0) { @@ -17056,6 +17282,8 @@ public class MessagesController extends BaseController implements NotificationCe getMediaDataController().reorderStickers(type, ((TLRPC.TL_updateStickerSetsOrder) baseUpdate).order, false); } else if (baseUpdate instanceof TLRPC.TL_updateRecentReactions) { getMediaDataController().loadRecentAndTopReactions(true); + } else if (baseUpdate instanceof TLRPC.TL_updateRecentReactions) { + getMediaDataController().loadSavedReactions(true); } else if (baseUpdate instanceof TLRPC.TL_updateFavedStickers) { getMediaDataController().loadRecents(MediaDataController.TYPE_FAVE, false, false, true); } else if (baseUpdate instanceof TLRPC.TL_updateContactsReset) { @@ -17412,6 +17640,8 @@ public class MessagesController extends BaseController implements NotificationCe } else { getMessagesStorage().setDialogViewThreadAsMessages(-update.channel_id, update.enabled); } + } else if (baseUpdate instanceof TLRPC.TL_updatePinnedSavedDialogs || baseUpdate instanceof TLRPC.TL_updateSavedDialogPinned) { + getSavedMessagesController().processUpdate(baseUpdate); } } if (editor != null) { @@ -17442,9 +17672,22 @@ public class MessagesController extends BaseController implements NotificationCe } if (webPagesFinal != null) { getNotificationCenter().postNotificationName(NotificationCenter.didReceivedWebpagesInUpdates, webPagesFinal); - for (int i = 0; i < 2; i++) { - HashMap> map = i == 1 ? reloadingScheduledWebpages : reloadingWebpages; - LongSparseArray> array = i == 1 ? reloadingScheduledWebpagesPending : reloadingWebpagesPending; + for (int i = 0; i < 3; i++) { + HashMap> map; + LongSparseArray> array; + int mode = 0; + if (i == 1) { + mode = ChatActivity.MODE_SCHEDULED; + map = reloadingScheduledWebpages; + array = reloadingScheduledWebpagesPending; + } else if (i == 2) { + mode = ChatActivity.MODE_SAVED; + map = reloadingSavedWebpages; + array = reloadingSavedWebpagesPending; + } else { + map = reloadingWebpages; + array = reloadingWebpagesPending; + } for (int b = 0, size = webPagesFinal.size(); b < size; b++) { long key = webPagesFinal.keyAt(b); @@ -17467,7 +17710,7 @@ public class MessagesController extends BaseController implements NotificationCe array.put(webpage.id, arrayList); } if (!arr.isEmpty()) { - getMessagesStorage().putMessages(arr, true, true, false, getDownloadController().getAutodownloadMask(), i == 1, 0); + getMessagesStorage().putMessages(arr, true, true, false, getDownloadController().getAutodownloadMask(), mode, 0); getNotificationCenter().postNotificationName(NotificationCenter.replaceMessagesObjects, dialogId, arrayList); } } @@ -17757,7 +18000,7 @@ public class MessagesController extends BaseController implements NotificationCe } if (topicsReadInbox != null) { for (MessagesStorage.TopicKey topicKey : topicsReadInbox.keySet()) { - getMessagesStorage().updateRepliesMaxReadId(-topicKey.dialogId, topicKey.topicId, topicsReadInbox.get(topicKey), -1, true); + getMessagesStorage().updateRepliesMaxReadId(-topicKey.dialogId, (int) topicKey.topicId, topicsReadInbox.get(topicKey), -1, true); } } if (topicsReadOutbox != null) { @@ -17810,7 +18053,7 @@ public class MessagesController extends BaseController implements NotificationCe return true; } - public void checkUnreadReactions(long dialogId, int topicId, SparseBooleanArray unreadReactions) { + public void checkUnreadReactions(long dialogId, long topicId, SparseBooleanArray unreadReactions) { getMessagesStorage().getStorageQueue().postRunnable(() -> { boolean needReload = false; boolean changed = false; @@ -17873,7 +18116,7 @@ public class MessagesController extends BaseController implements NotificationCe state.bindInteger(1, messageId); state.bindInteger(2, hasUnreadReaction ? 1 : 0); state.bindLong(3, dialogId); - state.bindInteger(4, topicId); + state.bindLong(4, topicId); state.step(); state.dispose(); } @@ -17905,7 +18148,7 @@ public class MessagesController extends BaseController implements NotificationCe }); } else { TLRPC.TL_channels_getForumTopicsByID req = new TLRPC.TL_channels_getForumTopicsByID(); - req.topics.add(topicId); + req.topics.add((int) topicId); req.channel = getMessagesController().getInputChannel(-dialogId); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { @@ -17944,15 +18187,15 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public boolean isDialogMuted(long dialogId, int topicId) { + public boolean isDialogMuted(long dialogId, long topicId) { return isDialogMuted(dialogId, topicId, null); } - public boolean isDialogNotificationsSoundEnabled(long dialogId, int topicId) { + public boolean isDialogNotificationsSoundEnabled(long dialogId, long topicId) { return notificationsPreferences.getBoolean("sound_enabled_" + NotificationsController.getSharedPrefKey(dialogId, topicId), true); } - public boolean isDialogMuted(long dialogId, int topicId, TLRPC.Chat chat) { + public boolean isDialogMuted(long dialogId, long topicId, TLRPC.Chat chat) { int mute_type = notificationsPreferences.getInt("notify2_" + NotificationsController.getSharedPrefKey(dialogId, topicId), -1); if (mute_type == -1) { Boolean forceChannel; @@ -17978,7 +18221,7 @@ public class MessagesController extends BaseController implements NotificationCe return false; } - public void markReactionsAsRead(long dialogId, int topicId) { + public void markReactionsAsRead(long dialogId, long topicId) { if (topicId == 0) { TLRPC.Dialog dialog = dialogs_dict.get(dialogId); if (dialog != null) { @@ -17991,7 +18234,7 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.TL_messages_readReactions req = new TLRPC.TL_messages_readReactions(); req.peer = getInputPeer(dialogId); if (topicId != 0) { - req.top_msg_id = topicId; + req.top_msg_id = (int) topicId; } getConnectionsManager().sendRequest(req, (response, error) -> { @@ -18162,22 +18405,22 @@ public class MessagesController extends BaseController implements NotificationCe return peerUser; } - public CharSequence getPrintingString(long dialogId, int threadId, boolean isDialog) { + public CharSequence getPrintingString(long dialogId, long threadId, boolean isDialog) { if (isDialog && DialogObject.isUserDialog(dialogId)) { TLRPC.User user = getUser(dialogId); if (user != null && user.status != null && user.status.expires < 0) { return null; } } - SparseArray threads = printingStrings.get(dialogId); + LongSparseArray threads = printingStrings.get(dialogId); if (threads == null) { return null; } return threads.get(threadId); } - public Integer getPrintingStringType(long dialogId, int threadId) { - SparseArray threads = printingStringsTypes.get(dialogId); + public Integer getPrintingStringType(long dialogId, long threadId) { + LongSparseArray threads = printingStringsTypes.get(dialogId); if (threads == null) { return null; } @@ -19037,9 +19280,9 @@ public class MessagesController extends BaseController implements NotificationCe int lastMessageId = (int) args[4]; if ((size < count / 2 && !isEnd) && isCache) { if (finalMessageId != 0) { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 3, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null, 0L); } else { - loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null); + loadMessagesInternal(dialogId, 0, false, count, finalMessageId, 0, false, 0, classGuid, 2, lastMessageId, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null, 0L); } } else { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoadWithoutProcess); @@ -19063,9 +19306,9 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().addObserver(delegate, NotificationCenter.loadingMessagesFailed); if (messageId != 0) { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 3, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null, 0L); } else { - loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null); + loadMessagesInternal(dialogId, 0, true, count, finalMessageId, 0, true, 0, classGuid, 2, 0, 0, 0, -1, 0, 0, 0, false, 0, true, false, false, null, 0L); } } @@ -19142,7 +19385,7 @@ public class MessagesController extends BaseController implements NotificationCe if (onSuccess != null) { onSuccess.run(); } - getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0); + getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0L); }); } else { AndroidUtilities.runOnUIThread(() -> { @@ -19184,7 +19427,7 @@ public class MessagesController extends BaseController implements NotificationCe full.available_reactions = req.available_reactions; getMessagesStorage().updateChatInfo(full, false); } - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0)); + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0L)); } }); } @@ -19386,7 +19629,7 @@ public class MessagesController extends BaseController implements NotificationCe } } - public String getMutedString(long dialogId, int topicId) { + public String getMutedString(long dialogId, long topicId) { if (getMessagesController().isDialogMuted(dialogId, topicId)) { int mute_until = notificationsPreferences.getInt("notifyuntil_" + NotificationsController.getSharedPrefKey(dialogId, topicId), 0); if (mute_until >= getConnectionsManager().getCurrentTime()) { @@ -19598,6 +19841,19 @@ public class MessagesController extends BaseController implements NotificationCe return storiesController; } + public SavedMessagesController getSavedMessagesController() { + if (savedMessagesController != null) { + return savedMessagesController; + } + synchronized (lockObjects[currentAccount]) { + if (savedMessagesController != null) { + return savedMessagesController; + } + savedMessagesController = new SavedMessagesController(currentAccount); + } + return savedMessagesController; + } + public UnconfirmedAuthController getUnconfirmedAuthController() { if (unconfirmedAuthController != null) { return unconfirmedAuthController; @@ -19704,6 +19960,129 @@ public class MessagesController extends BaseController implements NotificationCe return rec; } + private boolean loadedReactionTags; + private TLRPC.TL_messages_savedReactionsTags reactionTags; + public void updateSavedReactionTags(ReactionsLayoutInBubble.VisibleReaction reaction, boolean add) { + if (reactionTags != null) { + boolean changed = false; + boolean found = false; + for (int i = 0; i < reactionTags.tags.size(); ++i) { + TLRPC.TL_savedReactionTag tag = reactionTags.tags.get(i); + if (reaction.isSame(tag.reaction)) { + found = true; + int wasCount = tag.count; + tag.count = Math.max(0, tag.count + (add ? +1 : -1)); + if (tag.count <= 0) { + reactionTags.tags.remove(i); + i--; + changed = true; + } else if (tag.count != wasCount) { + changed = true; + } + } + } + if (!found && add) { + TLRPC.TL_savedReactionTag tag = new TLRPC.TL_savedReactionTag(); + tag.reaction = reaction.toTLReaction(); + tag.count = 1; + reactionTags.tags.add(tag); + changed = true; + } + if (changed) { + Collections.sort(reactionTags.tags, (a, b) -> b.count - a.count); + long hash = 0; + for (int i = 0; i < reactionTags.tags.size(); ++i) { + TLRPC.TL_savedReactionTag tag = reactionTags.tags.get(i); + if (tag.count <= 0) continue; + if (tag.reaction instanceof TLRPC.TL_reactionEmoji) { + String md5 = Utilities.MD5(((TLRPC.TL_reactionEmoji) tag.reaction).emoticon); + hash = MediaDataController.calcHash(hash, Long.parseLong(md5.substring(0, 16), 16)); + } else if (tag.reaction instanceof TLRPC.TL_reactionCustomEmoji) { + hash = MediaDataController.calcHash(hash, ((TLRPC.TL_reactionCustomEmoji) tag.reaction).document_id); + } + if ((tag.flags & 1) != 0 && tag.title != null) { + hash = MediaDataController.calcHash(hash, Long.parseLong(Utilities.MD5(tag.title).substring(0, 16), 16)); + } + hash = MediaDataController.calcHash(hash, tag.count); + } + reactionTags.hash = hash; + saveSavedReactionsTags(reactionTags); + getNotificationCenter().postNotificationName(NotificationCenter.savedReactionTagsUpdate); + } + } + } + public TLRPC.TL_messages_savedReactionsTags getSavedReactionTags() { + if (loadedReactionTags) { + return reactionTags; + } + loadedReactionTags = true; + getMessagesStorage().getStorageQueue().postRunnable(() -> { + TLRPC.messages_SavedReactionTags result = null; + SQLiteDatabase database = getMessagesStorage().getDatabase(); + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM saved_reaction_tags")); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + result = TLRPC.messages_SavedReactionTags.TLdeserialize(data, data.readInt32(true), true); + } + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + cursor = null; + } + } + + final TLRPC.messages_SavedReactionTags finalResult = result; + AndroidUtilities.runOnUIThread(() -> { + if (finalResult instanceof TLRPC.TL_messages_savedReactionsTags) { + reactionTags = (TLRPC.TL_messages_savedReactionsTags) finalResult; + getNotificationCenter().postNotificationName(NotificationCenter.savedReactionTagsUpdate); + } + + TLRPC.TL_messages_getSavedReactionTags req = new TLRPC.TL_messages_getSavedReactionTags(); + if (finalResult instanceof TLRPC.TL_messages_savedReactionsTags) { + req.hash = finalResult.hash; + } + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.TL_messages_savedReactionsTags) { + reactionTags = (TLRPC.TL_messages_savedReactionsTags) res; + getNotificationCenter().postNotificationName(NotificationCenter.savedReactionTagsUpdate); + saveSavedReactionsTags(reactionTags); + } + })); + }); + }); + return null; + } + + private void saveSavedReactionsTags(TLRPC.TL_messages_savedReactionsTags res) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + SQLiteDatabase database2 = getMessagesStorage().getDatabase(); + SQLitePreparedStatement state = null; + try { + database2.executeFast("DELETE FROM saved_reaction_tags WHERE 1").stepThis().dispose(); + state = database2.executeFast("REPLACE INTO saved_reaction_tags VALUES(?)"); + state.requery(); + NativeByteBuffer buffer = new NativeByteBuffer(res.getObjectSize()); + res.serializeToStream(buffer); + state.bindByteBuffer(1, buffer); + state.step(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); + state = null; + } + } + }); + } + public void checkPeerColors(boolean force) { if (peerColors == null || peerColors.needUpdate() || force) { TLRPC.TL_help_getPeerColors req = new TLRPC.TL_help_getPeerColors(); @@ -19736,4 +20115,89 @@ public class MessagesController extends BaseController implements NotificationCe }); } } + + private LongSparseArray cachedIsUserPremiumBlocked = new LongSparseArray<>(); + private HashSet loadingIsUserPremiumBlocked = new HashSet<>(); + public boolean isUserPremiumBlocked(long userId) { + return isUserPremiumBlocked(userId, false); + } + public boolean isUserPremiumBlocked(long userId, boolean cache) { + if (getUserConfig().isPremium()) { + return false; + } + Boolean cached = cachedIsUserPremiumBlocked.get(userId); + if (cached != null) + return cached; + TLRPC.User user = getUser(userId); + if (user != null && !user.contact_require_premium) + return false; + TLRPC.UserFull userFull = getUserFull(userId); + if (userFull != null) + return userFull.contact_require_premium; + if (getInputUser(userId) == null) + return false; + if (cache) + return false; + loadingIsUserPremiumBlocked.add(userId); + AndroidUtilities.cancelRunOnUIThread(requestIsUserPremiumBlockedRunnable); + AndroidUtilities.runOnUIThread(requestIsUserPremiumBlockedRunnable, 60); + return false; + } + + public void invalidateUserPremiumBlocked(long userId, int classGuid) { + if (loadingFullUsers.contains(userId)) { + return; + } + int index = loadedFullUsers.indexOfKey(userId); + if (index >= 0) { + loadedFullUsers.removeAt(index); + } + loadFullUser(getUser(userId), classGuid, true); + } + + private Runnable requestIsUserPremiumBlockedRunnable = this::requestIsUserPremiumBlocked; + private void requestIsUserPremiumBlocked() { + if (loadingIsUserPremiumBlocked.isEmpty()) return; + TLRPC.TL_users_getIsPremiumRequiredToContact req = new TLRPC.TL_users_getIsPremiumRequiredToContact(); + final ArrayList ids = new ArrayList<>(); + for (long userId : loadingIsUserPremiumBlocked) { + TLRPC.InputUser inputUser = getInputUser(userId); + if (inputUser != null) { + req.id.add(inputUser); + ids.add(userId); + } + } + loadingIsUserPremiumBlocked.clear(); + if (req.id.isEmpty()) { + return; + } + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + boolean changed = false; + if (res instanceof TLRPC.Vector) { + ArrayList objects = ((TLRPC.Vector) res).objects; + for (int i = 0; i < Math.min(ids.size(), objects.size()); ++i) { + long userId = ids.get(i); + boolean blocked = objects.get(i) instanceof TLRPC.TL_boolTrue; + Boolean pastBlocked = cachedIsUserPremiumBlocked.get(userId); + if (pastBlocked == null || pastBlocked != blocked) { + cachedIsUserPremiumBlocked.put(userId, blocked); + changed = true; + } + + TLRPC.UserFull userFull = getUserFull(userId); + if (userFull != null && userFull.contact_require_premium != blocked) { + userFull.contact_require_premium = blocked; + getMessagesStorage().updateUserInfo(userFull, true); + changed = true; + } else if (userFull == null) { + getMessagesStorage().updateUserInfoPremiumBlocked(userId, blocked); + changed = true; + } + } + } + if (changed) { + getNotificationCenter().postNotificationName(NotificationCenter.userIsPremiumBlockedUpadted); + } + })); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index ace1a6c24..726e9b46d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -8,6 +8,12 @@ package org.telegram.messenger; +import static org.telegram.messenger.MessagesController.LOAD_AROUND_DATE; +import static org.telegram.messenger.MessagesController.LOAD_AROUND_MESSAGE; +import static org.telegram.messenger.MessagesController.LOAD_BACKWARD; +import static org.telegram.messenger.MessagesController.LOAD_FORWARD; +import static org.telegram.messenger.MessagesController.LOAD_FROM_UNREAD; + import android.appwidget.AppWidgetManager; import android.content.SharedPreferences; import android.os.SystemClock; @@ -36,6 +42,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DialogsSearchAdapter; +import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; import org.telegram.ui.EditWidgetActivity; @@ -97,7 +104,7 @@ public class MessagesStorage extends BaseController { } } - public final static int LAST_DB_VERSION = 136; + public final static int LAST_DB_VERSION = 139; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -494,6 +501,7 @@ public class MessagesStorage extends BaseController { "emoji_statuses", "messages_holes_topics", "messages_topics", + "saved_dialogs", "media_topics", "media_holes_topics", "topics", @@ -527,6 +535,12 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE INDEX IF NOT EXISTS idx_to_reply_messages_v2 ON messages_v2(reply_to_message_id, mid);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_groupid_messages_v2 ON messages_v2(uid, mid, group_id);").stepThis().dispose(); + database.executeFast("CREATE TABLE saved_dialogs(did INTEGER PRIMARY KEY, date INTEGER, last_mid INTEGER, pinned INTEGER, flags INTEGER, folder_id INTEGER, last_mid_group INTEGER, count INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON saved_dialogs(date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON saved_dialogs(last_mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS folder_id_idx_dialogs ON saved_dialogs(folder_id);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS flags_idx_dialogs ON saved_dialogs(flags);").stepThis().dispose(); + database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, parent TEXT, PRIMARY KEY (uid, type));").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); @@ -623,7 +637,7 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE wallpapers2(uid INTEGER PRIMARY KEY, data BLOB, num INTEGER)").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS wallpapers_num ON wallpapers2(num);").stepThis().dispose(); - database.executeFast("CREATE TABLE unread_push_messages(uid INTEGER, mid INTEGER, random INTEGER, date INTEGER, data BLOB, fm TEXT, name TEXT, uname TEXT, flags INTEGER, topicId INTEGER, PRIMARY KEY(uid, mid))").stepThis().dispose(); + database.executeFast("CREATE TABLE unread_push_messages(uid INTEGER, mid INTEGER, random INTEGER, date INTEGER, data BLOB, fm TEXT, name TEXT, uname TEXT, flags INTEGER, topicId INTEGER, is_reaction INTEGER, PRIMARY KEY(uid, mid))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS unread_push_messages_idx_date ON unread_push_messages(date);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS unread_push_messages_idx_random ON unread_push_messages(random);").stepThis().dispose(); @@ -690,6 +704,8 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE unconfirmed_auth (data BLOB);").stepThis().dispose(); + database.executeFast("CREATE TABLE saved_reaction_tags (data BLOB);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = " + MessagesStorage.LAST_DB_VERSION).stepThis().dispose(); } @@ -1277,7 +1293,7 @@ public class MessagesStorage extends BaseController { flags |= 2; } - SQLitePreparedStatement state = database.executeFast("REPLACE INTO unread_push_messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO unread_push_messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); state.requery(); state.bindLong(1, message.getDialogId()); state.bindInteger(2, message.getId()); @@ -1300,7 +1316,8 @@ public class MessagesStorage extends BaseController { state.bindString(8, message.localUserName); } state.bindInteger(9, flags); - state.bindInteger(10, MessageObject.getTopicId(message.messageOwner, false)); + state.bindLong(10, MessageObject.getTopicId(currentAccount, message.messageOwner, false)); + state.bindInteger(11, message.isReactionPush ? 1 : 0); state.step(); data.reuse(); @@ -1328,6 +1345,7 @@ public class MessagesStorage extends BaseController { database.executeFast("DELETE FROM stickersets2").stepThis().dispose(); database.executeFast("DELETE FROM messages_holes_topics").stepThis().dispose(); database.executeFast("DELETE FROM messages_topics").stepThis().dispose(); + database.executeFast("DELETE FROM saved_dialogs").stepThis().dispose(); database.executeFast("DELETE FROM topics").stepThis().dispose(); database.executeFast("DELETE FROM media_holes_topics").stepThis().dispose(); database.executeFast("DELETE FROM media_topics").stepThis().dispose(); @@ -1414,6 +1432,9 @@ public class MessagesStorage extends BaseController { database.executeFast("PRAGMA journal_size_limit = -1").stepThis().dispose(); getMessagesController().getTopicsController().databaseCleared(); + AndroidUtilities.runOnUIThread(() -> { + getMessagesController().getSavedMessagesController().cleanup(); + }); } catch (Exception e) { checkSQLException(e); } finally { @@ -1878,6 +1899,58 @@ public class MessagesStorage extends BaseController { } + public void getSavedDialogMaxMessageId(long dialog_id, IntCallback callback) { + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + int[] max = new int[1]; + try { + final long selfId = getUserConfig().getClientUserId(); + cursor = database.queryFinalized("SELECT MAX(mid) FROM messages_topics WHERE uid = ? AND topic_id = ?", selfId, dialog_id); + if (cursor.next()) { + max[0] = cursor.intValue(0); + } + } catch (Exception e) { + checkSQLException(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + AndroidUtilities.runOnUIThread(() -> callback.run(max[0])); + }); + } + + public void deleteSavedDialog(long did) { + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + long selfId = getUserConfig().getClientUserId(); + cursor = database.queryFinalized("SELECT mid FROM messages_topics WHERE uid = ? AND topic_id = ?", selfId, did); + ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + final int mid = cursor.intValue(0); + mids.add(mid); + } + cursor.dispose(); + cursor = null; + if (!mids.isEmpty()) { + database.executeFast("DELETE FROM messages_v2 WHERE uid = " + selfId + " AND mid IN ("+TextUtils.join(",", mids)+")").stepThis().dispose(); + database.executeFast("DELETE FROM messages_topics WHERE uid = " + selfId + " AND topic_id = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v4 WHERE uid = " + selfId + " AND mid IN ("+TextUtils.join(",", mids)+")").stepThis().dispose(); + } + if (!mids.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.messagesDeleted, mids, 0L, false)); + } + } catch (Exception e) { + checkSQLException(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + }); + } + public void removeTopic(long dialogId, int topicId) { storageQueue.postRunnable(() -> { try { @@ -1959,6 +2032,7 @@ public class MessagesStorage extends BaseController { AndroidUtilities.runOnUIThread(() -> { getNotificationCenter().postNotificationName(NotificationCenter.onDatabaseReset); getNotificationCenter().postNotificationName(NotificationCenter.didClearDatabase); + getMessagesController().getSavedMessagesController().cleanup(); }); }); @@ -3518,7 +3592,7 @@ public class MessagesStorage extends BaseController { cursor = null; database.executeFast("DELETE FROM unread_push_messages WHERE date <= " + maxDate).stepThis().dispose(); - cursor = database.queryFinalized("SELECT data, mid, date, uid, random, fm, name, uname, flags, topicId FROM unread_push_messages WHERE 1 ORDER BY date DESC LIMIT 50"); + cursor = database.queryFinalized("SELECT data, mid, date, uid, random, fm, name, uname, flags, topicId, is_reaction FROM unread_push_messages WHERE 1 ORDER BY date DESC LIMIT 50"); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -3554,7 +3628,9 @@ public class MessagesStorage extends BaseController { message.reply_to.reply_to_top_id = topicId; } - pushMessages.add(new MessageObject(currentAccount, message, messageText, name, userName, (flags & 1) != 0, (flags & 2) != 0, (message.flags & 0x80000000) != 0, false)); + MessageObject messageObject = new MessageObject(currentAccount, message, messageText, name, userName, (flags & 1) != 0, (flags & 2) != 0, (message.flags & 0x80000000) != 0, false); + messageObject.isReactionPush = cursor.intValue(10) != 0; + pushMessages.add(messageObject); addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, null); } } @@ -4239,11 +4315,13 @@ public class MessagesStorage extends BaseController { storageQueue.postRunnable(() -> { SQLiteCursor cursor = null; SQLitePreparedStatement state = null; + SQLitePreparedStatement state_saved = null; try { ArrayList filesToDelete = new ArrayList<>(); ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); ArrayList messages = new ArrayList<>(); + ArrayList changedSavedMessages = null; cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid, custom_params FROM messages_v2 WHERE mid IN (%s) AND uid = %d", TextUtils.join(",", mids), dialogId)); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); @@ -4359,8 +4437,10 @@ public class MessagesStorage extends BaseController { storyData.reuse(); } } - state.dispose(); - state = null; + if (state != null) { + state.dispose(); + state = null; + } AndroidUtilities.runOnUIThread(() -> { for (int a = 0; a < messages.size(); a++) { getNotificationCenter().postNotificationName(NotificationCenter.updateMessageMedia, messages.get(a)); @@ -4369,6 +4449,14 @@ public class MessagesStorage extends BaseController { } AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, 0); + if (changedSavedMessages != null) { + final ArrayList finalChangedSavedMessages = changedSavedMessages; + AndroidUtilities.runOnUIThread(() -> { + if (getMessagesController().getSavedMessagesController().updateSavedDialogs(finalChangedSavedMessages)) { + getMessagesController().getSavedMessagesController().update(); + } + }); + } } catch (Exception e) { checkSQLException(e); } finally { @@ -4414,12 +4502,14 @@ public class MessagesStorage extends BaseController { boolean foundMessage = false; for (int k = 0; k < 2; k++) { boolean isTopic = k == 1; + SQLitePreparedStatement currentState; if (isTopic) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM messages_topics WHERE mid = %d AND uid = %d", mid, dialogId)); + currentState = state_topics; } else { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM messages_v2 WHERE mid = %d AND uid = %d", mid, dialogId)); + currentState = state; } - SQLitePreparedStatement currentState = isTopic ? state_topics : state; if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -4456,6 +4546,7 @@ public class MessagesStorage extends BaseController { } } state.dispose(); + state_topics.dispose(); database.commitTransaction(); } } catch (Exception e) { @@ -4820,13 +4911,13 @@ public class MessagesStorage extends BaseController { database.executeFast(String.format(Locale.US, "UPDATE messages_topics SET read_state = read_state | 2 WHERE mid = %d AND uid = %d", messageId, dialogId)).stepThis().dispose(); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM messages_topics WHERE mid = %d AND uid = %d", messageId, dialogId)); - int topicId = 0; + long topicId = 0; while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); data.reuse(); - topicId = MessageObject.getTopicId(message, isForum(dialogId)); + topicId = MessageObject.getTopicId(currentAccount, message, isForum(dialogId)); } } cursor.dispose(); @@ -4866,7 +4957,7 @@ public class MessagesStorage extends BaseController { }); } - public void resetMentionsCount(long did, int topicId, int count) { + public void resetMentionsCount(long did, long topicId, int count) { storageQueue.postRunnable(() -> { SQLiteCursor cursor = null; try { @@ -5587,7 +5678,7 @@ public class MessagesStorage extends BaseController { } if (filter != null) { if (!filter.alwaysShow.isEmpty()) { - if ((flags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED) != 0) { + if ((flags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED) != 0 && dialogsToUpdateMentions != null) { for (int b = 0, N2 = dialogsToUpdateMentions.size(); b < N2; b++) { long did = dialogsToUpdateMentions.keyAt(b); TLRPC.Chat chat = chatsDict.get(-did); @@ -6312,6 +6403,51 @@ public class MessagesStorage extends BaseController { }); } + public void updateUserInfoPremiumBlocked(long userId, boolean contact_require_premium) { + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + SQLitePreparedStatement state = null; + try { + TLRPC.UserFull userFull = null; + cursor = database.queryFinalized("SELECT uid, info, pinned FROM user_settings WHERE uid = " + userId); + boolean exist = cursor.next(); + if (exist) { + NativeByteBuffer data = cursor.byteBufferValue(1); + userFull = TLRPC.UserFull.TLdeserialize(data, data.readInt32(true), true); + if (userFull != null) { + userFull.pinned_msg_id = cursor.intValue(2); + } + data.reuse(); + } + cursor.dispose(); + cursor = null; + if (!exist || userFull == null || userFull.contact_require_premium == contact_require_premium) { + return; + } + userFull.contact_require_premium = contact_require_premium; + state = database.executeFast("REPLACE INTO user_settings VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(userFull.getObjectSize()); + userFull.serializeToStream(data); + state.bindLong(1, userId); + state.bindByteBuffer(2, data); + state.bindInteger(3, userFull.pinned_msg_id); + state.step(); + state.dispose(); + state = null; + data.reuse(); + } catch (Exception e) { + checkSQLException(e); + } finally { + if (state != null) { + state.dispose(); + } + if (cursor != null) { + cursor.dispose(); + } + } + }); + } + public void saveChatInviter(long chatId, long inviterId) { storageQueue.postRunnable(() -> { SQLitePreparedStatement state = null; @@ -7647,7 +7783,7 @@ public class MessagesStorage extends BaseController { return result[0]; } - public void getUnreadMention(long dialog_id, int topicId, IntCallback callback) { + public void getUnreadMention(long dialog_id, long topicId, IntCallback callback) { storageQueue.postRunnable(() -> { SQLiteCursor cursor = null; try { @@ -7690,12 +7826,15 @@ public class MessagesStorage extends BaseController { } catch (Exception e) { checkSQLException(e); } finally { - cursor.dispose(); + if (cursor != null) { + cursor.dispose(); + cursor = null; + } } }); } - public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count, int max_id, int offset_date, int minDate, int classGuid, int load_type, boolean scheduled, int threadMessageId, int loadIndex, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger) { + public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count, int max_id, int offset_date, int minDate, int classGuid, int load_type, int mode, long threadMessageId, int loadIndex, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger) { TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages(); long currentUserId = getUserConfig().clientUserId; int count_unread = 0; @@ -7713,9 +7852,11 @@ public class MessagesStorage extends BaseController { boolean isEnd = false; int num = dialogId == 777000 ? 10 : 1; int messagesCount = 0; + int totalMessagesCount = 0; int serviceUnreadCount = 0; long startLoadTime = SystemClock.elapsedRealtime(); SQLiteCursor cursor = null; + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; try { ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); @@ -7793,7 +7934,7 @@ public class MessagesStorage extends BaseController { cursor = null; } else { if (!DialogObject.isEncryptedDialog(dialogId)) { - if (load_type == 3 && minDate == 0) { + if (load_type == LOAD_AROUND_MESSAGE && minDate == 0) { if (threadMessageId == 0) { cursor = database.queryFinalized("SELECT inbox_max, unread_count, date, unread_count_i FROM dialogs WHERE did = " + dialogId); if (cursor.next()) { @@ -7813,8 +7954,8 @@ public class MessagesStorage extends BaseController { cursor.dispose(); cursor = null; } - } else if (load_type != 1 && load_type != 3 && load_type != 4 && minDate == 0) { - if (load_type == 2) { + } else if (load_type != LOAD_FORWARD && load_type != LOAD_AROUND_MESSAGE && load_type != LOAD_AROUND_DATE && minDate == 0) { + if (load_type == LOAD_FROM_UNREAD) { if (threadMessageId == 0) { cursor = database.queryFinalized("SELECT inbox_max, unread_count, date, unread_count_i FROM dialogs WHERE did = " + dialogId); if (cursor.next()) { @@ -7958,7 +8099,7 @@ public class MessagesStorage extends BaseController { state.requery(); state.bindLong(pointer++, dialogId); if (threadMessageId != 0) { - state.bindInteger(pointer++, threadMessageId); + state.bindLong(pointer++, threadMessageId); } state.bindInteger(pointer++, 0); state.bindInteger(pointer++, mid); @@ -7970,7 +8111,7 @@ public class MessagesStorage extends BaseController { cursor.dispose(); cursor = null; - if (load_type == 3 || load_type == 4 || queryFromServer && load_type == 2) { + if (load_type == LOAD_AROUND_MESSAGE || load_type == LOAD_AROUND_DATE || queryFromServer && load_type == LOAD_FROM_UNREAD) { if (threadMessageId != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages_topics WHERE uid = %d AND topic_id = %d AND mid > 0", dialogId, threadMessageId)); } else { @@ -7982,7 +8123,7 @@ public class MessagesStorage extends BaseController { cursor.dispose(); cursor = null; - if (load_type == 4 && offset_date != 0) { + if (load_type == LOAD_AROUND_DATE && offset_date != 0) { int startMid; int endMid; @@ -8104,7 +8245,7 @@ public class MessagesStorage extends BaseController { } } } else { - if (load_type == 2) { + if (load_type == LOAD_FROM_UNREAD) { int existingUnreadCount = 0; if (threadMessageId != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages_topics WHERE uid = %d AND topic_id = %d AND mid != 0 AND out = 0 AND read_state IN(0,2)", dialogId, threadMessageId)); @@ -8128,7 +8269,7 @@ public class MessagesStorage extends BaseController { } } } - } else if (load_type == 1) { + } else if (load_type == LOAD_FORWARD) { int holeMessageId = 0; if (threadMessageId != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes_topics WHERE uid = %d AND topic_id = %d AND (start >= %d AND start != 1 AND end != 1 OR start < %d AND end > %d) ORDER BY start ASC LIMIT 1", dialogId, threadMessageId, max_id, max_id, max_id)); @@ -8228,7 +8369,7 @@ public class MessagesStorage extends BaseController { } else { isEnd = true; - if (load_type == 3 && minDate == 0) { + if (load_type == LOAD_AROUND_MESSAGE && minDate == 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages_v2 WHERE uid = %d AND mid < 0", dialogId)); if (cursor.next()) { min_unread_id = cursor.intValue(0); @@ -8255,7 +8396,7 @@ public class MessagesStorage extends BaseController { } } - if (load_type == 3 || load_type == 4) { + if (load_type == LOAD_AROUND_MESSAGE || load_type == LOAD_AROUND_DATE) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages_v2 WHERE uid = %d AND mid < 0", dialogId)); if (cursor.next()) { last_message_id = cursor.intValue(0); @@ -8265,7 +8406,7 @@ public class MessagesStorage extends BaseController { cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (" + messageSelect + " WHERE m.uid = %d AND m.mid <= %d ORDER BY m.mid DESC LIMIT %d) UNION " + "SELECT * FROM (" + messageSelect + " WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d)", dialogId, messageMaxId, count_query / 2, dialogId, messageMaxId, count_query / 2)); - } else if (load_type == 1) { + } else if (load_type == LOAD_FORWARD) { cursor = database.queryFinalized(String.format(Locale.US, "" + messageSelect + " WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialogId, max_id, count_query)); } else if (minDate != 0) { if (max_id != 0) { @@ -8274,7 +8415,7 @@ public class MessagesStorage extends BaseController { cursor = database.queryFinalized(String.format(Locale.US, "" + messageSelect + " WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialogId, minDate, offset_query, count_query)); } } else { - if (load_type == 2) { + if (load_type == LOAD_FROM_UNREAD) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages_v2 WHERE uid = %d AND mid < 0", dialogId)); if (cursor.next()) { last_message_id = cursor.intValue(0); @@ -8593,11 +8734,11 @@ public class MessagesStorage extends BaseController { }; } else {*/ int finalMessagesCount = scheduled ? res.messages.size() : messagesCount; - return () -> getMessagesController().processLoadedMessages(res, finalMessagesCount, dialogId, mergeDialogId, countQueryFinal, maxIdOverrideFinal, offset_date, true, classGuid, minUnreadIdFinal, lastMessageIdFinal, countUnreadFinal, maxUnreadDateFinal, load_type, isEndFinal, scheduled ? 1 : 0, threadMessageId, loadIndex, queryFromServerFinal, mentionsUnreadFinal, processMessages, isTopic, loaderLogger); + return () -> getMessagesController().processLoadedMessages(res, finalMessagesCount, dialogId, mergeDialogId, countQueryFinal, maxIdOverrideFinal, offset_date, true, classGuid, minUnreadIdFinal, lastMessageIdFinal, countUnreadFinal, maxUnreadDateFinal, load_type, isEndFinal, mode, threadMessageId, loadIndex, queryFromServerFinal, mentionsUnreadFinal, processMessages, isTopic, loaderLogger); //} } - private void getAnimatedEmoji(String join, ArrayList documents) { + public void getAnimatedEmoji(String join, ArrayList documents) { SQLiteCursor cursor = null; try { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM animated_emoji WHERE document_id IN (%s)", join)); @@ -8624,12 +8765,12 @@ public class MessagesStorage extends BaseController { } } - public void getMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, int minDate, int classGuid, int load_type, boolean scheduled, int replyMessageId, int loadIndex, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger) { + public void getMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, int minDate, int classGuid, int load_type, int mode, long replyMessageId, int loadIndex, boolean processMessages, boolean isTopic, MessageLoaderLogger loaderLogger) { storageQueue.postRunnable(() -> { if (loaderLogger != null) { loaderLogger.logStorageQueuePost(); } - Runnable processMessagesRunnable = getMessagesInternal(dialogId, mergeDialogId, count, max_id, offset_date, minDate, classGuid, load_type, scheduled, replyMessageId, loadIndex, processMessages, isTopic, loaderLogger); + Runnable processMessagesRunnable = getMessagesInternal(dialogId, mergeDialogId, count, max_id, offset_date, minDate, classGuid, load_type, mode, replyMessageId, loadIndex, processMessages, isTopic, loaderLogger); if (loaderLogger != null) { loaderLogger.logStorageProccessing(); } @@ -9364,7 +9505,8 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); for (int a = 0; a < users.size(); a++) { TLRPC.User user = users.get(a); - if (user != null && user.min) { + if (user == null) continue; + if (user.min) { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM users WHERE uid = %d", user.id)); if (cursor.next()) { try { @@ -9405,11 +9547,11 @@ public class MessagesStorage extends BaseController { state.bindString(2, formatUserSearchName(user)); if (user.status != null) { if (user.status instanceof TLRPC.TL_userStatusRecently) { - user.status.expires = -100; + user.status.expires = user.status.by_me ? -1000 : -100; } else if (user.status instanceof TLRPC.TL_userStatusLastWeek) { - user.status.expires = -101; + user.status.expires = user.status.by_me ? -1001 : -101; } else if (user.status instanceof TLRPC.TL_userStatusLastMonth) { - user.status.expires = -102; + user.status.expires = user.status.by_me ? -1002 : -102; } state.bindInteger(3, user.status.expires); } else { @@ -9763,7 +9905,7 @@ public class MessagesStorage extends BaseController { data.reuse(); if (messageMedia.document != null) { downloadObject.object = messageMedia.document; - downloadObject.secret = MessageObject.isVideoDocument(messageMedia.document) && (messageMedia.ttl_seconds > 0 && messageMedia.ttl_seconds <= 60 || messageMedia.ttl_seconds == 0x7FFFFFFF); + downloadObject.secret = (MessageObject.isVideoDocument(messageMedia.document) || MessageObject.isVoiceDocument(messageMedia.document) || MessageObject.isRoundVideoDocument(messageMedia.document)) && (messageMedia.ttl_seconds > 0 && messageMedia.ttl_seconds <= 60 || messageMedia.ttl_seconds == 0x7FFFFFFF); } else if (messageMedia.photo != null) { downloadObject.object = messageMedia.photo; downloadObject.secret = messageMedia.ttl_seconds > 0 && messageMedia.ttl_seconds <= 60 || messageMedia.ttl_seconds == 0x7FFFFFFF; @@ -9786,7 +9928,7 @@ public class MessagesStorage extends BaseController { }); } - private int getMessageMediaType(TLRPC.Message message) { + public int getMessageMediaType(TLRPC.Message message) { if (message instanceof TLRPC.TL_message_secret) { if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isGifMessage(message) || MessageObject.isVoiceMessage(message) || @@ -10371,7 +10513,7 @@ public class MessagesStorage extends BaseController { } - private void putMessagesInternal(ArrayList messages, boolean withTransaction, boolean doNotUpdateDialogDate, int downloadMask, boolean ifNoLastMessage, boolean scheduled, int threadMessageId) { + private void putMessagesInternal(ArrayList messages, boolean withTransaction, boolean doNotUpdateDialogDate, int downloadMask, boolean ifNoLastMessage, int mode, long threadMessageId) { boolean databaseInTransaction = false; SQLitePreparedStatement state_messages = null; SQLitePreparedStatement state_messages_topic = null; @@ -10388,6 +10530,8 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state_media_topics = null; SQLiteCursor cursor = null; try { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; + final boolean saved = mode == ChatActivity.MODE_SAVED; if (scheduled) { if (withTransaction) { database.beginTransaction(); @@ -10497,6 +10641,7 @@ public class MessagesStorage extends BaseController { HashMap mediaIdsMapTopics = new HashMap<>(); HashMap> messagesMediaIdsMapTopics = new HashMap<>(); ArrayList createNewTopics = null; + ArrayList changedSavedMessages = null; state_messages = database.executeFast("REPLACE INTO messages_v2 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?)"); state_messages_topic = database.executeFast("REPLACE INTO messages_topics VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)"); @@ -10513,7 +10658,7 @@ public class MessagesStorage extends BaseController { int messageId = message.id; MessageObject.getDialogId(message); - int topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); + long topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); if (message.mentioned && message.media_unread) { ArrayList ids = dialogMentionsIdsMap.get(message.dialog_id); @@ -10904,7 +11049,7 @@ public class MessagesStorage extends BaseController { continue; } fixUnsupportedMedia(message); - int topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); + long topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); state_messages.requery(); int messageId = message.id; @@ -10940,12 +11085,13 @@ public class MessagesStorage extends BaseController { createNewTopics.add(message); } + final long selfId = getUserConfig().getClientUserId(); if (updateDialog) { TLRPC.Message lastMessage = messagesMap.get(message.dialog_id); if (lastMessage == null || message.date > lastMessage.date || lastMessage.id > 0 && message.id > lastMessage.id || lastMessage.id < 0 && message.id < lastMessage.id) { messagesMap.put(message.dialog_id, message); } - if (topicId != 0) { + if (topicId != 0 && message.dialog_id != selfId) { TopicKey topicKey = TopicKey.of(message.dialog_id, topicId); lastMessage = topicMessagesMap.get(topicKey); if (lastMessage == null || message.date > lastMessage.date || lastMessage.id > 0 && message.id > lastMessage.id || lastMessage.id < 0 && message.id < lastMessage.id) { @@ -10954,21 +11100,32 @@ public class MessagesStorage extends BaseController { } } - for (int i = 0; i < 2; i++) { - boolean isTopic = i == 1; + final boolean isTopic = i == 1; if (threadMessageId != 0 && !isTopic) { continue; } - if (isTopic && topicId == 0) { - continue; + SQLitePreparedStatement statement; + long dialogId = message.dialog_id; + if (isTopic) { + if (topicId == 0) { + continue; + } + statement = state_messages_topic; + if (selfId == dialogId && MessageObject.getSavedDialogId(selfId, message) != 0) { + if (changedSavedMessages == null) { + changedSavedMessages = new ArrayList<>(); + } + changedSavedMessages.add(message); + } + } else { + statement = state_messages; } - int pointer = 1; - SQLitePreparedStatement statement = isTopic ? state_messages_topic : state_messages; + int pointer = 1; statement.requery(); statement.bindInteger(pointer++, messageId); - statement.bindLong(pointer++, message.dialog_id); + statement.bindLong(pointer++, dialogId); if (isTopic) { statement.bindLong(pointer++, topicId); } @@ -11073,7 +11230,7 @@ public class MessagesStorage extends BaseController { state_media_topics.requery(); state_media_topics.bindInteger(1, messageId); state_media_topics.bindLong(2, message.dialog_id); - state_media_topics.bindInteger(3, topicId); + state_media_topics.bindLong(3, topicId); state_media_topics.bindInteger(4, message.date); state_media_topics.bindInteger(5, MediaDataController.getMediaType(message)); state_media_topics.bindByteBuffer(6, data); @@ -11268,7 +11425,7 @@ public class MessagesStorage extends BaseController { dids.add(key); if (exists) { - if (message == null || message.date > dialog_date || DialogObject.isEncryptedDialog(key)) { + if (message == null || (DialogObject.isEncryptedDialog(key) ? message.date > dialog_date : message.id >= last_mid) || message.send_state != 0 && ((message.flags & TLRPC.MESSAGE_FLAG_EDITED) == 0 || message.id >= last_mid)) { 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); @@ -11396,7 +11553,7 @@ public class MessagesStorage extends BaseController { state_topics_update.bindInteger(3, newUnreadMentions); state_topics_update.bindInteger(4, newTotalMessagesCount); state_topics_update.bindLong(5, topicKey.dialogId); - state_topics_update.bindInteger(6, topicKey.topicId); + state_topics_update.bindLong(6, topicKey.topicId); state_topics_update.step(); if (isForum(topicKey.dialogId)) { @@ -11480,7 +11637,7 @@ public class MessagesStorage extends BaseController { state_randoms.requery(); count += topicCountsMap.get(topicKey); state_randoms.bindLong(1, topicKey.dialogId); - state_randoms.bindInteger(2, topicKey.topicId); + state_randoms.bindLong(2, topicKey.topicId); state_randoms.bindInteger(3, type); state_randoms.bindInteger(4, Math.max(0, count)); state_randoms.bindInteger(5, old); @@ -11511,6 +11668,14 @@ public class MessagesStorage extends BaseController { AndroidUtilities.runOnUIThread(() -> getDownloadController().newDownloadObjectsAvailable(downloadMediaMaskFinal)); } updateWidgets(dids); + if (changedSavedMessages != null) { + final ArrayList finalChangedSavedMessages = changedSavedMessages; + AndroidUtilities.runOnUIThread(() -> { + if (getMessagesController().getSavedMessagesController().updateSavedDialogs(finalChangedSavedMessages)) { + getMessagesController().getSavedMessagesController().update(); + } + }); + } } } catch (Exception e) { checkSQLException(e); @@ -11523,6 +11688,9 @@ public class MessagesStorage extends BaseController { if (state_messages != null) { state_messages.dispose(); } + if (state_messages_topic != null) { + state_messages_topic.dispose(); + } if (state_randoms != null) { state_randoms.dispose(); } @@ -11586,7 +11754,7 @@ public class MessagesStorage extends BaseController { }); } else if (message.action instanceof TLRPC.TL_messageActionTopicEdit) { TLRPC.TL_messageActionTopicEdit action = (TLRPC.TL_messageActionTopicEdit) message.action; - forumTopic.id = MessageObject.getTopicId(message, true); + forumTopic.id = (int) MessageObject.getTopicId(currentAccount, message, true); forumTopic.icon_emoji_id = action.icon_emoji_id; forumTopic.title = action.title; forumTopic.closed = action.closed; @@ -11612,18 +11780,18 @@ public class MessagesStorage extends BaseController { } } - public void putMessages(ArrayList messages, boolean withTransaction, boolean useQueue, boolean doNotUpdateDialogDate, int downloadMask, boolean scheduled, int threadMessageId) { - putMessages(messages, withTransaction, useQueue, doNotUpdateDialogDate, downloadMask, false, scheduled, threadMessageId); + public void putMessages(ArrayList messages, boolean withTransaction, boolean useQueue, boolean doNotUpdateDialogDate, int downloadMask, int mode, long threadMessageId) { + putMessages(messages, withTransaction, useQueue, doNotUpdateDialogDate, downloadMask, false, mode, threadMessageId); } - public void putMessages(ArrayList messages, boolean withTransaction, boolean useQueue, boolean doNotUpdateDialogDate, int downloadMask, boolean ifNoLastMessage, boolean scheduled, int threadMessageId) { + public void putMessages(ArrayList messages, boolean withTransaction, boolean useQueue, boolean doNotUpdateDialogDate, int downloadMask, boolean ifNoLastMessage, int mode, long threadMessageId) { if (messages.size() == 0) { return; } if (useQueue) { - storageQueue.postRunnable(() -> putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage, scheduled, threadMessageId)); + storageQueue.postRunnable(() -> putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage, mode, threadMessageId)); } else { - putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage, scheduled, threadMessageId); + putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask, ifNoLastMessage, mode, threadMessageId); } } @@ -11685,6 +11853,7 @@ public class MessagesStorage extends BaseController { return null; } } + final long selfId = getUserConfig().getClientUserId(); oldMessageId = _oldId; if (_oldId < 0 && scheduled == 1) { SQLitePreparedStatement state = null; @@ -11760,6 +11929,7 @@ public class MessagesStorage extends BaseController { } SQLitePreparedStatement state = null; SQLitePreparedStatement state2 = null; + SQLitePreparedStatement state3 = null; if (oldMessageId == newId && date != 0) { try { if (scheduled == 0) { @@ -11821,6 +11991,10 @@ public class MessagesStorage extends BaseController { state2.dispose(); state2 = null; } + if (state3 != null) { + state3.dispose(); + state3 = null; + } } try { @@ -12237,6 +12411,7 @@ public class MessagesStorage extends BaseController { ArrayList unknownMessages = new ArrayList<>(messages); ArrayList unknownMessagesInTopics = new ArrayList<>(messages); LongSparseArray dialogsToUpdate = new LongSparseArray<>(); + LongSparseArray> savedMessagesByDialogs = new LongSparseArray<>(); HashMap topicsMessagesToUpdate = new HashMap<>(); LongSparseArray> messagesByDialogs = new LongSparseArray<>(); String ids = TextUtils.join(",", messages); @@ -12279,15 +12454,29 @@ public class MessagesStorage extends BaseController { } } } - if (!DialogObject.isEncryptedDialog(did) && !deleteFiles) { + if (!DialogObject.isEncryptedDialog(did) && !deleteFiles && did != currentUser) { continue; } NativeByteBuffer data = cursor.byteBufferValue(1); if (data != null) { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.readAttachPath(data, getUserConfig().clientUserId); + message.readAttachPath(data, currentUser); data.reuse(); - addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); + if (DialogObject.isEncryptedDialog(did) || deleteFiles) { + addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); + } + + if (did == currentUser) { + long savedDialogId = MessageObject.getSavedDialogId(currentUser, message); + if (savedDialogId != 0) { + ArrayList mids2 = savedMessagesByDialogs.get(savedDialogId); + if (mids2 == null) { + mids2 = new ArrayList<>(); + savedMessagesByDialogs.put(savedDialogId, mids2); + } + mids2.add(mid); + } + } } } } catch (Exception e) { @@ -12298,13 +12487,13 @@ public class MessagesStorage extends BaseController { ArrayList topicsToDelete = null; if (dialogId < 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data, read_state, out, mention, mid FROM messages_topics WHERE mid IN(%s) AND uid = %d", ids, dialogId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data, read_state, out, mention, mid FROM messages_topics WHERE mid IN(%s) AND uid = %d", ids, dialogId)); try { while (cursor.next()) { long did = cursor.longValue(0); int mid = cursor.intValue(5); - int topicId = 0; + long topicId = 0; unknownMessagesInTopics.remove((Integer) mid); NativeByteBuffer data = cursor.byteBufferValue(1); @@ -12319,7 +12508,7 @@ public class MessagesStorage extends BaseController { } topicsToDelete.add(TopicKey.of(did, message.id)); } - topicId = MessageObject.getTopicId(message, isForum(did)); + topicId = MessageObject.getTopicId(currentAccount, message, isForum(did)); } if (topicId != 0) { TopicKey topicKey = TopicKey.of(dialogId, topicId); @@ -12630,6 +12819,9 @@ public class MessagesStorage extends BaseController { database.executeFast(String.format(Locale.US, "DELETE FROM media_v4 WHERE mid IN(%s) AND uid = %d", ids, did)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM media_topics WHERE mid IN(%s) AND uid = %d", ids, did)).stepThis().dispose(); } + if (!savedMessagesByDialogs.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> getMessagesController().getSavedMessagesController().updateDeleted(savedMessagesByDialogs)); + } database.executeFast(String.format(Locale.US, "DELETE FROM messages_seq WHERE mid IN(%s)", ids)).stepThis().dispose(); if (!unknownMessages.isEmpty()) { if (dialogId == 0) { @@ -13064,7 +13256,7 @@ public class MessagesStorage extends BaseController { } } - private void doneHolesInTable(String table, long did, int max_id, int thread_message_id) throws Exception { + private void doneHolesInTable(String table, long did, int max_id, long thread_message_id) throws Exception { if (thread_message_id != 0) { if (max_id == 0) { database.executeFast(String.format(Locale.US, "DELETE FROM " + table + " WHERE uid = %d AND topic_id = %d", did, thread_message_id)).stepThis().dispose(); @@ -13089,7 +13281,7 @@ public class MessagesStorage extends BaseController { int pointer = 1; state.bindLong(pointer++, did); if (thread_message_id != 0) { - state.bindInteger(pointer++, thread_message_id); + state.bindLong(pointer++, thread_message_id); } state.bindInteger(pointer++, 1); state.bindInteger(pointer++, 1); @@ -13103,7 +13295,7 @@ public class MessagesStorage extends BaseController { } } - public void doneHolesInMedia(long did, int max_id, int type, int thread_message_id) throws Exception { + public void doneHolesInMedia(long did, int max_id, int type, long thread_message_id) throws Exception { if (type == -1) { if (thread_message_id != 0) { if (max_id == 0) { @@ -13130,7 +13322,7 @@ public class MessagesStorage extends BaseController { int pointer = 1; state.bindLong(pointer++, did); if (thread_message_id != 0) { - state.bindInteger(pointer++, thread_message_id); + state.bindLong(pointer++, thread_message_id); } state.bindInteger(pointer++, a); state.bindInteger(pointer++, 1); @@ -13170,7 +13362,7 @@ public class MessagesStorage extends BaseController { int pointer = 1; state.bindLong(pointer++, did); if (thread_message_id != 0) { - state.bindInteger(pointer++, thread_message_id); + state.bindLong(pointer++, thread_message_id); } state.bindInteger(pointer++, type); state.bindInteger(pointer++, 1); @@ -13205,7 +13397,7 @@ public class MessagesStorage extends BaseController { public int type; } - public void closeHolesInMedia(long did, int minId, int maxId, int type, int topicId) { + public void closeHolesInMedia(long did, int minId, int maxId, int type, long topicId) { SQLiteCursor cursor = null; SQLitePreparedStatement state = null; try { @@ -13283,7 +13475,7 @@ public class MessagesStorage extends BaseController { int pointer = 1; state.bindLong(pointer++, did); if (topicId != 0) { - state.bindInteger(pointer++, topicId); + state.bindLong(pointer++, topicId); } state.bindInteger(pointer++, hole.type); state.bindInteger(pointer++, hole.start); @@ -13312,7 +13504,7 @@ public class MessagesStorage extends BaseController { } } - private void closeHolesInTable(String table, long did, int minId, int maxId, int thread_message_id) { + private void closeHolesInTable(String table, long did, int minId, int maxId, long thread_message_id) { SQLiteCursor cursor = null; SQLitePreparedStatement state = null; try { @@ -13386,7 +13578,7 @@ public class MessagesStorage extends BaseController { state.requery(); state.bindLong(pointer++, did); if (thread_message_id != 0) { - state.bindInteger(pointer++, thread_message_id); + state.bindLong(pointer++, thread_message_id); } state.bindInteger(pointer++, hole.start); state.bindInteger(pointer++, minId); @@ -13395,7 +13587,7 @@ public class MessagesStorage extends BaseController { pointer = 1; state.bindLong(pointer++, did); if (thread_message_id != 0) { - state.bindInteger(pointer++, thread_message_id); + state.bindLong(pointer++, thread_message_id); } state.bindInteger(pointer++, maxId); state.bindInteger(pointer++, hole.end); @@ -13454,15 +13646,25 @@ public class MessagesStorage extends BaseController { MessageObject.normalizeFlags(message); NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); message.serializeToStream(data); + ArrayList changedSavedMessages = null; + final long selfId = getUserConfig().getClientUserId(); for (int i = 0; i < 2; i++) { boolean isTopic = i == 1; - int topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); - if (isTopic && topicId == 0) { - continue; - } + long topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); + long dialogId = message.dialog_id; + boolean removeSavedPeerIdLater = false; if (isTopic) { + if (topicId == 0) { + continue; + } state = database.executeFast("REPLACE INTO messages_topics VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)"); + if (dialogId == selfId && MessageObject.getSavedDialogId(selfId, message) != 0) { + if (changedSavedMessages == null) { + changedSavedMessages = new ArrayList<>(); + } + changedSavedMessages.add(message); + } } else { state = database.executeFast("REPLACE INTO messages_v2 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?)"); } @@ -13470,9 +13672,9 @@ public class MessagesStorage extends BaseController { int pointer = 1; state.bindInteger(pointer++, message.id); - state.bindLong(pointer++, message.dialog_id); + state.bindLong(pointer++, dialogId); if (isTopic) { - state.bindInteger(pointer++, topicId); + state.bindLong(pointer++, topicId); } state.bindInteger(pointer++, readState); state.bindInteger(pointer++, message.send_state); @@ -13542,12 +13744,17 @@ public class MessagesStorage extends BaseController { if (storyData != null) { storyData.reuse(); } + + if (removeSavedPeerIdLater) { + message.flags &=~ 268435456; + message.saved_peer_id = null; + } } if (MediaDataController.canAddMessageToMedia(message)) { for (int i = 0; i < 2; i++) { boolean isTopic = i == 1; - int topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); + long topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); if (isTopic && topicId == 0) { continue; } @@ -13594,6 +13801,14 @@ public class MessagesStorage extends BaseController { arrayList.add(messageObject); AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.replaceMessagesObjects, messageObject.getDialogId(), arrayList)); } + if (changedSavedMessages != null) { + final ArrayList finalChangedSavedMessages = changedSavedMessages; + AndroidUtilities.runOnUIThread(() -> { + if (getMessagesController().getSavedMessagesController().updateSavedDialogs(finalChangedSavedMessages)) { + getMessagesController().getSavedMessagesController().update(); + } + }); + } } catch (Exception e) { checkSQLException(e); } finally { @@ -13611,7 +13826,7 @@ public class MessagesStorage extends BaseController { } // put messages in data base while load history - public void putMessages(TLRPC.messages_Messages messages, long dialogId, int load_type, int max_id, boolean createDialog, boolean scheduled, int threadMessageId) { + public void putMessages(TLRPC.messages_Messages messages, long dialogId, int load_type, int max_id, boolean createDialog, int mode, long threadMessageId) { storageQueue.postRunnable(() -> { SQLitePreparedStatement state_messages = null; SQLitePreparedStatement state_messages_topics = null; @@ -13623,6 +13838,7 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state3 = null; SQLiteCursor cursor = null; try { + final boolean scheduled = mode == ChatActivity.MODE_SCHEDULED; if (scheduled) { database.executeFast(String.format(Locale.US, "DELETE FROM scheduled_messages_v2 WHERE uid = %d AND mid > 0", dialogId)).stepThis().dispose(); state_messages = database.executeFast("REPLACE INTO scheduled_messages_v2 VALUES(?, ?, ?, ?, ?, ?, NULL, 0)"); @@ -13661,7 +13877,7 @@ public class MessagesStorage extends BaseController { boolean isTopic = threadMessageId != 0; String holesTableName = isTopic ? "messages_holes_topics" : "messages_holes"; if (messages.messages.isEmpty()) { - if (load_type == 0) { + if (load_type == LOAD_BACKWARD) { doneHolesInTable(holesTableName, dialogId, max_id, threadMessageId); doneHolesInMedia(dialogId, max_id, -1, threadMessageId); } @@ -13669,16 +13885,16 @@ public class MessagesStorage extends BaseController { } database.beginTransaction(); - if (load_type == 0) { + if (load_type == LOAD_BACKWARD) { int minId = messages.messages.get(messages.messages.size() - 1).id; closeHolesInTable(holesTableName, dialogId, minId, max_id, threadMessageId); closeHolesInMedia(dialogId, minId, max_id, -1, threadMessageId); - } else if (load_type == 1) { + } else if (load_type == LOAD_FORWARD) { int maxId = messages.messages.get(0).id; closeHolesInTable(holesTableName, dialogId, max_id, maxId, threadMessageId); closeHolesInMedia(dialogId, max_id, maxId, -1, threadMessageId); - } else if (load_type == 3 || load_type == 2 || load_type == 4) { - int maxId = max_id == 0 && load_type != 4 ? Integer.MAX_VALUE : messages.messages.get(0).id; + } else if (load_type == LOAD_AROUND_MESSAGE || load_type == LOAD_FROM_UNREAD || load_type == LOAD_AROUND_DATE) { + int maxId = max_id == 0 && load_type != LOAD_AROUND_DATE ? Integer.MAX_VALUE : messages.messages.get(0).id; int minId = messages.messages.get(messages.messages.size() - 1).id; closeHolesInTable(holesTableName, dialogId, minId, maxId, threadMessageId); closeHolesInMedia(dialogId, minId, maxId, -1, threadMessageId); @@ -13693,6 +13909,7 @@ public class MessagesStorage extends BaseController { ArrayList filesToDelete = new ArrayList<>(); ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); + ArrayList changedSavedMessages = null; Integer lastMessageId = null; Long lastMessageGroupId = null; @@ -13706,6 +13923,7 @@ public class MessagesStorage extends BaseController { int minDeleteTime = Integer.MAX_VALUE; HashMap botKeyboards = null; long channelId = 0; + final long selfId = getUserConfig().getClientUserId(); for (int a = 0; a < count; a++) { TLRPC.Message message = messages.messages.get(a); if (lastMessageId == null && message != null || lastMessageId != null && lastMessageId < message.id) { @@ -13841,22 +14059,34 @@ public class MessagesStorage extends BaseController { for (int i = 0; i < 2; i++) { boolean isTopicMessage = i == 1; - int topicId = threadMessageId; - if (isTopicMessage && topicId == 0) { - topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); - } - if (isTopicMessage && topicId == 0) { - continue; + boolean removeSavedPeerIdLater = false; + SQLitePreparedStatement currentState; + long topicId = threadMessageId; + if (isTopicMessage) { + if (topicId == 0) { + topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); + } + if (topicId == 0) { + continue; + } + currentState = state_messages_topics; + if (dialogId == selfId && MessageObject.getSavedDialogId(selfId, message) != 0) { + if (changedSavedMessages == null) { + changedSavedMessages = new ArrayList<>(); + } + changedSavedMessages.add(message); + } + } else { + currentState = state_messages; } - SQLitePreparedStatement currentState = isTopicMessage ? state_messages_topics : state_messages; currentState.requery(); int pointer = 1; currentState.bindInteger(pointer++, message.id); currentState.bindLong(pointer++, dialogId); if (isTopicMessage) { - currentState.bindInteger(pointer++, topicId); + currentState.bindLong(pointer++, topicId); } currentState.bindInteger(pointer++, MessageObject.getUnreadFlags(message)); currentState.bindInteger(pointer++, message.send_state); @@ -13929,6 +14159,11 @@ public class MessagesStorage extends BaseController { if (storyData != null) { storyData.reuse(); } + + if (removeSavedPeerIdLater) { + message.flags &=~ 268435456; + message.saved_peer_id = null; + } } if (threadMessageId == 0 || load_type == -2) { @@ -13949,7 +14184,7 @@ public class MessagesStorage extends BaseController { } } } - int topicId = MessageObject.getTopicId(message, isForum(message.dialog_id)); + long topicId = MessageObject.getTopicId(currentAccount, message, isForum(message.dialog_id)); if (threadMessageId != 0 || (load_type == -2 && topicId != 0)) { if (MediaDataController.canAddMessageToMedia(message)) { state_media_topics.requery(); @@ -13999,7 +14234,7 @@ public class MessagesStorage extends BaseController { } if (load_type == 0 && isValidKeyboardToSave(message)) { - TopicKey topicKey = TopicKey.of(dialogId, MessageObject.getTopicId(message, isForum(dialogId))); + TopicKey topicKey = TopicKey.of(dialogId, MessageObject.getTopicId(currentAccount, message, isForum(dialogId))); TLRPC.Message currentBotKeyboard = botKeyboards == null ? null : botKeyboards.get(topicKey); if (currentBotKeyboard == null || currentBotKeyboard.id < message.id) { if (botKeyboards == null) { @@ -14059,6 +14294,14 @@ public class MessagesStorage extends BaseController { if (createDialog || updateDialogs) { updateDialogsWithDeletedMessages(dialogId, channelId, new ArrayList<>(), null, false); } + if (changedSavedMessages != null) { + final ArrayList finalChangedSavedMessages = changedSavedMessages; + AndroidUtilities.runOnUIThread(() -> { + if (getMessagesController().getSavedMessagesController().updateSavedDialogs(finalChangedSavedMessages)) { + getMessagesController().getSavedMessagesController().update(); + } + }); + } } } catch (Exception e) { checkSQLException(e); @@ -14260,12 +14503,12 @@ public class MessagesStorage extends BaseController { public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPeersAndFolders) { long[] draftsDialogIds; if (loadDraftsPeersAndFolders) { - LongSparseArray> drafts = getMediaDataController().getDrafts(); + LongSparseArray> drafts = getMediaDataController().getDrafts(); int draftsCount = drafts.size(); if (draftsCount > 0) { draftsDialogIds = new long[draftsCount]; for (int i = 0; i < draftsCount; i++) { - SparseArray threads = drafts.valueAt(i); + LongSparseArray threads = drafts.valueAt(i); if (threads.get(0) == null) { continue; } @@ -14599,12 +14842,13 @@ public class MessagesStorage extends BaseController { }); } - public static void createFirstHoles(long did, SQLitePreparedStatement state5, SQLitePreparedStatement state6, int messageId, int topicId) throws Exception { + public static void createFirstHoles(long did, SQLitePreparedStatement state5, SQLitePreparedStatement state6, int messageId, long topicId) throws Exception { + FileLog.d("createFirstHoles " + did + " " + messageId + " " + topicId); state5.requery(); int pointer = 1; state5.bindLong(pointer++, did); if (topicId != 0) { - state5.bindInteger(pointer++, topicId); + state5.bindLong(pointer++, topicId); } state5.bindInteger(pointer++, messageId == 1 ? 1 : 0); state5.bindInteger(pointer++, messageId); @@ -14615,7 +14859,7 @@ public class MessagesStorage extends BaseController { pointer = 1; state6.bindLong(pointer++, did); if (topicId != 0) { - state6.bindInteger(pointer++, topicId); + state6.bindLong(pointer++, topicId); } state6.bindInteger(pointer++, b); state6.bindInteger(pointer++, messageId == 1 ? 1 : 0); @@ -14734,7 +14978,7 @@ public class MessagesStorage extends BaseController { messageDate = Math.max(message.date, messageDate); if (isValidKeyboardToSave(message)) { - TopicKey topicKey = TopicKey.of(dialog.id, MessageObject.getTopicId(message, isForum(dialog.id))); + TopicKey topicKey = TopicKey.of(dialog.id, MessageObject.getTopicId(currentAccount, message, isForum(dialog.id))); getMediaDataController().putBotKeyboard(topicKey, message); } @@ -15836,11 +16080,11 @@ public class MessagesStorage extends BaseController { return messageIds; } - public void updateUnreadReactionsCount(long dialogId, int topicId, int count) { + public void updateUnreadReactionsCount(long dialogId, long topicId, int count) { updateUnreadReactionsCount(dialogId, topicId, count, false); } - public void updateUnreadReactionsCount(long dialogId, int topicId, int count, boolean increment) { + public void updateUnreadReactionsCount(long dialogId, long topicId, int count, boolean increment) { storageQueue.postRunnable(() -> { SQLitePreparedStatement state = null; if (topicId != 0) { @@ -15856,7 +16100,7 @@ public class MessagesStorage extends BaseController { state = database.executeFast("UPDATE topics SET unread_reactions = ? WHERE did = ? AND topic_id = ?"); state.bindInteger(1, Math.max(currentReactions + count, 0)); state.bindLong(2, dialogId); - state.bindInteger(3, topicId); + state.bindLong(3, topicId); state.step(); state.dispose(); state = null; @@ -15864,7 +16108,7 @@ public class MessagesStorage extends BaseController { if (count == 0) { state = database.executeFast("UPDATE reaction_mentions_topics SET state = 0 WHERE dialog_id = ? AND topic_id = ? "); state.bindLong(1, dialogId); - state.bindInteger(2, topicId); + state.bindLong(2, topicId); state.step(); state.dispose(); state = null; @@ -15903,7 +16147,7 @@ public class MessagesStorage extends BaseController { }); } - public void markMessageReactionsAsRead(long dialogId, int topicId, int messageId, boolean usequeue) { + public void markMessageReactionsAsRead(long dialogId, long topicId, int messageId, boolean usequeue) { if (usequeue) { getStorageQueue().postRunnable(() -> { markMessageReactionsAsReadInternal(dialogId, topicId, messageId); @@ -15913,7 +16157,7 @@ public class MessagesStorage extends BaseController { } } - public void markMessageReactionsAsReadInternal(long dialogId, int topicId, int messageId) { + public void markMessageReactionsAsReadInternal(long dialogId, long topicId, int messageId) { SQLitePreparedStatement state = null; SQLiteCursor cursor = null; try { @@ -15934,7 +16178,7 @@ public class MessagesStorage extends BaseController { state = getMessagesStorage().getDatabase().executeFast("UPDATE reaction_mentions_topics SET state = 0 WHERE message_id = ? AND dialog_id = ? AND topic_id = ? "); state.bindInteger(1, messageId); state.bindLong(2, dialogId); - state.bindInteger(3, topicId); + state.bindLong(3, topicId); state.step(); state.dispose(); state = null; @@ -15989,7 +16233,7 @@ public class MessagesStorage extends BaseController { } - public void updateDialogUnreadReactions(long dialogId, int topicId, int newUnreadCount, boolean increment) { + public void updateDialogUnreadReactions(long dialogId, long topicId, int newUnreadCount, boolean increment) { storageQueue.postRunnable(() -> { SQLiteCursor cursor = null; SQLitePreparedStatement state = null; @@ -16026,7 +16270,7 @@ public class MessagesStorage extends BaseController { state = getMessagesStorage().getDatabase().executeFast("UPDATE topics SET unread_reactions = ? WHERE did = ? AND topic_id = ?"); state.bindInteger(1, oldUnreadRactions); state.bindLong(2, dialogId); - state.bindInteger(3, topicId); + state.bindLong(3, topicId); state.step(); state.dispose(); state = null; @@ -16072,9 +16316,9 @@ public class MessagesStorage extends BaseController { public static class TopicKey { public long dialogId; - public int topicId; + public long topicId; - public static TopicKey of(long dialogId, int topicId) { + public static TopicKey of(long dialogId, long topicId) { TopicKey topicKey = new TopicKey(); topicKey.dialogId = dialogId; topicKey.topicId = topicId; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MusicBrowserService.java b/TMessagesProj/src/main/java/org/telegram/messenger/MusicBrowserService.java index 428ec3d07..732ee31b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MusicBrowserService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MusicBrowserService.java @@ -34,6 +34,7 @@ import android.os.Process; import android.os.SystemClock; import android.service.media.MediaBrowserService; import android.text.TextUtils; +import android.util.Log; import android.widget.Toast; import androidx.collection.LongSparseArray; @@ -50,6 +51,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import javax.annotation.Nullable; + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class MusicBrowserService extends MediaBrowserService implements NotificationCenter.NotificationCenterDelegate { @@ -57,6 +60,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica private static final String SLOT_RESERVATION_SKIP_TO_PREV = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS"; private static final String SLOT_RESERVATION_QUEUE = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_QUEUE"; + @Nullable private MediaSession mediaSession; private static final String MEDIA_ID_ROOT = "__ROOT__"; @@ -91,6 +95,15 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica lastSelectedDialog = AndroidUtilities.getPrefIntOrLong(MessagesController.getNotificationsSettings(currentAccount), "auto_lastSelectedDialog", 0); + updatePlaybackState(null); + + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingPlayStateChanged); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidStart); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidReset); + } + + private void createMediaSession() { + if (mediaSession != null) return; mediaSession = new MediaSession(this, "MusicService"); setSessionToken(mediaSession.getSessionToken()); mediaSession.setCallback(new MediaSessionCallback()); @@ -106,12 +119,6 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica extras.putBoolean(SLOT_RESERVATION_SKIP_TO_PREV, true); extras.putBoolean(SLOT_RESERVATION_SKIP_TO_NEXT, true); mediaSession.setExtras(extras); - - updatePlaybackState(null); - - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingPlayStateChanged); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidStart); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.messagePlayingDidReset); } @Override @@ -135,7 +142,9 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica super.onDestroy(); handleStopRequest(null); delayedStopHandler.removeCallbacksAndMessages(null); - mediaSession.release(); + if (mediaSession != null) { + mediaSession.release(); + } } @Override @@ -241,6 +250,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica ArrayList arrayList = musicObjects.get(lastSelectedDialog); ArrayList arrayList1 = musicQueues.get(lastSelectedDialog); if (arrayList != null && !arrayList.isEmpty()) { + createMediaSession(); mediaSession.setQueue(arrayList1); if (lastSelectedDialog > 0) { TLRPC.User user = users.get(lastSelectedDialog); @@ -413,6 +423,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica lastSelectedDialog = did; MessagesController.getNotificationsSettings(currentAccount).edit().putLong("auto_lastSelectedDialog", did).commit(); MediaController.getInstance().setPlaylist(arrayList, arrayList.get(id), 0, false, null); + createMediaSession(); mediaSession.setQueue(arrayList1); if (did > 0) { TLRPC.User user = users.get(did); @@ -515,8 +526,9 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica } else { stateBuilder.setActiveQueueItemId(0); } - - mediaSession.setPlaybackState(stateBuilder.build()); + if (mediaSession != null) { + mediaSession.setPlaybackState(stateBuilder.build()); + } } private long getAvailableActions() { @@ -554,7 +566,8 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica serviceStarted = true; } - if (!mediaSession.isActive()) { + if (mediaSession == null || !mediaSession.isActive()) { + createMediaSession(); mediaSession.setActive(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index fa191a308..0294d98d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -176,6 +176,8 @@ public class NotificationCenter { public static final int recordStarted = totalEvents++; public static final int recordStartError = totalEvents++; public static final int recordStopped = totalEvents++; + public static final int recordPaused = totalEvents++; + public static final int recordResumed = totalEvents++; public static final int screenshotTook = totalEvents++; public static final int albumsDidLoad = totalEvents++; public static final int audioDidSent = totalEvents++; @@ -223,7 +225,9 @@ public class NotificationCenter { public static final int unconfirmedAuthUpdate = totalEvents++; public static final int dialogPhotosUpdate = totalEvents++; public static final int channelRecommendationsLoaded = totalEvents++; - public static final int savedMessagesUpdate = totalEvents++; + public static final int savedMessagesDialogsUpdate = totalEvents++; + public static final int savedReactionTagsUpdate = totalEvents++; + public static final int userIsPremiumBlockedUpadted = totalEvents++; //global public static final int pushMessagesUpdated = totalEvents++; @@ -737,29 +741,35 @@ public class NotificationCenter { } } - public static void listenEmojiLoading(View view) { - if (view == null) { - return; + public Runnable listen(View view, final int id, final Utilities.Callback callback) { + if (view == null || callback == null) { + return () -> {}; } - - final NotificationCenterDelegate delegate = (id, account, args) -> { - if (id == NotificationCenter.emojiLoaded) { - if (view != null && view.isAttachedToWindow()) { - view.invalidate(); - } + final NotificationCenterDelegate delegate = (_id, account, args) -> { + if (_id == id) { + callback.run(args); } }; - view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + final View.OnAttachStateChangeListener viewListener = new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View view) { - NotificationCenter.getGlobalInstance().addObserver(delegate, NotificationCenter.emojiLoaded); + NotificationCenter.getGlobalInstance().addObserver(delegate, id); } - @Override public void onViewDetachedFromWindow(View view) { - NotificationCenter.getGlobalInstance().removeObserver(delegate, NotificationCenter.emojiLoaded); + NotificationCenter.getGlobalInstance().removeObserver(delegate, id); } - }); + }; + view.addOnAttachStateChangeListener(viewListener); + + return () -> { + view.removeOnAttachStateChangeListener(viewListener); + NotificationCenter.getGlobalInstance().removeObserver(delegate, id); + }; + } + + public static void listenEmojiLoading(View view) { + getGlobalInstance().listen(view, NotificationCenter.emojiLoaded, args -> view.invalidate()); } public void listenOnce(int id, Runnable callback) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 535974bb9..da559b1a5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -37,14 +37,12 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Shader; -import android.graphics.Xfermode; import android.graphics.drawable.BitmapDrawable; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.SoundPool; import android.net.Uri; import android.os.Build; -import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; import android.provider.Settings; @@ -54,8 +52,6 @@ import android.util.Pair; import android.util.SparseArray; import android.util.SparseBooleanArray; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; @@ -92,7 +88,6 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.TreeSet; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @@ -119,7 +114,7 @@ public class NotificationsController extends BaseController { private final ArrayList storyPushMessages = new ArrayList<>(); private final LongSparseArray storyPushMessagesDict = new LongSparseArray<>(); private long openedDialogId = 0; - private int openedTopicId = 0; + private long openedTopicId = 0; private int lastButtonId = 5000; private int total_unread_count = 0; private int personalCount = 0; @@ -284,15 +279,15 @@ public class NotificationsController extends BaseController { private static final LongSparseArray sharedPrefCachedKeys = new LongSparseArray<>(); - public static String getSharedPrefKey(long dialog_id, int topicId) { + public static String getSharedPrefKey(long dialog_id, long topicId) { return getSharedPrefKey(dialog_id, topicId, false); } - public static String getSharedPrefKey(long dialog_id, int topicId, boolean backgroundThread) { + public static String getSharedPrefKey(long dialog_id, long topicId, boolean backgroundThread) { if (backgroundThread) { String key; if (topicId != 0) { - key = String.format(Locale.US, "%d_%d",dialog_id, topicId); + key = String.format(Locale.US, "%d_%d", dialog_id, topicId); } else { key = String.valueOf(dialog_id); } @@ -310,7 +305,7 @@ public class NotificationsController extends BaseController { } String key; if (topicId != 0) { - key = String.format(Locale.US, "%d_%d",dialog_id, topicId); + key = String.format(Locale.US, "%d_%d", dialog_id, topicId); } else { key = String.valueOf(dialog_id); } @@ -318,7 +313,7 @@ public class NotificationsController extends BaseController { return key; } - public void muteUntil(long did, int topicId, int selectedTimeInSeconds) { + public void muteUntil(long did, long topicId, int selectedTimeInSeconds) { if (did != 0) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); SharedPreferences.Editor editor = preferences.edit(); @@ -425,7 +420,7 @@ public class NotificationsController extends BaseController { inChatSoundEnabled = value; } - public void setOpenedDialogId(long dialog_id, int topicId) { + public void setOpenedDialogId(long dialog_id, long topicId) { notificationsQueue.postRunnable(() -> { openedDialogId = dialog_id; openedTopicId = topicId; @@ -462,8 +457,10 @@ public class NotificationsController extends BaseController { for (int a = 0; a < pushMessages.size(); a++) { MessageObject messageObject = pushMessages.get(a); long dialog_id = messageObject.getDialogId(); - if (messageObject.messageOwner.mentioned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || - DialogObject.isEncryptedDialog(dialog_id) || messageObject.messageOwner.peer_id.channel_id != 0 && !messageObject.isSupergroup()) { + if (messageObject.isReactionPush || + messageObject.messageOwner.mentioned && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || + DialogObject.isEncryptedDialog(dialog_id) || + messageObject.messageOwner.peer_id.channel_id != 0 && !messageObject.isSupergroup()) { continue; } return true; @@ -1009,7 +1006,7 @@ public class NotificationsController extends BaseController { } long originalDialogId = dialogId; - int topicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(messageObject)); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(messageObject)); if (dialogId == openedDialogId && ApplicationLoader.isScreenOn) { if (!isFcm) { playInChatSound(); @@ -1104,7 +1101,7 @@ public class NotificationsController extends BaseController { } else if (added) { MessageObject messageObject = messageObjects.get(0); long dialog_id = messageObject.getDialogId(); - int topicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(dialog_id)); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(dialog_id)); Boolean isChannel; if (messageObject.isFcmMessage()) { isChannel = messageObject.localChannel; @@ -1354,7 +1351,7 @@ public class NotificationsController extends BaseController { } long dialog_id = messageObject.getDialogId(); long original_dialog_id = dialog_id; - int topicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(messageObject)); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(messageObject)); if (messageObject.messageOwner.mentioned) { dialog_id = messageObject.getFromChatId(); } @@ -1426,7 +1423,7 @@ public class NotificationsController extends BaseController { } long dialogId = messageObject.getDialogId(); long originalDialogId = dialogId; - int topicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(messageObject)); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(messageObject)); long randomId = messageObject.messageOwner.random_id; if (messageObject.messageOwner.mentioned) { dialogId = messageObject.getFromChatId(); @@ -2086,6 +2083,10 @@ public class NotificationsController extends BaseController { } else { return LocaleController.getString("Message", R.string.Message); } + } else if (messageObject.isVoiceOnce()) { + return LocaleController.getString(R.string.AttachOnceAudio); + } else if (messageObject.isRoundOnce()) { + return LocaleController.getString(R.string.AttachOnceRound); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(messageObject.messageOwner.message)) { return "\uD83D\uDDBC " + replaceSpoilers(messageObject); @@ -2899,7 +2900,7 @@ public class NotificationsController extends BaseController { && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty); } - private int getNotifyOverride(SharedPreferences preferences, long dialog_id, int topicId) { + private int getNotifyOverride(SharedPreferences preferences, long dialog_id, long topicId) { int notifyOverride = dialogsNotificationsFacade.getProperty(NotificationsSettingsFacade.PROPERTY_NOTIFY, dialog_id, topicId, -1); if (notifyOverride == 3) { int muteUntil = dialogsNotificationsFacade.getProperty(NotificationsSettingsFacade.PROPERTY_NOTIFY_UNTIL, dialog_id, topicId, 0); @@ -3041,11 +3042,11 @@ public class NotificationsController extends BaseController { return true; } - public void deleteNotificationChannel(long dialogId, int topicId) { + public void deleteNotificationChannel(long dialogId, long topicId) { deleteNotificationChannel(dialogId, topicId, -1); } - private void deleteNotificationChannelInternal(long dialogId, int topicId, int what) { + private void deleteNotificationChannelInternal(long dialogId, long topicId, int what) { if (Build.VERSION.SDK_INT < 26) { return; } @@ -3091,7 +3092,7 @@ public class NotificationsController extends BaseController { } } - public void deleteNotificationChannel(long dialogId, int topicId, int what) { + public void deleteNotificationChannel(long dialogId, long topicId, int what) { if (Build.VERSION.SDK_INT < 26) { return; } @@ -3406,7 +3407,7 @@ public class NotificationsController extends BaseController { } @TargetApi(26) - private String validateChannelId(long dialogId, int topicId, String name, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int type) { + private String validateChannelId(long dialogId, long topicId, String name, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int type) { ensureGroupsCreated(); SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); @@ -3778,7 +3779,7 @@ public class NotificationsController extends BaseController { } long dialog_id = lastMessageObject.getDialogId(); - int topicId = MessageObject.getTopicId(lastMessageObject.messageOwner, getMessagesController().isForum(lastMessageObject)); + long topicId = MessageObject.getTopicId(currentAccount, lastMessageObject.messageOwner, getMessagesController().isForum(lastMessageObject)); boolean story = lastMessageObject.isStoryPush; boolean isChannel = false; @@ -4324,7 +4325,7 @@ public class NotificationsController extends BaseController { } } - private void resetNotificationSound(NotificationCompat.Builder notificationBuilder, long dialogId, int topicId, String chatName, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int chatType) { + private void resetNotificationSound(NotificationCompat.Builder notificationBuilder, long dialogId, long topicId, String chatName, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int chatType) { Uri defaultSound = Settings.System.DEFAULT_RINGTONE_URI; if (defaultSound != null && sound != null && !TextUtils.equals(defaultSound.toString(), sound.toString())) { SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); @@ -4365,7 +4366,7 @@ public class NotificationsController extends BaseController { } @SuppressLint("InlinedApi") - private void showExtraNotifications(NotificationCompat.Builder notificationBuilder, String summary, long lastDialogId, int lastTopicId, String chatName, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int chatType) { + private void showExtraNotifications(NotificationCompat.Builder notificationBuilder, String summary, long lastDialogId, long lastTopicId, String chatName, long[] vibrationPattern, int ledColor, Uri sound, int importance, boolean isDefault, boolean isInApp, boolean isSilent, int chatType) { if (Build.VERSION.SDK_INT >= 26) { notificationBuilder.setChannelId(validateChannelId(lastDialogId, lastTopicId, chatName, vibrationPattern, ledColor, sound, importance, isDefault, isInApp, isSilent, chatType)); } @@ -4388,7 +4389,7 @@ public class NotificationsController extends BaseController { for (int a = 0; a < pushMessages.size(); a++) { MessageObject messageObject = pushMessages.get(a); long dialog_id = messageObject.getDialogId(); - int topicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(messageObject)); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(messageObject)); int dismissDate = preferences.getInt("dismissDate" + dialog_id, 0); if (!messageObject.isStoryPush && messageObject.messageOwner.date <= dismissDate) { continue; @@ -4412,14 +4413,14 @@ public class NotificationsController extends BaseController { class NotificationHolder { int id; long dialogId; - int topicId; + long topicId; boolean story; String name; TLRPC.User user; TLRPC.Chat chat; NotificationCompat.Builder notification; - NotificationHolder(int i, long li, boolean story, int topicId, String n, TLRPC.User u, TLRPC.Chat c, NotificationCompat.Builder builder) { + NotificationHolder(int i, long li, boolean story, long topicId, String n, TLRPC.User u, TLRPC.Chat c, NotificationCompat.Builder builder) { id = i; name = n; user = u; @@ -4462,7 +4463,8 @@ public class NotificationsController extends BaseController { } DialogKey dialogKey = sortedDialogs.get(b); long dialogId; - int topicId, maxId; + long topicId; + int maxId; MessageObject lastMessageObject = null; ArrayList messageObjects; if (dialogKey.story) { @@ -4525,7 +4527,7 @@ public class NotificationsController extends BaseController { photoPath = user.photo.photo_small; } } else if (!DialogObject.isEncryptedDialog(dialogId)) { - canReply = dialogId != 777000; + canReply = (lastMessageObject != null && !lastMessageObject.isReactionPush) && dialogId != 777000; if (DialogObject.isUserDialog(dialogId)) { user = getMessagesController().getUser(dialogId); if (user == null) { @@ -4758,7 +4760,7 @@ public class NotificationsController extends BaseController { } else { for (int a = messageObjects.size() - 1; a >= 0; a--) { MessageObject messageObject = messageObjects.get(a); - int messageTopicId = MessageObject.getTopicId(messageObject.messageOwner, getMessagesController().isForum(messageObject)); + long messageTopicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, getMessagesController().isForum(messageObject)); if (topicId != messageTopicId) { continue; } @@ -5374,7 +5376,7 @@ public class NotificationsController extends BaseController { public static final int SETTING_MUTE_UNMUTE = 4; public static final int SETTING_MUTE_CUSTOM = 5; - public void clearDialogNotificationsSettings(long did, int topicId) { + public void clearDialogNotificationsSettings(long did, long topicId) { SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); SharedPreferences.Editor editor = preferences.edit(); String prefKey = NotificationsController.getSharedPrefKey(did, topicId); @@ -5388,7 +5390,7 @@ public class NotificationsController extends BaseController { getNotificationsController().updateServerNotificationsSettings(did, topicId,true); } - public void setDialogNotificationsSettings(long dialog_id, int topicId, int setting) { + public void setDialogNotificationsSettings(long dialog_id, long topicId, int setting) { SharedPreferences preferences = getAccountInstance().getNotificationsSettings(); SharedPreferences.Editor editor = preferences.edit(); TLRPC.Dialog dialog = MessagesController.getInstance(UserConfig.selectedAccount).dialogs_dict.get(dialog_id); @@ -5435,11 +5437,11 @@ public class NotificationsController extends BaseController { updateServerNotificationsSettings(dialog_id, topicId); } - public void updateServerNotificationsSettings(long dialog_id, int topicId) { + public void updateServerNotificationsSettings(long dialog_id, long topicId) { updateServerNotificationsSettings(dialog_id, topicId, true); } - public void updateServerNotificationsSettings(long dialogId, int topicId, boolean post) { + public void updateServerNotificationsSettings(long dialogId, long topicId, boolean post) { if (post) { getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); } @@ -5492,10 +5494,10 @@ public class NotificationsController extends BaseController { } else { req.settings.sound = new TLRPC.TL_notificationSoundDefault(); } - if (topicId != 0) { + if (topicId != 0 && dialogId != getUserConfig().getClientUserId()) { TLRPC.TL_inputNotifyForumTopic topicPeer = new TLRPC.TL_inputNotifyForumTopic(); topicPeer.peer = getMessagesController().getInputPeer(dialogId); - topicPeer.top_msg_id = topicId; + topicPeer.top_msg_id = (int) topicId; req.peer = topicPeer; } else { req.peer = new TLRPC.TL_inputNotifyPeer(); @@ -5625,7 +5627,7 @@ public class NotificationsController extends BaseController { } } - public void muteDialog(long dialog_id, int topicId, boolean mute) { + public void muteDialog(long dialog_id, long topicId, boolean mute) { if (mute) { NotificationsController.getInstance(currentAccount).muteUntil(dialog_id, topicId, Integer.MAX_VALUE); } else { @@ -5683,10 +5685,10 @@ public class NotificationsController extends BaseController { private static class DialogKey { final long dialogId; - final int topicId; + final long topicId; final boolean story; - private DialogKey(long dialogId, int topicId, boolean story) { + private DialogKey(long dialogId, long topicId, boolean story) { this.dialogId = dialogId; this.topicId = topicId; this.story = story; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsSettingsFacade.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsSettingsFacade.java index 5cce19407..597e75cfc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsSettingsFacade.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsSettingsFacade.java @@ -24,12 +24,12 @@ public class NotificationsSettingsFacade { } - public boolean isDefault(long dialogId, int topicId) { + public boolean isDefault(long dialogId, long topicId) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId, true); return false; } - public void clearPreference(long dialogId, int topicId) { + public void clearPreference(long dialogId, long topicId) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId, true); getPreferences().edit() .remove(PROPERTY_NOTIFY + key) @@ -43,7 +43,7 @@ public class NotificationsSettingsFacade { } - public int getProperty(String property, long dialogId, int topicId, int defaultValue) { + public int getProperty(String property, long dialogId, long topicId, int defaultValue) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId, true); if (getPreferences().contains(property + key)) { return getPreferences().getInt(property + key, defaultValue); @@ -52,7 +52,7 @@ public class NotificationsSettingsFacade { return getPreferences().getInt(property + key, defaultValue); } - public long getProperty(String property, long dialogId, int topicId, long defaultValue) { + public long getProperty(String property, long dialogId, long topicId, long defaultValue) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId, true); if (getPreferences().contains(property + key)) { return getPreferences().getLong(property + key, defaultValue); @@ -61,7 +61,7 @@ public class NotificationsSettingsFacade { return getPreferences().getLong(property + key, defaultValue); } - public boolean getProperty(String property, long dialogId, int topicId, boolean defaultValue) { + public boolean getProperty(String property, long dialogId, long topicId, boolean defaultValue) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId); if (getPreferences().contains(property + key)) { return getPreferences().getBoolean(property + key, defaultValue); @@ -70,7 +70,7 @@ public class NotificationsSettingsFacade { return getPreferences().getBoolean(property + key, defaultValue); } - public String getPropertyString(String property, long dialogId, int topicId, String defaultValue) { + public String getPropertyString(String property, long dialogId, long topicId, String defaultValue) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId); if (getPreferences().contains(property + key)) { return getPreferences().getString(property + key, defaultValue); @@ -80,7 +80,7 @@ public class NotificationsSettingsFacade { } - public void removeProperty(String property, long dialogId, int topicId) { + public void removeProperty(String property, long dialogId, long topicId) { String key = NotificationsController.getSharedPrefKey(dialogId, topicId); getPreferences().edit().remove(property + key).apply(); } @@ -89,7 +89,7 @@ public class NotificationsSettingsFacade { return MessagesController.getNotificationsSettings(currentAccount); } - public void applyDialogNotificationsSettings(long dialogId, int topicId, TLRPC.PeerNotifySettings notify_settings) { + public void applyDialogNotificationsSettings(long dialogId, long topicId, TLRPC.PeerNotifySettings notify_settings) { if (notify_settings == null) { return; } @@ -183,7 +183,7 @@ public class NotificationsSettingsFacade { }); } - public void applySoundSettings(TLRPC.NotificationSound settings, SharedPreferences.Editor editor, long dialogId, int topicId, int globalType, boolean serverUpdate) { + public void applySoundSettings(TLRPC.NotificationSound settings, SharedPreferences.Editor editor, long dialogId, long topicId, int globalType, boolean serverUpdate) { if (settings == null) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java index a3896ed82..1f6b675aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java @@ -1,76 +1,1143 @@ package org.telegram.messenger; +import android.os.Bundle; +import android.text.TextUtils; + import androidx.collection.LongSparseArray; +import com.google.android.exoplayer2.util.Log; +import com.google.android.exoplayer2.util.Util; + import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.LaunchActivity; +import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.Objects; public class SavedMessagesController { private final int currentAccount; - - public boolean loading, loaded; - public LongSparseArray> messages = new LongSparseArray>(); + public boolean unsupported; public SavedMessagesController(int account) { this.currentAccount = account; + unsupported = MessagesController.getMainSettings(currentAccount).getBoolean("savedMessagesUnsupported", true); } - public void getSavedMessagesDialogs() { - if (loaded || loading) { + public void cleanup() { + cachedDialogs.clear(); + loadedDialogs.clear(); + dialogsLoaded = false; + dialogsCount = 0; + dialogsCountHidden = 0; + dialogsEndReached = false; + loadedCache = true; + deleteCache(); + unsupported = true; + MessagesController.getMainSettings(currentAccount).edit().remove("savedMessagesUnsupported").apply(); + } + + private ArrayList cachedDialogs = new ArrayList<>(); + + private boolean dialogsLoading, dialogsLoaded; + public boolean dialogsEndReached; + private int dialogsCount; + private int dialogsCountHidden; + private ArrayList loadedDialogs = new ArrayList<>(); + + public ArrayList allDialogs = new ArrayList<>(); + private void updateAllDialogs(boolean notify) { + allDialogs.clear(); + HashSet ids = new HashSet<>(); + for (int i = 0; i < cachedDialogs.size(); ++i) { + SavedDialog d = cachedDialogs.get(i); + if (d.pinned && !ids.contains(d.dialogId) && !d.isHidden()) { + allDialogs.add(d); + ids.add(d.dialogId); + } + } + for (int i = 0; i < loadedDialogs.size(); ++i) { + SavedDialog d = loadedDialogs.get(i); + if (d.pinned && !ids.contains(d.dialogId) && !d.isHidden()) { + allDialogs.add(d); + ids.add(d.dialogId); + } + } + ArrayList dialogs = new ArrayList<>(); + for (int i = 0; i < loadedDialogs.size(); ++i) { + SavedDialog d = loadedDialogs.get(i); + if (!ids.contains(d.dialogId) && !d.isHidden()) { + dialogs.add(d); + ids.add(d.dialogId); + } + } + if (!dialogsEndReached) { + for (int i = 0; i < cachedDialogs.size(); ++i) { + SavedDialog d = cachedDialogs.get(i); + if (!ids.contains(d.dialogId) && !d.isHidden()) { + dialogs.add(d); + ids.add(d.dialogId); + } + } + } + Collections.sort(dialogs, (d1, d2) -> d2.getDate() - d1.getDate()); + allDialogs.addAll(dialogs); + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.savedMessagesDialogsUpdate); + } + } + + public int getAllCount() { + if (dialogsEndReached) { + return allDialogs.size(); + } + if (dialogsLoaded) { + return dialogsCount - dialogsCountHidden; + } + return cachedDialogs.size(); + } + + public int getLoadedCount() { + return loadedDialogs.size(); + } + + public int getPinnedCount() { + int count = 0; + for (int i = 0; i < allDialogs.size(); ++i) { + if (allDialogs.get(i).pinned) { + count++; + } + } + return count; + } + + public SavedDialog findSavedDialog(long did) { + return findSavedDialog(allDialogs, did); + } + + public SavedDialog findSavedDialog(ArrayList dialogs, long did) { + for (int i = 0; i < dialogs.size(); ++i) { + SavedDialog d = dialogs.get(i); + if (d.dialogId == did) { + return d; + } + } + return null; + } + + public ArrayList searchDialogs(String q) { + ArrayList result = new ArrayList<>(); + if (TextUtils.isEmpty(q)) return result; + String lq = AndroidUtilities.translitSafe(q.toLowerCase()); + for (int i = 0; i < allDialogs.size(); ++i) { + SavedDialog d = allDialogs.get(i); + final String name; + String name2 = null; + if (d.dialogId == UserObject.ANONYMOUS) { + name = LocaleController.getString(R.string.AnonymousForward); + } else if (d.dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { + name = LocaleController.getString(R.string.MyNotes); + name2 = LocaleController.getString(R.string.SavedMessages); + } else if (d.dialogId >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(d.dialogId); + name = UserObject.getUserName(user); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-d.dialogId); + name = chat != null ? chat.title : ""; + } + if (name == null) continue; + String lname = AndroidUtilities.translitSafe(name.toLowerCase()); + if (lname.startsWith(lq) || lname.contains(" " + lq)) { + result.add(d); + } else if (name2 != null) { + lname = AndroidUtilities.translitSafe(name2.toLowerCase()); + if (lname.startsWith(lq) || lname.contains(" " + lq)) { + result.add(d); + } + } + } + return result; + } + + public int getMessagesCount(long dialogId) { + for (int i = 0; i < allDialogs.size(); ++i) { + SavedDialog d = allDialogs.get(i); + if (d.dialogId == dialogId) + return d.messagesCount; + } + return 0; + } + + public boolean containsDialog(long dialogId) { + for (int i = 0; i < allDialogs.size(); ++i) { + SavedDialog d = allDialogs.get(i); + if (d.dialogId == dialogId) + return true; + } + return false; + } + + public void preloadDialogs() { + if (!dialogsLoaded) { + loadDialogs(); + } + } + + public void loadDialogs() { + if (dialogsLoading || dialogsEndReached || loadingCache) { return; } - loading = true; - final long myself = UserConfig.getInstance(currentAccount).getClientUserId(); - MessagesStorage storage = MessagesStorage.getInstance(currentAccount); - storage.getStorageQueue().postRunnable(() -> { - SQLiteDatabase database = storage.getDatabase(); - SQLiteCursor cursor = null; - final LongSparseArray> messages = new LongSparseArray<>(); - try { - cursor = database.queryFinalized("SELECT data, mid, date, send_state, read_state, custom_params FROM messages_v2 WHERE out = 0 AND uid = ?", myself); - while (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - if (message.fwd_from == null || message.fwd_from.saved_from_peer == null) { - continue; - } - long did = DialogObject.getPeerDialogId(message.fwd_from.saved_from_peer); + if (!loadedCache) { + loadCache(this::loadDialogs); + return; + } + dialogsLoading = true; - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.send_state = cursor.intValue(3); - MessageObject.setUnreadFlags(message, cursor.intValue(4)); + TLRPC.TL_messages_getSavedDialogs req = new TLRPC.TL_messages_getSavedDialogs(); + SavedDialog lastDialog = loadedDialogs.isEmpty() ? null : loadedDialogs.get(loadedDialogs.size() - 1); - MessageObject messageObject = new MessageObject(currentAccount, message, true, true); - ArrayList messageObjects = messages.get(did); - if (messageObjects == null) { - messages.put(did, messageObjects = new ArrayList<>()); + if (lastDialog != null) { + req.offset_id = lastDialog.top_message_id; + req.offset_date = lastDialog.getDate(); + req.offset_peer = MessagesController.getInstance(currentAccount).getInputPeer(lastDialog.dialogId); + } else { + req.offset_id = Integer.MAX_VALUE; + req.offset_date = 0; + req.offset_peer = new TLRPC.TL_inputPeerEmpty(); + } + req.limit = 20; + + final ArrayList expectedDialogs = new ArrayList<>(); + expectedDialogs.addAll(allDialogs.subList( + Math.min(loadedDialogs.size(), allDialogs.size()), + Math.min(loadedDialogs.size() + req.limit, allDialogs.size()) + )); + for (int i = 0; i < expectedDialogs.size(); ++i) { + SavedDialog d = expectedDialogs.get(i); + req.hash = MediaDataController.calcHash(req.hash, d.pinned ? 1 : 0); + req.hash = MediaDataController.calcHash(req.hash, Math.abs(d.dialogId)); + req.hash = MediaDataController.calcHash(req.hash, d.top_message_id); + req.hash = MediaDataController.calcHash(req.hash, d.getDate()); + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + final boolean wasUnsupported = unsupported; + if (res instanceof TLRPC.TL_messages_savedDialogs) { + dialogsLoaded = true; + TLRPC.TL_messages_savedDialogs r = (TLRPC.TL_messages_savedDialogs) res; + MessagesController.getInstance(currentAccount).putUsers(r.users, false); + MessagesController.getInstance(currentAccount).putChats(r.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(r.users, r.chats, true, true); + MessagesStorage.getInstance(currentAccount).putMessages(r.messages, false, true, false, 0, false, ChatActivity.MODE_SAVED, 0); + for (int i = 0; i < r.dialogs.size(); ++i) { + SavedDialog d = SavedDialog.fromTL(currentAccount, r.dialogs.get(i), r.messages); + for (int j = 0; j < cachedDialogs.size(); ++j) { + if (cachedDialogs.get(j).dialogId == d.dialogId) { + d.messagesCount = cachedDialogs.get(j).messagesCount; + cachedDialogs.get(j).pinned = d.pinned; + break; } - messageObjects.add(messageObject); + } + boolean found = false; + for (int j = 0; j < loadedDialogs.size(); ++j) { + if (loadedDialogs.get(j).dialogId == d.dialogId) { + found = true; + break; + } + } + if (!found) { + loadedDialogs.add(d); + if (d.isHidden()) + dialogsCountHidden++; } } + dialogsEndReached = true; + dialogsCount = r.dialogs.size(); + updateAllDialogs(true); + saveCacheSchedule(); + unsupported = false; + } else if (res instanceof TLRPC.TL_messages_savedDialogsSlice) { + dialogsLoaded = true; + TLRPC.TL_messages_savedDialogsSlice r = (TLRPC.TL_messages_savedDialogsSlice) res; + MessagesController.getInstance(currentAccount).putUsers(r.users, false); + MessagesController.getInstance(currentAccount).putChats(r.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(r.users, r.chats, true, true); + MessagesStorage.getInstance(currentAccount).putMessages(r.messages, false, true, false, 0, false, ChatActivity.MODE_SAVED, 0); + for (int i = 0; i < r.dialogs.size(); ++i) { + SavedDialog d = SavedDialog.fromTL(currentAccount, r.dialogs.get(i), r.messages); + for (int j = 0; j < cachedDialogs.size(); ++j) { + if (cachedDialogs.get(j).dialogId == d.dialogId) { + d.messagesCount = cachedDialogs.get(j).messagesCount; + cachedDialogs.get(j).pinned = d.pinned; + break; + } + } + boolean found = false; + for (int j = 0; j < loadedDialogs.size(); ++j) { + if (loadedDialogs.get(j).dialogId == d.dialogId) { + found = true; + break; + } + } + if (!found) { + loadedDialogs.add(d); + if (d.isHidden()) + dialogsCountHidden++; + } + } + dialogsCount = r.count; + dialogsEndReached = getPinnedCount() + loadedDialogs.size() >= dialogsCount || r.dialogs.size() == 0; + updateAllDialogs(true); + saveCacheSchedule(); + unsupported = false; + } else if (res instanceof TLRPC.TL_messages_savedDialogsNotModified) { + dialogsLoaded = true; + loadedDialogs.addAll(expectedDialogs); + dialogsCount = ((TLRPC.TL_messages_savedDialogsNotModified) res).count; + dialogsCountHidden = 0; + for (int i = 0; i < expectedDialogs.size(); ++i) { + if (expectedDialogs.get(i).isHidden()) { + dialogsCountHidden++; + } + } + dialogsEndReached = loadedDialogs.size() >= dialogsCount; + unsupported = false; + } else if (err != null) { + dialogsLoaded = true; + if ("SAVED_DIALOGS_UNSUPPORTED".equals(err.text)) { + unsupported = true; + } + } + if (unsupported != wasUnsupported) { + MessagesController.getMainSettings(currentAccount).edit().putBoolean("savedMessagesUnsupported", unsupported).apply(); + } - AndroidUtilities.runOnUIThread(() -> { - SavedMessagesController.this.messages.clear(); - SavedMessagesController.this.messages.putAll(messages); - loading = false; - }); - } catch (SQLiteException e) { - e.printStackTrace(); + dialogsLoading = false; + })); + } + + public boolean updateSavedDialogs(ArrayList inputMessages) { + if (inputMessages == null) { + return false; + } + LongSparseArray messages = new LongSparseArray<>(); + LongSparseArray messagesCount = new LongSparseArray<>(); + HashSet dialogsCountToCheck = new HashSet<>(); + long self = UserConfig.getInstance(currentAccount).getClientUserId(); + for (int i = 0; i < inputMessages.size(); ++i) { + TLRPC.Message message = inputMessages.get(i); + long dialogId = MessageObject.getSavedDialogId(self, message); + if (dialogId != self && (message.id < 0 || message.send_state != 0 && message.fwd_from != null)) { + // we might not know does user privacy hide fwd_from.from_id + continue; + } + TLRPC.Message existingMessage = messages.get(dialogId); + if (existingMessage == null || existingMessage.id < message.id) { + messages.put(dialogId, message); + } + Integer count = messagesCount.get(dialogId); + messagesCount.put(dialogId, (count == null ? 0 : count) + 1); + } + + boolean changed = false; + for (int i = 0; i < messages.size(); ++i) { + long dialogId = messages.keyAt(i); + TLRPC.Message message = messages.valueAt(i); + Integer newMessagesCount = messagesCount.get(dialogId); + boolean found = false; + for (int j = 0; j < cachedDialogs.size(); ++j) { + SavedDialog d = cachedDialogs.get(j); + if (d.dialogId == dialogId) { + found = true; + if (d.top_message_id < message.id || message.id < 0 && message.date > d.getDate()) { + changed = true; + d.message = new MessageObject(currentAccount, message, false, false); + d.top_message_id = d.message.getId(); + } + dialogsCountToCheck.add(d.dialogId); + break; + } + } + if (!found) { + SavedDialog d = SavedDialog.fromMessage(currentAccount, message); + if (newMessagesCount != null) { + d.messagesCount = newMessagesCount; + } + cachedDialogs.add(d); + changed = true; + } + found = false; + for (int j = 0; j < loadedDialogs.size(); ++j) { + SavedDialog d = loadedDialogs.get(j); + if (d.dialogId == dialogId) { + found = true; + if (d.top_message_id < message.id || message.id < 0 && message.date > d.getDate()) { + changed = true; + d.message = new MessageObject(currentAccount, message, false, false); + d.top_message_id = d.message.getId(); + } + dialogsCountToCheck.add(d.dialogId); + break; + } + } + if (!found) { + SavedDialog d = SavedDialog.fromMessage(currentAccount, message); + if (newMessagesCount != null) { + d.messagesCount = newMessagesCount; + } + loadedDialogs.add(d); + changed = true; + } + } + if (!dialogsCountToCheck.isEmpty()) { + updateDialogsCount(dialogsCountToCheck); + } + return changed; + } + + public boolean updateSavedDialog(TLRPC.Message message) { + if (message == null) { + return false; + } + long self = UserConfig.getInstance(currentAccount).getClientUserId(); + long dialogId = MessageObject.getSavedDialogId(self, message); + for (int i = 0; i < allDialogs.size(); ++i) { + SavedDialog d = allDialogs.get(i); + if (d.dialogId == dialogId) { + d.message = new MessageObject(currentAccount, message, false, false); + d.top_message_id = d.message.getId(); + return true; + } + } + return false; + } + + public boolean updatedDialogCount(long dialogId, int messagesCount) { + for (int i = 0; i < allDialogs.size(); ++i) { + SavedDialog d = allDialogs.get(i); + if (d.dialogId == dialogId) { + if (d.messagesCount != messagesCount) { + d.messagesCount = messagesCount; + return true; + } + break; + } + } + return false; + } + + public void update(long dialogId, TLRPC.messages_Messages messagesRes) { + boolean changed = false; + changed = updateSavedDialogs(messagesRes.messages) || changed; + if (messagesRes instanceof TLRPC.TL_messages_messagesSlice) { + changed = updatedDialogCount(dialogId, messagesRes.count) || changed; + } else if (messagesRes instanceof TLRPC.TL_messages_messages) { + changed = updatedDialogCount(dialogId, messagesRes.messages.size()) || changed; + } + if (changed) { + AndroidUtilities.runOnUIThread(this::update); + } + } + + public void updateDeleted(LongSparseArray> messageIds) { + boolean changed = false; + ArrayList updateDialogsLastMessageId = new ArrayList<>(); + for (int i = 0; i < messageIds.size(); ++i) { + long did = messageIds.keyAt(i); + ArrayList ids = messageIds.valueAt(i); + int maxId = 0; + for (int j = 0; j < ids.size(); ++j) { + maxId = Math.max(maxId, ids.get(j)); + } + SavedDialog d = null; + for (int j = 0; j < allDialogs.size(); ++j) { + if (allDialogs.get(j).dialogId == did) { + d = allDialogs.get(j); + break; + } + } + if (d != null) { + if (Math.max(0, d.messagesCount - ids.size()) != d.messagesCount) { + d.messagesCount = Math.max(0, d.messagesCount - ids.size()); + changed = true; + } + if (d.messagesCount <= 0) { + removeDialog(d.dialogId); + changed = true; + } else if (d.top_message_id <= maxId) { + updateDialogsLastMessageId.add(d); + changed = true; + } + } + } + if (changed) { + if (!updateDialogsLastMessageId.isEmpty()) { + updateDialogsLastMessage(updateDialogsLastMessageId); + } else { + update(); + } + } + } + + private void invalidate() { + if (dialogsLoaded && loadedDialogs.isEmpty()) { + return; + } + + // put everything in cached + for (int i = 0; i < loadedDialogs.size(); ++i) { + SavedDialog ld = loadedDialogs.get(i); + SavedDialog cd = null; + for (int j = 0; j < cachedDialogs.size(); ++j) { + SavedDialog d = cachedDialogs.get(j); + if (d.dialogId == ld.dialogId) { + cd = d; + break; + } + } + if (cd == null && !ld.pinned) { + cachedDialogs.add(ld); + } + } + // reload + loadedDialogs.clear(); + dialogsLoaded = false; + dialogsCount = 0; + dialogsEndReached = false; + update(); + loadDialogs(); + } + + public void deleteDialog(long did) { + dialogsCount -= removeDialog(did); + update(); + } + + public void deleteDialogs(ArrayList dids) { + for (int i = 0; i < dids.size(); ++i) { + dialogsCount -= removeDialog(dids.get(i)); + } + update(); + } + + private int removeDialog(long did) { + int acount = 0; + for (int i = 0; i < allDialogs.size(); ++i) { + if (allDialogs.get(i).dialogId == did) { + allDialogs.remove(i); + acount++; + i--; + } + } + int lcount = 0; + for (int i = 0; i < loadedDialogs.size(); ++i) { + if (loadedDialogs.get(i).dialogId == did) { + loadedDialogs.remove(i); + lcount++; + i--; + } + } + for (int i = 0; i < cachedDialogs.size(); ++i) { + if (cachedDialogs.get(i).dialogId == did) { + cachedDialogs.remove(i); + i--; + } + } + return Math.max(acount, lcount); + } + + public void update() { + updateAllDialogs(true); + saveCacheSchedule(); + } + + public boolean updatePinned(ArrayList dialogIds, boolean pin) { + ArrayList currentOrder = getCurrentPinnedOrder(allDialogs); + ArrayList newOrder = new ArrayList<>(currentOrder); + for (int i = dialogIds.size() - 1; i >= 0; --i) { + final long did = dialogIds.get(i); + if (pin && !newOrder.contains(did)) { + newOrder.add(0, did); + } else if (!pin) { + newOrder.remove(did); + } + } + int limit = ( + UserConfig.getInstance(currentAccount).isPremium() ? + MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitPremium : + MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitDefault + ); + if (newOrder.size() > limit) { + return false; + } + if (!sameOrder(currentOrder, newOrder)) { + updatePinnedOrderToServer(newOrder); + } + return true; + } + + public boolean updatePinnedOrder(ArrayList newOrder) { + ArrayList currentOrder = getCurrentPinnedOrder(allDialogs); + int limit = ( + UserConfig.getInstance(currentAccount).isPremium() ? + MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitPremium : + MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitDefault + ); + if (newOrder.size() > limit) { + return false; + } + if (!sameOrder(currentOrder, newOrder)) { + updatePinnedOrderToServer(newOrder); + } + return true; + } + + private void updatePinnedOrderToServer(ArrayList newOrder) { + final boolean updateLoaded = updatePinnedOrder(loadedDialogs, newOrder); + final boolean updateCached = updatePinnedOrder(cachedDialogs, newOrder); + if (updateLoaded || updateCached) { + TLRPC.TL_messages_reorderPinnedSavedDialogs req = new TLRPC.TL_messages_reorderPinnedSavedDialogs(); + req.force = true; + for (int i = 0; i < newOrder.size(); ++i) { + final long did = newOrder.get(i); + TLRPC.TL_inputDialogPeer dialogPeer = new TLRPC.TL_inputDialogPeer(); + dialogPeer.peer = MessagesController.getInstance(currentAccount).getInputPeer(did); + if (dialogPeer.peer != null) { + req.order.add(dialogPeer); + } + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + update(); + } + } + + public void processUpdate(TLRPC.Update update) { + if (processUpdateInternal(update)) { + update(); + } + } + + private boolean processUpdateInternal(TLRPC.Update update) { + if (update instanceof TLRPC.TL_updateSavedDialogPinned) { + TLRPC.TL_updateSavedDialogPinned upd = (TLRPC.TL_updateSavedDialogPinned) update; + if (!(upd.peer instanceof TLRPC.TL_dialogPeer)) return false; + long dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_dialogPeer) upd.peer).peer); + boolean changed = false; + ArrayList[] arraysToCheck = new ArrayList[] { loadedDialogs, cachedDialogs }; + for (int a = 0; a < arraysToCheck.length; ++a) { + for (int i = 0; i < arraysToCheck[a].size(); ++i) { + SavedDialog d = arraysToCheck[a].get(i); + if (d.dialogId == dialogId && d.pinned != upd.pinned) { + d.pinned = upd.pinned; + changed = true; + } + } + } + return changed; + } else if (update instanceof TLRPC.TL_updatePinnedSavedDialogs) { + TLRPC.TL_updatePinnedSavedDialogs upd = (TLRPC.TL_updatePinnedSavedDialogs) update; + ArrayList newOrder = new ArrayList<>(upd.order.size()); + for (int i = 0; i < upd.order.size(); ++i) { + TLRPC.DialogPeer dialogPeer = upd.order.get(i); + if (!(dialogPeer instanceof TLRPC.TL_dialogPeer)) { + continue; + } + newOrder.add(DialogObject.getPeerDialogId(((TLRPC.TL_dialogPeer) dialogPeer).peer)); + } + final boolean updateLoaded = updatePinnedOrder(loadedDialogs, newOrder); + final boolean updateCached = updatePinnedOrder(cachedDialogs, newOrder); + return updateLoaded || updateCached; + } + return false; + } + + private ArrayList getCurrentPinnedOrder(ArrayList dialogs) { + ArrayList currentOrder = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + SavedDialog d = dialogs.get(i); + if (d.pinned) currentOrder.add(d.dialogId); + } + return currentOrder; + } + + private boolean sameOrder(ArrayList a, ArrayList b) { + if (a.size() != b.size()) { + return false; + } + for (int i = 0; i < a.size(); ++i) { + if (!Objects.equals(a.get(i), b.get(i))) { + return false; + } + } + return true; + } + + private boolean updatePinnedOrder(ArrayList dialogs, ArrayList order) { + ArrayList currentOrder = getCurrentPinnedOrder(dialogs); + if (sameOrder(order, currentOrder)) { + return false; + } + + // remove all pinned + ArrayList oldPinned = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + SavedDialog d = dialogs.get(i); + if (d.pinned) { + d.pinned = false; + oldPinned.add(d); + dialogs.remove(i); + i--; + } + } + dialogs.addAll(oldPinned); + + // gather new pinned + ArrayList newPinned = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + SavedDialog d = dialogs.get(i); + int index; + if ((index = order.indexOf(d.dialogId)) >= 0) { + d.pinnedOrder = index; + d.pinned = true; + newPinned.add(d); + dialogs.remove(i); + i--; + } + } + + // sort other not pinned + Collections.sort(dialogs, (d1, d2) -> d2.getDate() - d1.getDate()); + + // sort pinned by new order + Collections.sort(newPinned, (d1, d2) -> d1.pinnedOrder - d2.pinnedOrder); + + // add pinned + dialogs.addAll(0, newPinned); + + return true; + } + + private void updateDialogsCount(HashSet dialogIds) { + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); + messagesStorage.getStorageQueue().postRunnable(() -> { + SQLiteDatabase db = messagesStorage.getDatabase(); + LongSparseArray countResult = new LongSparseArray<>(); + SQLiteCursor cursor = null; + try { + for (long did : dialogIds) { + cursor = db.queryFinalized("SELECT COUNT(*) FROM messages_topics WHERE uid = ? AND topic_id = ?", selfId, did); + if (cursor.next()) { + countResult.put(did, cursor.intValue(0)); + } + cursor.dispose(); + } + } catch (Exception e) { + FileLog.e(e); } finally { if (cursor != null) { cursor.dispose(); cursor = null; } } + AndroidUtilities.runOnUIThread(() -> { + boolean changed = false; + for (int i = 0; i < countResult.size(); ++i) { + long did = countResult.keyAt(i); + int count = countResult.valueAt(i); + + SavedDialog d = findSavedDialog(did); + if (d != null && d.messagesCount != count) { + d.messagesCount = count; + changed = true; + } + } + if (changed) { + update(); + } + }); }); } + + private boolean loadingCache, loadedCache; + private void loadCache(Runnable whenDone) { + if (loadingCache) { + return; + } + loadingCache = true; + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); + messagesStorage.getStorageQueue().postRunnable(() -> { + SQLiteDatabase db = messagesStorage.getDatabase(); + SQLiteCursor cursor = null; + SQLiteCursor cursor2 = null; + final ArrayList dialogs = new ArrayList<>(); + final ArrayList usersToLoad = new ArrayList<>(); + final ArrayList chatsToLoad = new ArrayList<>(); + final ArrayList emojiToLoad = new ArrayList<>(); + + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + final ArrayList emojis = new ArrayList<>(); + + try { + cursor = db.queryFinalized("SELECT did, date, last_mid, pinned, flags, folder_id, last_mid_group, count FROM saved_dialogs ORDER BY pinned ASC, date DESC"); + while (cursor.next()) { + SavedDialog d = new SavedDialog(); + d.dialogId = cursor.longValue(0); + d.localDate = cursor.intValue(1); + d.top_message_id = cursor.intValue(2); + d.pinnedOrder = cursor.intValue(3); + d.pinned = d.pinnedOrder != 999; + d.messagesCount = cursor.intValue(7); + if (d.dialogId < 0) { + chatsToLoad.add(-d.dialogId); + } else { + usersToLoad.add(d.dialogId); + } + + cursor2 = db.queryFinalized("SELECT data FROM messages_topics WHERE uid = ? AND mid = ? AND topic_id = ?", selfId, d.top_message_id, d.dialogId); + if (cursor2.next()) { + NativeByteBuffer buffer = cursor2.byteBufferValue(0); + TLRPC.Message message = TLRPC.Message.TLdeserialize(buffer, buffer.readInt32(true), true); + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, emojiToLoad); + d.message = new MessageObject(currentAccount, message, null, null, null, null, null, false, false, 0, false, false, true); + } + cursor2.dispose(); + + dialogs.add(d); + } + + if (!usersToLoad.isEmpty()) { + messagesStorage.getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + messagesStorage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + if (!emojiToLoad.isEmpty()) { + messagesStorage.getAnimatedEmoji(TextUtils.join(",", emojiToLoad), emojis); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + cursor = null; + } + if (cursor2 != null) { + cursor2.dispose(); + cursor2 = null; + } + } + AndroidUtilities.runOnUIThread(() -> { + loadingCache = false; + loadedCache = true; + + MessagesController.getInstance(currentAccount).putUsers(users, true); + MessagesController.getInstance(currentAccount).putChats(chats, true); + AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).processDocuments(emojis); + + cachedDialogs.clear(); + cachedDialogs.addAll(dialogs); + updateAllDialogs(true); + + if (whenDone != null) { + whenDone.run(); + } + }); + }); + } + private void updateDialogsLastMessage(ArrayList dialogs) { + final long selfId = UserConfig.getInstance(currentAccount).getClientUserId(); + MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); + messagesStorage.getStorageQueue().postRunnable(() -> { + + SQLiteDatabase db = messagesStorage.getDatabase(); + SQLiteCursor cursor = null; + + final ArrayList dialogsToDelete = new ArrayList<>(); + final LongSparseArray newMessages = new LongSparseArray<>(); + + final ArrayList usersToLoad = new ArrayList<>(); + final ArrayList chatsToLoad = new ArrayList<>(); + final ArrayList emojiToLoad = new ArrayList<>(); + + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + final ArrayList emojis = new ArrayList<>(); + + try { + for (int i = 0; i < dialogs.size(); ++i) { + SavedDialog d = dialogs.get(i); + + cursor = db.queryFinalized("SELECT mid, data FROM messages_topics WHERE uid = ? AND topic_id = ? ORDER BY mid DESC LIMIT 1", selfId, d.dialogId); + if (cursor.next()) { + int topMessageId = cursor.intValue(0); + NativeByteBuffer buffer = cursor.byteBufferValue(1); + TLRPC.Message message = TLRPC.Message.TLdeserialize(buffer, buffer.readInt32(true), true); + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad, emojiToLoad); + newMessages.put(d.dialogId, message); + } else { + dialogsToDelete.add(d.dialogId); + } + cursor.dispose(); + } + + if (!usersToLoad.isEmpty()) { + messagesStorage.getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + messagesStorage.getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + if (!emojiToLoad.isEmpty()) { + messagesStorage.getAnimatedEmoji(TextUtils.join(",", emojiToLoad), emojis); + } + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + cursor = null; + } + } + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).putUsers(users, true); + MessagesController.getInstance(currentAccount).putChats(chats, true); + AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).processDocuments(emojis); + + for (int i = 0; i < dialogsToDelete.size(); ++i) { + removeDialog(dialogsToDelete.get(i)); + } + for (int i = 0; i < newMessages.size(); ++i) { + long did = newMessages.keyAt(i); + TLRPC.Message message = newMessages.valueAt(i); + MessageObject messageObject = new MessageObject(currentAccount, message, null, null, null, null, null, false, false, 0, false, false, true); + for (int j = 0; j < loadedDialogs.size(); ++j) { + SavedDialog d = loadedDialogs.get(j); + if (d.dialogId == did) { + d.top_message_id = messageObject.getId(); + d.message = messageObject; + } + } + for (int j = 0; j < cachedDialogs.size(); ++j) { + SavedDialog d = cachedDialogs.get(j); + if (d.dialogId == did) { + d.top_message_id = messageObject.getId(); + d.message = messageObject; + } + } + } + + update(); + }); + }); + } + + private final Runnable saveCacheRunnable = this::saveCache; + private void saveCacheSchedule() { + AndroidUtilities.cancelRunOnUIThread(saveCacheRunnable); + AndroidUtilities.runOnUIThread(saveCacheRunnable, 450); + } + + private boolean saving; + private void saveCache() { + if (saving) { + return; + } + saving = true; + ArrayList dialogsToSave = new ArrayList(allDialogs); + MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); + messagesStorage.getStorageQueue().postRunnable(() -> { + SQLiteDatabase db = messagesStorage.getDatabase(); + SQLitePreparedStatement state = null; + try { + db.executeFast("DELETE FROM saved_dialogs").stepThis().dispose(); + state = db.executeFast("REPLACE INTO saved_dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + for (int i = 0; i < dialogsToSave.size(); ++i) { + SavedDialog d = dialogsToSave.get(i); + state.requery(); + state.bindLong(1, d.dialogId); + state.bindInteger(2, d.getDate()); + state.bindInteger(3, d.top_message_id); + state.bindInteger(4, d.pinned ? i : 999); + state.bindInteger(5, 0); + state.bindInteger(6, 0); + state.bindInteger(7, 0); + state.bindInteger(8, d.messagesCount); + state.step(); + } + state.dispose(); + + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { + state.dispose(); + state = null; + } + } + AndroidUtilities.runOnUIThread(() -> { + saving = false; + }); + }); + } + private void deleteCache() { + if (saving) { + return; + } + saving = true; + MessagesStorage messagesStorage = MessagesStorage.getInstance(currentAccount); + messagesStorage.getStorageQueue().postRunnable(() -> { + SQLiteDatabase db = messagesStorage.getDatabase(); + try { + db.executeFast("DELETE FROM saved_dialogs").stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + AndroidUtilities.runOnUIThread(() -> { + saving = false; + loadedCache = false; + }); + }); + } + + public static class SavedDialog { + public long dialogId; + public boolean pinned; + public int top_message_id; + public MessageObject message; + public int messagesCount; + + // used only in cache + private int localDate; + + // used only when sorting in update + private int pinnedOrder; + + public int getDate() { + if (message == null || message.messageOwner == null) { + return localDate; + } + if ((message.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0) { + return message.messageOwner.edit_date; + } + return message.messageOwner.date; + } + + public boolean isHidden() { + return message != null && message.messageOwner != null && message.messageOwner.action instanceof TLRPC.TL_messageActionHistoryClear; + } + + public static SavedDialog fromMessage(int currentAccount, TLRPC.Message message) { + SavedDialog d = new SavedDialog(); + d.dialogId = MessageObject.getSavedDialogId(UserConfig.getInstance(currentAccount).getClientUserId(), message); + d.pinned = false; + d.top_message_id = message.id; + d.message = new MessageObject(currentAccount, message, null, null, null, null, null, false, false, 0, false, false, true); + return d; + } + + public static SavedDialog fromTL(int currentAccount, TLRPC.TL_savedDialog tl, ArrayList messages) { + SavedDialog d = new SavedDialog(); + d.dialogId = DialogObject.getPeerDialogId(tl.peer); + d.pinned = tl.pinned; + d.top_message_id = tl.top_message; + TLRPC.Message message = null; + for (int i = 0; i < messages.size(); ++i) { + TLRPC.Message msg = messages.get(i); + if (d.top_message_id == msg.id) { + message = msg; + break; + } + } + if (message != null) { + d.message = new MessageObject(currentAccount, message, null, null, null, null, null, false, false, 0, false, false, true); + } + return d; + } + } + public static void openSavedMessages() { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment == null) { + return; + } + Bundle args = new Bundle(); + args.putLong("user_id", UserConfig.getInstance(lastFragment.getCurrentAccount()).getClientUserId()); + lastFragment.presentFragment(new ChatActivity(args)); + } + + private final LongSparseArray>> checkMessagesCallbacks = new LongSparseArray<>(); + public void hasSavedMessages(long did, Utilities.Callback whenDone) { + if (whenDone == null) return; + + final SavedDialog savedDialog = findSavedDialog(did); + if (savedDialog != null && savedDialog.messagesCount > 0) { + whenDone.run(true); + return; + } + + ArrayList> existingCallbacks = checkMessagesCallbacks.get(did); + if (existingCallbacks != null) { + existingCallbacks.add(whenDone); + return; + } + existingCallbacks = new ArrayList<>(); + existingCallbacks.add(whenDone); + checkMessagesCallbacks.put(did, existingCallbacks); + + TLRPC.TL_messages_getSavedHistory req = new TLRPC.TL_messages_getSavedHistory(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(did); + req.limit = 1; + req.hash = 0; + req.offset_id = Integer.MAX_VALUE; + req.offset_date = Integer.MAX_VALUE; + req.add_offset = -1; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.messages_Messages) { + TLRPC.messages_Messages r = (TLRPC.messages_Messages) res; + int count = r.messages.size(); + if (r instanceof TLRPC.TL_messages_messagesSlice) { + count = ((TLRPC.TL_messages_messagesSlice) r).count; + } + + MessagesController.getInstance(currentAccount).putUsers(r.users, false); + MessagesController.getInstance(currentAccount).putChats(r.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(r.users, r.chats, true, true); + + boolean hasMessages = count > 0; + if (count > 0) { + if (!updatedDialogCount(did, count)) { + if (!r.messages.isEmpty()) { + SavedDialog dialog = SavedDialog.fromMessage(currentAccount, r.messages.get(0)); + dialog.messagesCount = count; + cachedDialogs.add(dialog); + update(); + } + } + } + + ArrayList> callbacks = checkMessagesCallbacks.get(did); + checkMessagesCallbacks.remove(did); + if (callbacks != null) { + for (int i = 0; i < callbacks.size(); ++i) { + callbacks.get(i).run(hasMessages); + } + } + } + })); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java index 3880ca670..e003ac849 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -154,7 +154,7 @@ public class SecretChatHelper extends BaseController { ArrayList arr = new ArrayList<>(); arr.add(newMsg); - getMessagesStorage().putMessages(arr, false, true, true, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, true, 0, false, 0, 0); return newMsg; } @@ -534,7 +534,7 @@ public class SecretChatHelper extends BaseController { ImageLoader.getInstance().replaceImageInCache(fileName, fileName2, ImageLocation.getForPhoto(size, newMsg.media.photo), true); ArrayList arr = new ArrayList<>(); arr.add(newMsg); - getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0, 0); //getMessagesStorage().putSentFile(originalPath, newMsg.media.photo, 3); } else if (newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { @@ -568,7 +568,7 @@ public class SecretChatHelper extends BaseController { ArrayList arr = new ArrayList<>(); arr.add(newMsg); - getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, 0, 0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 274bd9fdc..6443c9c13 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -1134,7 +1134,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList messages = new ArrayList<>(); messages.add(obj.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, obj.scheduled, 0); + getMessagesStorage().putMessages(messages, false, true, false, 0, obj.scheduled ? 1 : 0, 0); break; } } @@ -1145,7 +1145,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList messages = new ArrayList<>(); messages.add(message.obj.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, message.obj.scheduled, 0); + getMessagesStorage().putMessages(messages, false, true, false, 0, message.obj.scheduled ? 1 : 0, 0); break; } } @@ -1216,7 +1216,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe messageObject.messageOwner.attachPath = cacheFile.toString(); ArrayList messages = new ArrayList<>(); messages.add(messageObject.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, messageObject.scheduled, 0); + getMessagesStorage().putMessages(messages, false, true, false, 0, messageObject.scheduled ? 1 : 0, 0); getNotificationCenter().postNotificationName(NotificationCenter.updateMessageMedia, messageObject.messageOwner); message.photoSize = photo.sizes.get(photo.sizes.size() - 1); message.locationParent = photo; @@ -1265,7 +1265,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } ArrayList messages = new ArrayList<>(); messages.add(messageObject.messageOwner); - getMessagesStorage().putMessages(messages, false, true, false, 0, messageObject.scheduled, 0); + getMessagesStorage().putMessages(messages, false, true, false, 0, messageObject.scheduled ? 1 : 0, 0); message.performMediaUpload = true; performSendDelayedMessage(message); getNotificationCenter().postNotificationName(NotificationCenter.updateMessageMedia, message.obj.messageOwner); @@ -1328,7 +1328,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList arr = new ArrayList<>(); arr.add(object.messageOwner); - getMessagesStorage().putMessages(arr, false, true, false, 0, object.scheduled, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, object.scheduled ? 1 : 0, 0); ArrayList arrayList = new ArrayList<>(); arrayList.add(object); @@ -1406,7 +1406,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); messagesRes.messages.add(prevMessage.messageOwner); - getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduled, 0); + getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduled ? 1 : 0, 0); } if (!checkReadyToSendGroups.contains(message)) { checkReadyToSendGroups.add(message); @@ -1620,7 +1620,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); ArrayList arr = new ArrayList<>(); arr.add(message); - getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(arr, false, true, false, 0, false, 0, 0); performSendMessageRequest(req, newMsgObj, null, null, null, null, false); } @@ -2140,7 +2140,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } if (arr.size() == 100 || a == messages.size() - 1 || a != messages.size() - 1 && messages.get(a + 1).getDialogId() != msgObj.getDialogId()) { - getMessagesStorage().putMessages(new ArrayList<>(arr), false, true, false, 0, scheduleDate != 0, 0); + getMessagesStorage().putMessages(new ArrayList<>(arr), false, true, false, 0, scheduleDate != 0 ? 1 : 0, 0); getMessagesController().updateInterfaceWithMessages(peer, objArr, scheduleDate != 0); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); getUserConfig().saveConfig(false); @@ -2261,7 +2261,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe messageIds.add(oldId); getMessagesController().deleteMessages(messageIds, null, null, newMsgObj1.dialog_id, false, true); getMessagesStorage().getStorageQueue().postRunnable(() -> { - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, false, 0); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, 0, 0); AndroidUtilities.runOnUIThread(() -> { ArrayList messageObjects = new ArrayList<>(); messageObjects.add(new MessageObject(msgObj.currentAccount, msgObj.messageOwner, true, true)); @@ -2275,7 +2275,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } else { getMessagesStorage().getStorageQueue().postRunnable(() -> { getMessagesStorage().updateMessageStateAndId(newMsgObj1.random_id, MessageObject.getPeerId(peer_id), oldId, newMsgObj1.id, 0, false, scheduleDate != 0 ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduleDate != 0, 0); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduleDate != 0 ? 1 : 0, 0); AndroidUtilities.runOnUIThread(() -> { newMsgObj1.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; getMediaDataController().increasePeerRaiting(peer); @@ -2542,7 +2542,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList arr = new ArrayList<>(); arr.add(newMsg); - getMessagesStorage().putMessages(arr, false, true, false, 0, messageObject.scheduled, MessageObject.getTopicId(newMsg, getMessagesController().isForum(newMsg))); + getMessagesStorage().putMessages(arr, false, true, false, 0, messageObject.scheduled ? 1 : 0, 0); getMessagesController().getTopicsController().processEditedMessage(newMsg); messageObject.type = -1; @@ -3971,7 +3971,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } } if (isForum) { - anotherTopic = replyToTopMsg.getId() != replyToMsg.getId() && MessageObject.getTopicId(replyToMsg.messageOwner, true) != replyToTopMsg.getId(); + anotherTopic = replyToTopMsg.getId() != replyToMsg.getId() && MessageObject.getTopicId(currentAccount, replyToMsg.messageOwner, true) != replyToTopMsg.getId(); } } if (anotherChat || anotherTopic) { @@ -4036,6 +4036,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } if (newMsgObj.videoEditedInfo != null && videoEditedInfo == null) { videoEditedInfo = newMsgObj.videoEditedInfo; + } else if (videoEditedInfo != null && videoEditedInfo.notReadyYet) { + newMsgObj.videoEditedInfo.notReadyYet = videoEditedInfo.notReadyYet; } if (groupId == 0) { @@ -4043,7 +4045,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe objArr.add(newMsgObj); ArrayList arr = new ArrayList<>(); arr.add(newMsg); - MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, scheduleDate != 0, 0); + MessagesStorage.getInstance(currentAccount).putMessages(arr, false, true, false, 0, scheduleDate != 0 ? 1 : 0, 0); MessagesController.getInstance(currentAccount).updateInterfaceWithMessages(peer, objArr, scheduleDate != 0); if (scheduleDate == 0) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogsNeedReload); @@ -5057,10 +5059,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe location = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + document.id + ".mp4"; } putToDelayedMessages(location, message); - if (message.obj.videoEditedInfo != null && message.obj.videoEditedInfo.needConvert()) { - getFileLoader().uploadFile(location, false, false, document.size, ConnectionsManager.FileTypeVideo, false); - } else { - getFileLoader().uploadFile(location, false, false, ConnectionsManager.FileTypeVideo); + if (message.obj.videoEditedInfo == null || !message.obj.videoEditedInfo.notReadyYet) { + if (message.obj.videoEditedInfo != null && message.obj.videoEditedInfo.needConvert()) { + getFileLoader().uploadFile(location, false, false, document.size, ConnectionsManager.FileTypeVideo, false); + } else { + getFileLoader().uploadFile(location, false, false, ConnectionsManager.FileTypeVideo); + } } putToUploadingMessages(message.obj); } else { @@ -5392,7 +5396,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe return; } else if (add) { delayedMessages.remove(key); - getMessagesStorage().putMessages(message.messages, false, true, false, 0, message.scheduled, 0); + getMessagesStorage().putMessages(message.messages, false, true, false, 0, message.scheduled ? 1 : 0, 0); getMessagesController().updateInterfaceWithMessages(message.peer, message.messageObjects, message.scheduled); if (!message.scheduled) { getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); @@ -5731,7 +5735,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id, existFlags, scheduled); getMessagesStorage().getStorageQueue().postRunnable(() -> { getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled, 0); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled ? 1 : 0, 0); AndroidUtilities.runOnUIThread(() -> { getMediaDataController().increasePeerRaiting(newMsgObj.dialog_id); getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, grouped_id, existFlags, scheduled); @@ -6035,7 +6039,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe messageIds.add(oldId); getMessagesController().deleteMessages(messageIds, null, null, newMsgObj.dialog_id, false, true); getMessagesStorage().getStorageQueue().postRunnable(() -> { - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, false, 0); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, false, 0, 0); AndroidUtilities.runOnUIThread(() -> { ArrayList messageObjects = new ArrayList<>(); messageObjects.add(new MessageObject(msgObj.currentAccount, msgObj.messageOwner, true, true)); @@ -6049,7 +6053,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L, existFlags, scheduled); getMessagesStorage().getStorageQueue().postRunnable(() -> { getMessagesStorage().updateMessageStateAndId(newMsgObj.random_id, MessageObject.getPeerId(newMsgObj.peer_id), oldId, newMsgObj.id, 0, false, scheduled ? 1 : 0); - getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled, 0); + getMessagesStorage().putMessages(sentMessages, true, false, false, 0, scheduled ? 1 : 0, 0); AndroidUtilities.runOnUIThread(() -> { getMediaDataController().increasePeerRaiting(newMsgObj.dialog_id); getNotificationCenter().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, newMsgObj.dialog_id, 0L, existFlags, scheduled); @@ -6987,7 +6991,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); messagesRes.messages.add(prevMessage.messageOwner); - accountInstance.getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduleDate != 0, 0); + accountInstance.getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduleDate != 0 ? 1 : 0, 0); instance.sendReadyToSendGroup(message, true, true); } }); @@ -7478,7 +7482,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } @UiThread - public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, int topicId, boolean notify, int scheduleDate) { + public static void prepareSendingText(AccountInstance accountInstance, String text, long dialogId, long topicId, boolean notify, int scheduleDate) { accountInstance.getMessagesStorage().getStorageQueue().postRunnable(() -> Utilities.stageQueue.postRunnable(() -> AndroidUtilities.runOnUIThread(() -> { String textFinal = getTrimmedString(text); if (textFinal.length() != 0) { @@ -8625,7 +8629,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } } if (document == null) { - thumb = createVideoThumbnailAtTime(videoPath, startTime); + if (videoEditedInfo != null && videoEditedInfo.notReadyYet) { + thumb = videoEditedInfo.thumb; + } + if (thumb == null) { + thumb = createVideoThumbnailAtTime(videoPath, startTime); + } if (thumb == null) { thumb = createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); } @@ -8669,14 +8678,19 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } attributeVideo.round_message = isRound; document.attributes.add(attributeVideo); - if (videoEditedInfo != null && videoEditedInfo.needConvert()) { + if (videoEditedInfo != null && videoEditedInfo.notReadyYet) { + attributeVideo.w = videoEditedInfo.resultWidth; + attributeVideo.h = videoEditedInfo.resultHeight; + attributeVideo.duration = videoEditedInfo.estimatedDuration / 1000.0; + document.size = videoEditedInfo.estimatedSize; + } else if (videoEditedInfo != null && videoEditedInfo.needConvert()) { if (videoEditedInfo.muted) { document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); fillVideoAttribute(videoPath, attributeVideo, videoEditedInfo); videoEditedInfo.originalWidth = attributeVideo.w; videoEditedInfo.originalHeight = attributeVideo.h; } else { - attributeVideo.duration = (int) (videoEditedInfo.estimatedDuration / 1000); + attributeVideo.duration = videoEditedInfo.estimatedDuration / 1000.0; } int w, h; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index 4b2bd2657..e07eae3b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -118,7 +118,7 @@ public class TopicsController extends BaseController { topicsIsLoading.put(chatId, 0); processTopics(chatId, topics.topics, messagesMap, false, loadType, ((TLRPC.TL_messages_forumTopics) response).count); - getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0, 0); sortTopics(chatId); getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); @@ -390,7 +390,7 @@ public class TopicsController extends BaseController { getMessagesController().putChats(((TLRPC.TL_messages_forumTopics) response).chats, false); processTopics(chatId, topics.topics, messagesMap, false, LOAD_TYPE_LOAD_UNKNOWN, -1); - getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0); + getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0, 0); getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); if (callback != null) { callback.run(); @@ -400,7 +400,7 @@ public class TopicsController extends BaseController { })); } - public void updateMaxReadId(long chatId, int topicId, int readMaxId, int unreadCount, int mentionsUnread) { + public void updateMaxReadId(long chatId, long topicId, int readMaxId, int unreadCount, int mentionsUnread) { TLRPC.TL_forumTopic topic = findTopic(chatId, topicId); if (topic != null) { topic.read_inbox_max_id = readMaxId; @@ -412,7 +412,7 @@ public class TopicsController extends BaseController { } } - public TLRPC.TL_forumTopic findTopic(long chatId, int topicId) { + public TLRPC.TL_forumTopic findTopic(long chatId, long topicId) { LongSparseArray topicsMap = topicsMapByChatId.get(chatId); if (topicsMap != null) { return topicsMap.get(topicId); @@ -717,7 +717,7 @@ public class TopicsController extends BaseController { ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); } - public void updateMentionsUnread(long dialogId, int topicId, int topicMentionsCount) { + public void updateMentionsUnread(long dialogId, long topicId, int topicMentionsCount) { AndroidUtilities.runOnUIThread(() -> { TLRPC.TL_forumTopic topic = findTopic(-dialogId, topicId); if (topic != null) { @@ -727,7 +727,7 @@ public class TopicsController extends BaseController { }); } - public int updateReactionsUnread(long dialogId, int topicId, int count, boolean increment) { + public int updateReactionsUnread(long dialogId, long topicId, int count, boolean increment) { TLRPC.TL_forumTopic topic = findTopic(-dialogId, topicId); int totalCount = -1; if (topic != null) { @@ -745,7 +745,7 @@ public class TopicsController extends BaseController { return totalCount; } - public void markAllReactionsAsRead(long chatId, int topicId) { + public void markAllReactionsAsRead(long chatId, long topicId) { TLRPC.TL_forumTopic topic = findTopic(chatId, topicId); if (topic != null && topic.unread_reactions_count > 0) { topic.unread_reactions_count = 0; @@ -811,7 +811,7 @@ public class TopicsController extends BaseController { topicsToReload.put(update.dialogId, arrayList); } TLRPC.TL_forumTopic forumTopic = new TLRPC.TL_forumTopic(); - forumTopic.id = update.topicId; + forumTopic.id = (int) update.topicId; arrayList.add(forumTopic); } else { TLRPC.TL_forumTopic topic = findTopic(-update.dialogId, update.topicId); @@ -1031,7 +1031,7 @@ public class TopicsController extends BaseController { public static class TopicUpdate { public int totalMessagesCount = -1; long dialogId; - int topicId; + long topicId; int unreadMentions; int unreadCount; int topMessageId; @@ -1057,13 +1057,13 @@ public class TopicsController extends BaseController { openedTopicsBuChatId.put(chatId, v); } - public void getTopicRepliesCount(long dialogId, int topicId) { + public void getTopicRepliesCount(long dialogId, long topicId) { TLRPC.TL_forumTopic topic = findTopic(-dialogId, topicId); if (topic != null) { if (topic.totalMessagesCount == 0) { TLRPC.TL_messages_getReplies req = new TLRPC.TL_messages_getReplies(); req.peer = getMessagesController().getInputPeer(dialogId); - req.msg_id = topicId; + req.msg_id = (int) topicId; req.limit = 1; getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index 6af2c53cb..7279b9326 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -18,6 +18,7 @@ import org.telegram.tgnet.TLRPC; public class UserObject { public static final long REPLY_BOT = 1271266957L; + public static final long ANONYMOUS = 2666000L; public static boolean isDeleted(TLRPC.User user) { return user == null || user instanceof TLRPC.TL_userDeleted_old2 || user instanceof TLRPC.TL_userEmpty || user.deleted; @@ -32,7 +33,11 @@ public class UserObject { } public static boolean isReplyUser(TLRPC.User user) { - return user != null && (user.id == 708513 || user.id == REPLY_BOT); + return user != null && (user.id == 708513L || user.id == REPLY_BOT); + } + + public static boolean isAnonymous(TLRPC.User user) { + return user != null && user.id == ANONYMOUS; } public static boolean isReplyUser(long did) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 68c1cd56e..402c69cc5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -12,6 +12,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Rect; import com.carrotsearch.randomizedtesting.Xoroshiro128PlusRandom; @@ -86,12 +87,21 @@ public class Utilities { public static native void setupNativeCrashesListener(String path); public static Bitmap stackBlurBitmapMax(Bitmap bitmap) { + return stackBlurBitmapMax(bitmap, false); + } + + public static Bitmap stackBlurBitmapMax(Bitmap bitmap, boolean round) { int w = AndroidUtilities.dp(20); int h = (int) (AndroidUtilities.dp(20) * (float) bitmap.getHeight() / bitmap.getWidth()); Bitmap scaledBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(scaledBitmap); canvas.save(); canvas.scale((float) scaledBitmap.getWidth() / bitmap.getWidth(), (float) scaledBitmap.getHeight() / bitmap.getHeight()); + if (round) { + Path path = new Path(); + path.addCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2f - 1, Path.Direction.CW); + canvas.clipPath(path); + } canvas.drawBitmap(bitmap, 0, 0, null); canvas.restore(); Utilities.stackBlurBitmap(scaledBitmap, Math.max(10, Math.max(w, h) / 150)); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index 5dc4868b3..170179815 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -62,6 +62,9 @@ public class VideoEditedInfo { public boolean isStory; public StoryEntry.HDRInfo hdrInfo; + public Bitmap thumb; + public boolean notReadyYet; + public Integer gradientTopColor, gradientBottomColor; public int account; public boolean isDark; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java index 115b0fc21..0c9f6bf85 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java @@ -31,8 +31,12 @@ public class VideoEncodingService extends Service implements NotificationCenter. public static void start(boolean cancelled) { if (instance == null) { - Intent intent = new Intent(ApplicationLoader.applicationContext, VideoEncodingService.class); - ApplicationLoader.applicationContext.startService(intent); + try { + Intent intent = new Intent(ApplicationLoader.applicationContext, VideoEncodingService.class); + ApplicationLoader.applicationContext.startService(intent); + } catch (Exception e) { + FileLog.e(e); + } } else if (cancelled) { MediaController.VideoConvertMessage messageInController = MediaController.getInstance().getCurrentForegroundConverMessage(); if (instance.currentMessage != messageInController) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java index 05eeb38f5..be4380a0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java @@ -33,7 +33,7 @@ public class WearReplyReceiver extends BroadcastReceiver { } long dialogId = intent.getLongExtra("dialog_id", 0); int maxId = intent.getIntExtra("max_id", 0); - int topicId = intent.getIntExtra("topic_id", 0); + long topicId = intent.getLongExtra("topic_id", 0); int currentAccount = intent.getIntExtra("currentAccount", 0); if (dialogId == 0 || maxId == 0 || !UserConfig.isValidAccount(currentAccount)) { return; @@ -67,19 +67,27 @@ public class WearReplyReceiver extends BroadcastReceiver { sendMessage(accountInstance, text, dialogId, topicId, maxId); } - private void sendMessage(AccountInstance accountInstance, CharSequence text, long dialog_id, int topicId, int max_id) { + private void sendMessage(AccountInstance accountInstance, CharSequence text, long dialog_id, long topicId, int max_id) { MessageObject replyToMsgId = null; + MessageObject replyToTopMsgId = null; + if (max_id != 0) { + TLRPC.TL_message replyMessage = new TLRPC.TL_message(); + replyMessage.message = ""; + replyMessage.id = max_id; + replyMessage.peer_id = accountInstance.getMessagesController().getPeer(dialog_id); + replyToMsgId = new MessageObject(accountInstance.getCurrentAccount(), replyMessage, false, false); + } if (topicId != 0) { TLRPC.TL_message topicStartMessage = new TLRPC.TL_message(); topicStartMessage.message = ""; - topicStartMessage.id = topicId; + topicStartMessage.id = (int) topicId; topicStartMessage.peer_id = accountInstance.getMessagesController().getPeer(dialog_id); topicStartMessage.action = new TLRPC.TL_messageActionTopicCreate(); topicStartMessage.action.title = ""; - replyToMsgId = new MessageObject(accountInstance.getCurrentAccount(), topicStartMessage, false, false); + replyToTopMsgId = new MessageObject(accountInstance.getCurrentAccount(), topicStartMessage, false, false); } - accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(text.toString(), dialog_id, replyToMsgId, null, null, true, null, null, null, true, 0, null, false)); + accountInstance.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(text.toString(), dialog_id, replyToMsgId, replyToTopMsgId, null, true, null, null, null, true, 0, null, false)); //TODO handle topics if (topicId == 0) { accountInstance.getMessagesController().markDialogAsRead(dialog_id, max_id, max_id, 0, false, topicId, 0, true, 0); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index 4c91e7555..d9ce3ed6b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -449,6 +449,16 @@ public class Browser { return false; } + public static boolean isTMe(String url) { + try { + final String linkPrefix = MessagesController.getInstance(UserConfig.selectedAccount).linkPrefix; + return TextUtils.equals(AndroidUtilities.getHostAuthority(url), linkPrefix); + } catch (Exception e) { + FileLog.e(e); + } + return false; + } + public static boolean isInternalUri(Uri uri, boolean[] forceBrowser) { return isInternalUri(uri, false, forceBrowser); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java index 32a327a52..ca6217bc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java @@ -10,6 +10,7 @@ package org.telegram.messenger.video; import android.media.MediaCodec; import android.media.MediaFormat; +import android.util.Log; import com.coremedia.iso.BoxParser; import com.coremedia.iso.IsoFile; @@ -38,11 +39,18 @@ import com.coremedia.iso.boxes.TrackHeaderBox; import com.googlecode.mp4parser.DataSource; import com.googlecode.mp4parser.util.Matrix; +import org.telegram.messenger.AndroidUtilities; + +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -207,6 +215,47 @@ public class MP4Builder { fos.close(); } + public void finishMovie(File into) throws Exception { + if (into == null) { + finishMovie(); + return; + } + + fos.flush(); + final long wasPosition = fc.position(); + if (allowSyncFiles) { + fos.getFD().sync(); + } + + AndroidUtilities.copyFile(currentMp4Movie.getCacheFile(), into); + + try (RandomAccessFile raf = new RandomAccessFile(into, "rw"); + FileChannel copiedFc = raf.getChannel()) { + + // put mdat box + copiedFc.position(wasPosition); + if (mdat.getContentSize() != 0) { + copiedFc.position(mdat.getOffset()); + mdat.getBox(copiedFc); + copiedFc.position(wasPosition); + } + + // put moov box + track2SampleSizes.clear(); + for (Track track : currentMp4Movie.getTracks()) { + List samples = track.getSamples(); + long[] sizes = new long[samples.size()]; + for (int i = 0; i < sizes.length; i++) { + sizes[i] = samples.get(i).getSize(); + } + track2SampleSizes.put(track, sizes); + } + Box moov = createMovieBox(currentMp4Movie); + moov.getBox(copiedFc); + } + } + + protected FileTypeBox createFileTypeBox(boolean hevc) { LinkedList minorBrands = new LinkedList<>(); minorBrands.add("isom"); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java index 6979f6ddb..cf4098543 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java @@ -11,6 +11,7 @@ package org.telegram.messenger.video; import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaFormat; +import android.util.Log; import com.coremedia.iso.boxes.AbstractMediaHeaderBox; import com.coremedia.iso.boxes.SampleDescriptionBox; @@ -330,6 +331,8 @@ public class Track { } public void prepare() { + duration = 0; + ArrayList original = new ArrayList<>(samplePresentationTimes); Collections.sort(samplePresentationTimes, (o1, o2) -> { if (o1.presentationTime > o2.presentationTime) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java index ebbf0456b..7d7f941dc 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -3029,7 +3029,8 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } else { ringtonePlayer.setAudioStreamType(AudioManager.STREAM_RING); if (!USE_CONNECTION_SERVICE) { - am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN); + int focusResult = am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + hasAudioFocus = focusResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; } } try { @@ -3156,8 +3157,8 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } } cpuWakelock.release(); + AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); if (!playingSound) { - AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); VoipAudioManager vam = VoipAudioManager.get(); if (!USE_CONNECTION_SERVICE) { if (isBtHeadsetConnected || bluetoothScoActive || bluetoothScoConnecting) { @@ -3194,15 +3195,16 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa if (audioDeviceCallback != null) { am.unregisterAudioDeviceCallback(audioDeviceCallback); } - if (hasAudioFocus) { - am.abandonAudioFocus(this); - } + Utilities.globalQueue.postRunnable(() -> { if (soundPool != null) { soundPool.release(); } }); } + if (hasAudioFocus) { + am.abandonAudioFocus(this); + } if (USE_CONNECTION_SERVICE) { if (!didDeleteConnectionServiceContact) { @@ -3574,7 +3576,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } try { AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER) != null) { + if (am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER) != null) { int outFramesPerBuffer = Integer.parseInt(am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)); Instance.setBufferSize(outFramesPerBuffer); } else { @@ -3763,7 +3765,8 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa FileLog.e(e); } AndroidUtilities.runOnUIThread(() -> { - am.requestAudioFocus(VoIPService.this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN); + int focusResult = am.requestAudioFocus(VoIPService.this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + hasAudioFocus = focusResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; final VoipAudioManager vam = VoipAudioManager.get(); if (isBluetoothHeadsetConnected() && hasEarpiece()) { switch (audioRouteToSet) { diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index b6fdda8a0..272156eaf 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -76,7 +76,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 = 170; + public static final int LAYER = 172; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -10217,6 +10217,8 @@ public class TLRPC { public boolean archive_and_mute_new_noncontact_peers; public boolean keep_archived_unmuted; public boolean keep_archived_folders; + public boolean hide_read_marks; + public boolean new_noncontact_peers_require_premium; public static TL_globalPrivacySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_globalPrivacySettings.constructor != constructor) { @@ -10236,6 +10238,8 @@ public class TLRPC { archive_and_mute_new_noncontact_peers = (flags & 1) != 0; keep_archived_unmuted = (flags & 2) != 0; keep_archived_folders = (flags & 4) != 0; + hide_read_marks = (flags & 8) != 0; + new_noncontact_peers_require_premium = (flags & 16) != 0; } public void serializeToStream(AbstractSerializedData stream) { @@ -10243,6 +10247,8 @@ public class TLRPC { flags = archive_and_mute_new_noncontact_peers ? (flags | 1) : (flags &~ 1); flags = keep_archived_unmuted ? (flags | 2) : (flags &~ 2); flags = keep_archived_folders ? (flags | 4) : (flags &~ 4); + flags = hide_read_marks ? (flags | 8) : (flags &~ 8); + flags = new_noncontact_peers_require_premium ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); } } @@ -24088,6 +24094,7 @@ public class TLRPC { public boolean close_friend; public boolean stories_unavailable; public boolean stories_hidden; + public boolean contact_require_premium; public int bot_info_version; public String bot_inline_placeholder; public String lang_code; @@ -24282,6 +24289,7 @@ public class TLRPC { close_friend = (flags2 & 4) != 0; stories_hidden = (flags2 & 8) != 0; stories_unavailable = (flags2 & 16) != 0; + contact_require_premium = (flags2 & 1024) != 0; id = stream.readInt64(exception); if ((flags & 1) != 0) { access_hash = stream.readInt64(exception); @@ -24393,6 +24401,7 @@ public class TLRPC { flags2 = close_friend ? (flags2 | 4) : (flags2 &~ 4); flags2 = stories_hidden ? (flags2 | 8) : (flags2 &~ 8); flags2 = stories_unavailable ? (flags2 | 16) : (flags2 &~ 16); + flags2 = contact_require_premium ? (flags2 | 1024) : (flags2 &~ 1024); stream.writeInt32(flags2); stream.writeInt64(id); if ((flags & 1) != 0) { @@ -28754,6 +28763,7 @@ public class TLRPC { public int flags; public boolean min; public boolean can_see_list; + public boolean reactions_as_tags; public ArrayList results = new ArrayList<>(); public ArrayList recent_reactions = new ArrayList<>(); @@ -28787,6 +28797,7 @@ public class TLRPC { flags = stream.readInt32(exception); min = (flags & 1) != 0; can_see_list = (flags & 4) != 0; + reactions_as_tags = (flags & 8) != 0; int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -28825,6 +28836,7 @@ public class TLRPC { stream.writeInt32(constructor); flags = min ? (flags | 1) : (flags &~ 1); flags = can_see_list ? (flags | 4) : (flags &~ 4); + flags = reactions_as_tags ? (flags | 8) : (flags &~ 8); stream.writeInt32(flags); stream.writeInt32(0x1cb5c415); int count = results.size(); @@ -28843,6 +28855,144 @@ public class TLRPC { } } + public static class TL_savedReactionTag extends TLObject { + public static final int constructor = 0xcb6ff828; + + public int flags; + public Reaction reaction; + public String title; + public int count; + + public static TL_savedReactionTag TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_savedReactionTag.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_savedReactionTag", constructor)); + } else { + return null; + } + } + TL_savedReactionTag result = new TL_savedReactionTag(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + title = stream.readString(exception); + } + count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + reaction.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeString(title); + } + stream.writeInt32(count); + } + } + + public static class messages_SavedReactionTags extends TLObject { + public ArrayList tags = new ArrayList<>(); + public long hash; + + public static messages_SavedReactionTags TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_SavedReactionTags result = null; + switch (constructor) { + case TL_messages_savedReactionsTagsNotModified.constructor: + result = new TL_messages_savedReactionsTagsNotModified(); + break; + case TL_messages_savedReactionsTags.constructor: + result = new TL_messages_savedReactionsTags(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_SavedReactionTags", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_savedReactionsTagsNotModified extends messages_SavedReactionTags { + public static final int constructor = 0x889b59ef; + + public void readParams(AbstractSerializedData stream, boolean exception) { + + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_savedReactionsTags extends messages_SavedReactionTags { + public static final int constructor = 0x3259950a; + + 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 a = 0; a < count; a++) { + TL_savedReactionTag object = TL_savedReactionTag.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + tags.add(object); + } + hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = tags.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + tags.get(a).serializeToStream(stream); + } + stream.writeInt64(hash); + } + } + + public static class TL_outboxReadDate extends TLObject { + public static final int constructor = 0x3bb842ac; + + public int date; + + public static TL_outboxReadDate TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_outboxReadDate.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_outboxReadDate", constructor)); + } else { + return null; + } + } + TL_outboxReadDate result = new TL_outboxReadDate(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(date); + } + } + public static class TL_messageReactionsOld extends TL_messageReactions { public static final int constructor = 0x87b6e36; @@ -33558,7 +33708,9 @@ public class TLRPC { } public static abstract class UserStatus extends TLObject { + public int flags; public int expires; + public boolean by_me; public static UserStatus TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserStatus result = null; @@ -33566,21 +33718,33 @@ public class TLRPC { case 0x8c703f: result = new TL_userStatusOffline(); break; - case 0x7bf09fc: + case TL_userStatusLastWeek.constructor: result = new TL_userStatusLastWeek(); break; + case TL_userStatusLastWeek_layer171.constructor: + result = new TL_userStatusLastWeek_layer171(); + break; case 0x9d05049: result = new TL_userStatusEmpty(); break; - case 0x77ebc742: + case TL_userStatusLastMonth.constructor: result = new TL_userStatusLastMonth(); break; + case TL_userStatusLastMonth_layer171.constructor: + result = new TL_userStatusLastMonth_layer171(); + break; case 0xedb93949: result = new TL_userStatusOnline(); break; - case 0xe26f42f1: + case TL_userStatusRecently.constructor: result = new TL_userStatusRecently(); break; + case TL_userStatusRecently_layer171.constructor: + result = new TL_userStatusRecently_layer171(); + break; + case TL_userStatusHidden.constructor: + result = new TL_userStatusHidden(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in UserStatus", constructor)); @@ -33592,6 +33756,19 @@ public class TLRPC { } } + public static class TL_userStatusHidden extends UserStatus { + public static final int constructor = 0xcf7d64b1; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_userStatusOffline extends UserStatus { public static final int constructor = 0x8c703f; @@ -33607,8 +33784,29 @@ public class TLRPC { } public static class TL_userStatusLastWeek extends UserStatus { + public static final int constructor = 0x541a1d1a; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + by_me = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream.writeInt32(flags); + } + } + + + public static class TL_userStatusLastWeek_layer171 extends TL_userStatusLastWeek { public static final int constructor = 0x7bf09fc; + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + + } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); @@ -33625,8 +33823,28 @@ public class TLRPC { } public static class TL_userStatusLastMonth extends UserStatus { + public static final int constructor = 0x65899777; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + by_me = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream.writeInt32(flags); + } + } + + public static class TL_userStatusLastMonth_layer171 extends TL_userStatusLastMonth { public static final int constructor = 0x77ebc742; + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + + } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); @@ -33648,8 +33866,28 @@ public class TLRPC { } public static class TL_userStatusRecently extends UserStatus { + public static final int constructor = 0x7b197dc8; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + by_me = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = by_me ? flags | 1 : flags &~ 1; + stream.writeInt32(flags); + } + } + + public static class TL_userStatusRecently_layer171 extends TL_userStatusRecently { public static final int constructor = 0xe26f42f1; + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + + } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); @@ -34180,6 +34418,9 @@ public class TLRPC { case TL_updateRecentReactions.constructor: result = new TL_updateRecentReactions(); break; + case TL_updateSavedReactionTags.constructor: + result = new TL_updateSavedReactionTags(); + break; case TL_updateWebPage.constructor: result = new TL_updateWebPage(); break; @@ -35306,6 +35547,14 @@ public class TLRPC { } } + public static class TL_updateSavedReactionTags extends Update { + public static final int constructor = 0x39c67432; + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_updateWebPage extends Update { public static final int constructor = 0x7f891213; @@ -51431,6 +51680,8 @@ public class TLRPC { public boolean stories_pinned_available; public boolean blocked_my_stories_from; public boolean wallpaper_overridden; + public boolean contact_require_premium; + public boolean read_dates_private; public User user; public String about; public TL_contacts_link_layer101 link; @@ -51456,7 +51707,7 @@ public class TLRPC { public static UserFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { UserFull result = null; switch (constructor) { - case 0xb9b12c6c: + case TL_userFull.constructor: result = new TL_userFull(); break; case 0x4fe1cc86: @@ -51522,6 +51773,8 @@ public class TLRPC { stories_pinned_available = (flags & 67108864) != 0; blocked_my_stories_from = (flags & 134217728) != 0; wallpaper_overridden = (flags & 268435456) != 0; + contact_require_premium = (flags & 536870912) != 0; + read_dates_private = (flags & 1073741824) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -51600,6 +51853,8 @@ public class TLRPC { flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); flags = wallpaper_overridden ? (flags | 268435456) : (flags &~ 268435456); + flags = contact_require_premium ? (flags | 536870912) : (flags &~ 536870912); + flags = read_dates_private ? (flags | 1073741824) : (flags &~ 1073741824); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -56182,6 +56437,35 @@ public class TLRPC { id.serializeToStream(stream); } } + + public static class TL_users_getIsPremiumRequiredToContact extends TLObject { + public static final int constructor = 0xa622aa10; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + Bool object = Bool.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + id.get(i).serializeToStream(stream); + } + } + } public static class TL_contacts_getStatuses extends TLObject { public static final int constructor = 0xc4a353ee; @@ -56587,13 +56871,14 @@ public class TLRPC { } public static class TL_messages_search extends TLObject { - public static final int constructor = 0xa7b4e929; + public static final int constructor = 0x29ee847a; public int flags; public InputPeer peer; public String q; public InputPeer from_id; public InputPeer saved_peer_id; + public ArrayList saved_reaction = new ArrayList<>(); public int top_msg_id; public MessagesFilter filter; public int min_date; @@ -56620,6 +56905,14 @@ public class TLRPC { if ((flags & 4) != 0) { saved_peer_id.serializeToStream(stream); } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = saved_reaction.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + saved_reaction.get(a).serializeToStream(stream); + } + } if ((flags & 2) != 0) { stream.writeInt32(top_msg_id); } @@ -71481,6 +71774,23 @@ public class TLRPC { } } + public static class TL_messages_getDefaultTagReactions extends TLObject { + public static final int constructor = 0xbdf93428; + + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Reactions.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + public static abstract class ForumTopic extends TLObject { public static ForumTopic TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -74750,6 +75060,66 @@ public class TLRPC { } } + public static class TL_messages_getSavedReactionTags extends TLObject { + public static final int constructor = 0x761ddacf; + + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SavedReactionTags.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_messages_updateSavedReactionTag extends TLObject { + public static final int constructor = 0x60297dec; + + public int flags; + public Reaction reaction; + public String title; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + reaction.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeString(title); + } + } + } + + public static class TL_messages_getOutboxReadDate extends TLObject { + public static final int constructor = 0x8c4bfe5d; + + public InputPeer peer; + public int msg_id; + + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_outboxReadDate.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + } + } + public static class Vector extends TLObject { public static final int constructor = 0x1cb5c415; public ArrayList objects = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index bc5b09713..0bddabec4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -1003,6 +1003,10 @@ public class ActionBar extends FrameLayout { } } + public int getBackgroundColor() { + return actionBarColor; + } + public boolean isActionModeShowed() { return actionMode != null && actionModeVisible; } @@ -1159,6 +1163,12 @@ public class ActionBar extends FrameLayout { } } + public void clearSearchFilters() { + if (menu != null) { + menu.clearSearchFilters(); + } + } + public void setSearchFieldText(String text) { menu.setSearchFieldText(text); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 9256e0337..ddeb8f934 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -566,7 +566,17 @@ public class ActionBarMenu extends LinearLayout { } public void clearSearchFilters() { - + int count = getChildCount(); + for (int a = 0; a < count; a++) { + View view = getChildAt(a); + if (view instanceof ActionBarMenuItem) { + ActionBarMenuItem item = (ActionBarMenuItem) view; + if (item.isSearchField()) { + item.clearSearchFilters(); + break; + } + } + } } private Runnable onLayoutListener; 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 8ea9ed562..855e4a0a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -8,6 +8,8 @@ package org.telegram.ui.ActionBar; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -65,6 +67,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Adapters.FiltersView; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CloseProgressDrawable2; import org.telegram.ui.Components.CombinedDrawable; @@ -73,6 +76,7 @@ import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import java.util.ArrayList; import java.util.HashMap; @@ -1052,7 +1056,7 @@ public class ActionBarMenuItem extends FrameLayout { } for (int i = 0; i < searchFilterLayout.getChildCount(); i++) { - boolean removed = localFilters.remove(((SearchFilterView)searchFilterLayout.getChildAt(i)).getFilter()); + boolean removed = localFilters.remove(((SearchFilterView) searchFilterLayout.getChildAt(i)).getFilter()); if (!removed) { searchFilterLayout.removeViewAt(i); i--; @@ -1060,8 +1064,14 @@ public class ActionBarMenuItem extends FrameLayout { } for (int i = 0; i < localFilters.size(); i++) { - SearchFilterView searchFilterView = new SearchFilterView(getContext(), resourcesProvider); - searchFilterView.setData(localFilters.get(i)); + FiltersView.MediaFilterData filter = localFilters.get(i); + SearchFilterView searchFilterView; + if (filter.reaction != null) { + searchFilterView = new ReactionFilterView(getContext(), resourcesProvider); + } else { + searchFilterView = new SearchFilterView(getContext(), resourcesProvider); + } + searchFilterView.setData(filter); searchFilterView.setOnClickListener(view -> { int index = currentSearchFilters.indexOf(searchFilterView.getFilter()); if (selectedFilterIndex != index) { @@ -2014,6 +2024,78 @@ public class ActionBarMenuItem extends FrameLayout { return Theme.getColor(key, resourcesProvider); } + private static class ReactionFilterView extends SearchFilterView { + + private ReactionsLayoutInBubble.ReactionButton reactionButton; + + public ReactionFilterView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + removeAllViews(); + setBackground(null); + + setWillNotDraw(false); + } + + public void setData(FiltersView.MediaFilterData data) { + TLRPC.TL_reactionCount reactionCount = new TLRPC.TL_reactionCount(); + reactionCount.count = 1; + reactionCount.reaction = data.reaction.toTLReaction(); + + reactionButton = new ReactionsLayoutInBubble.ReactionButton(null, UserConfig.selectedAccount, this, reactionCount, false, resourcesProvider) { + @Override + protected void updateColors(float progress) { + lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, Theme.getColor(Theme.key_chat_inReactionButtonBackground, resourcesProvider), progress); + } + + @Override + protected int getCacheType() { + return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_EMOJI_STATUS; + } + }; + reactionButton.width = dp(44.33f); + reactionButton.height = dp(28); + reactionButton.choosen = true; + if (attached) { + reactionButton.attach(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(dp(45 + 4), dp(32)); + } + + @Override + protected void onDraw(Canvas canvas) { + if (reactionButton != null) { + reactionButton.draw(canvas, (getWidth() - dp(4) - reactionButton.width) / 2f, (getHeight() - reactionButton.height) / 2f, 1f, 1f, false); + } + } + + private boolean attached; + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (!attached) { + if (reactionButton != null) { + reactionButton.attach(); + } + attached = true; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (attached) { + if (reactionButton != null) { + reactionButton.detach(); + } + attached = false; + } + } + } + private static class SearchFilterView extends FrameLayout { Drawable thumbDrawable; @@ -2036,7 +2118,7 @@ public class ActionBarMenuItem extends FrameLayout { } }; - private final Theme.ResourcesProvider resourcesProvider; + protected final Theme.ResourcesProvider resourcesProvider; public SearchFilterView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index 5f727c5ef..99b549bbc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -12,6 +12,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; @@ -19,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.CornerPathEffect; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -53,6 +55,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; @@ -198,7 +202,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati } protected boolean supportsNativeBlur() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && LaunchActivity.systemBlurEnabled; + return false; // Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && LaunchActivity.systemBlurEnabled; } public void redPositive() { 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 8dd2cd34b..8888ee3b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -67,7 +67,7 @@ public abstract class BaseFragment { protected Dialog visibleDialog; protected int currentAccount = UserConfig.selectedAccount; - protected View fragmentView; + public View fragmentView; protected INavigationLayout parentLayout; protected ActionBar actionBar; protected boolean inPreviewMode; 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 c796ea69e..4ad9103c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -97,6 +97,7 @@ public class SimpleTextView extends View implements Drawable.Callback { private boolean wasLayout; private boolean rightDrawableOutside; + private boolean rightDrawableInside; private boolean ellipsizeByGradient, ellipsizeByGradientLeft; private Boolean forceEllipsizeByGradientLeft; private int ellipsizeByGradientWidthDp = 16; @@ -317,7 +318,16 @@ public class SimpleTextView extends View implements Drawable.Callback { offsetX = -AndroidUtilities.dp(8); } offsetX += getPaddingLeft(); - textDoesNotFit = textWidth > (width - paddingRight); + int rightDrawableWidth = 0; + if (rightDrawableInside) { + if (rightDrawable != null && !rightDrawableOutside) { + rightDrawableWidth += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); + } + if (rightDrawable2 != null && !rightDrawableOutside) { + rightDrawableWidth += (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + } + } + textDoesNotFit = textWidth + rightDrawableWidth > (width - paddingRight); if (fullLayout != null && fullLayoutAdditionalWidth > 0) { fullLayoutLeftCharactersOffset = fullLayout.getPrimaryHorizontal(0) - firstLineLayout.getPrimaryHorizontal(0); @@ -342,15 +352,17 @@ public class SimpleTextView extends View implements Drawable.Callback { width -= drawablePadding; } int rightDrawableWidth = 0; - if (rightDrawable != null && !rightDrawableOutside) { - rightDrawableWidth = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); - width -= rightDrawableWidth; - width -= drawablePadding; - } - if (rightDrawable2 != null && !rightDrawableOutside) { - rightDrawableWidth = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); - width -= rightDrawableWidth; - width -= drawablePadding; + if (!rightDrawableInside) { + if (rightDrawable != null && !rightDrawableOutside) { + rightDrawableWidth += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); + width -= rightDrawableWidth; + width -= drawablePadding; + } + if (rightDrawable2 != null && !rightDrawableOutside) { + rightDrawableWidth += (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + width -= rightDrawableWidth; + width -= drawablePadding; + } } if (replacedText != null && replacedDrawable != null) { replacingDrawableTextIndex = text.toString().indexOf(replacedText); @@ -487,7 +499,7 @@ public class SimpleTextView extends View implements Drawable.Callback { } public int getTextWidth() { - return textWidth; + return textWidth + (rightDrawableInside ? (rightDrawable != null ? (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale) : 0) + (rightDrawable2 != null ? (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale) : 0) : 0); } public int getRightDrawableWidth() { @@ -742,15 +754,17 @@ public class SimpleTextView extends View implements Drawable.Callback { width -= drawablePadding; } int rightDrawableWidth = 0; - if (rightDrawable != null && !rightDrawableOutside) { - rightDrawableWidth = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); - width -= rightDrawableWidth; - width -= drawablePadding; - } - if (rightDrawable2 != null && !rightDrawableOutside) { - rightDrawableWidth = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); - width -= rightDrawableWidth; - width -= drawablePadding; + if (!rightDrawableInside) { + if (rightDrawable != null && !rightDrawableOutside) { + rightDrawableWidth = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); + width -= rightDrawableWidth; + width -= drawablePadding; + } + if (rightDrawable2 != null && !rightDrawableOutside) { + rightDrawableWidth = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + width -= rightDrawableWidth; + width -= drawablePadding; + } } if (replacedText != null && replacedDrawable != null) { if ((replacingDrawableTextIndex = text.toString().indexOf(replacedText)) < 0) { @@ -823,7 +837,7 @@ public class SimpleTextView extends View implements Drawable.Callback { } } - if (rightDrawable != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside) { + if (rightDrawable != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside && !rightDrawableInside) { int x = textOffsetX + textWidth + drawablePadding + (int) -scrollingOffset; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.CENTER_HORIZONTAL || (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.RIGHT) { @@ -843,7 +857,7 @@ public class SimpleTextView extends View implements Drawable.Callback { rightDrawable.draw(canvas); totalWidth += drawablePadding + dw; } - if (rightDrawable2 != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside) { + if (rightDrawable2 != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside && !rightDrawableInside) { int x = textOffsetX + textWidth + drawablePadding + (int) -scrollingOffset; if (rightDrawable != null) { x += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale) + drawablePadding; @@ -963,6 +977,47 @@ public class SimpleTextView extends View implements Drawable.Callback { if (offsetX + textOffsetX != 0 || offsetY != 0 || scrollingOffset != 0) { canvas.restore(); } + if (rightDrawable != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside && rightDrawableInside) { + int x = textOffsetX + textWidth + drawablePadding + (int) -scrollingOffset; + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.CENTER_HORIZONTAL || + (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.RIGHT) { + x += offsetX; + } + int dw = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); + int dh = (int) (rightDrawable.getIntrinsicHeight() * rightDrawableScale); + int y; + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.CENTER_VERTICAL) { + y = (getMeasuredHeight() - dh) / 2 + rightDrawableTopPadding; + } else { + y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding; + } + rightDrawable.setBounds(x, y, x + dw, y + dh); + rightDrawableX = x + (dw >> 1); + rightDrawableY = y + (dh >> 1); + rightDrawable.draw(canvas); + totalWidth += drawablePadding + dw; + } + if (rightDrawable2 != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside && rightDrawableInside) { + int x = textOffsetX + textWidth + drawablePadding + (int) -scrollingOffset; + if (rightDrawable != null) { + x += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale) + drawablePadding; + } + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.CENTER_HORIZONTAL || + (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.RIGHT) { + x += offsetX; + } + int dw = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + int dh = (int) (rightDrawable2.getIntrinsicHeight() * rightDrawableScale); + int y; + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.CENTER_VERTICAL) { + y = (getMeasuredHeight() - dh) / 2 + rightDrawableTopPadding; + } else { + y = getPaddingTop() + (textHeight - dh) / 2 + rightDrawableTopPadding; + } + rightDrawable2.setBounds(x, y, x + dw, y + dh); + rightDrawable2.draw(canvas); + totalWidth += drawablePadding + dw; + } if (fade) { if (scrollingOffset < AndroidUtilities.dp(10)) { fadePaint.setAlpha((int) (255 * (scrollingOffset / AndroidUtilities.dp(10)))); @@ -1170,6 +1225,12 @@ public class SimpleTextView extends View implements Drawable.Callback { rightDrawableOutside = outside; } + // right drawable is ellipsized with text + public void setRightDrawableInside(boolean inside) { + rightDrawableInside = inside; + } + + public boolean getRightDrawableOutside() { return rightDrawableOutside; } @@ -1187,14 +1248,23 @@ public class SimpleTextView extends View implements Drawable.Callback { touchDownX = event.getX(); touchDownY = event.getY(); getParent().requestDisallowInterceptTouchEvent(true); + if (rightDrawable instanceof PressableDrawable) { + ((PressableDrawable) rightDrawable).setPressed(true); + } } else if (event.getAction() == MotionEvent.ACTION_MOVE && maybeClick) { if (Math.abs(event.getX() - touchDownX) >= AndroidUtilities.touchSlop || Math.abs(event.getY() - touchDownY) >= AndroidUtilities.touchSlop) { maybeClick = false; getParent().requestDisallowInterceptTouchEvent(false); + if (rightDrawable instanceof PressableDrawable) { + ((PressableDrawable) rightDrawable).setPressed(false); + } } } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (maybeClick && event.getAction() == MotionEvent.ACTION_UP) { rightDrawableOnClickListener.onClick(this); + if (rightDrawable instanceof PressableDrawable) { + ((PressableDrawable) rightDrawable).setPressed(false); + } } maybeClick = false; getParent().requestDisallowInterceptTouchEvent(false); @@ -1202,4 +1272,9 @@ public class SimpleTextView extends View implements Drawable.Callback { } return super.onTouchEvent(event) || maybeClick; } + + public static interface PressableDrawable { + public void setPressed(boolean value); + public boolean isPressed(); + } } 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 7c88f7c8b..d5c5d570d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -863,6 +863,7 @@ public class Theme { rad = heightHalf; } if (isOut) { + // LEFT-BOTTOM <- RIGHT-BOTTOM if (drawFullBubble || currentType == TYPE_PREVIEW || customPaint || drawFullBottom) { int radToUse = botButtonsBottom ? nearRad : rad; if (currentType == TYPE_MEDIA) { @@ -878,10 +879,12 @@ public class Theme { path.lineTo(bounds.left + padding, top - topY + currentBackgroundHeight); } if (drawFullBubble || currentType == TYPE_PREVIEW || customPaint || drawFullTop) { + // LEFT-BOTTOM -> LEFT-TOP path.lineTo(bounds.left + padding, bounds.top + padding + rad); rect.set(bounds.left + padding, bounds.top + padding, bounds.left + padding + rad * 2, bounds.top + padding + rad * 2); path.arcTo(rect, 180, 90, false); + // LEFT-TOP -> RIGHT-TOP int radToUse = isTopNear ? nearRad : rad; if (currentType == TYPE_MEDIA) { path.lineTo(bounds.right - padding - radToUse, bounds.top + padding); @@ -892,13 +895,17 @@ public class Theme { } path.arcTo(rect, 270, 90, false); } else { + // LEFT-BOTTOM -> LEFT-TOP path.lineTo(bounds.left + padding, top - topY - dp(2)); + + // LEFT-TOP -> RIGHT-TOP if (currentType == TYPE_MEDIA) { path.lineTo(bounds.right - padding, top - topY - dp(2)); } else { path.lineTo(bounds.right - dp(8), top - topY - dp(2)); } } + // RIGHT-TOP -> RIGHT-BOTTOM if (currentType == TYPE_MEDIA) { if (customPaint || drawFullBottom) { int radToUse = isBottomNear ? nearRad : rad; @@ -3098,7 +3105,7 @@ public class Theme { public static Paint avatar_backgroundPaint; public static Drawable listSelector; - public static Drawable[] avatarDrawables = new Drawable[18]; + public static Drawable[] avatarDrawables = new Drawable[20]; public static Drawable moveUpDrawable; @@ -3635,6 +3642,9 @@ public class Theme { public static final int key_chat_inBubbleSelectedOverlay = colorsCount++; public static final int key_chat_inBubbleShadow = colorsCount++; + public static final int key_actionBarActionModeReaction = colorsCount++; + public static final int key_actionBarActionModeReactionDot = colorsCount++; + //my messages bubbles public static final int myMessagesBubblesStartIndex = colorsCount; public static final int key_chat_outBubble = colorsCount++; @@ -4384,6 +4394,8 @@ public class Theme { fallbackKeys.put(key_statisticChartLine_indigo, key_color_purple); fallbackKeys.put(key_statisticChartLine_cyan, key_color_cyan); + fallbackKeys.put(key_actionBarActionModeReaction, key_windowBackgroundGray); + for (int i = 0; i < keys_avatar_background.length; i++) { themeAccentExclusionKeys.add(keys_avatar_background[i]); } @@ -8134,6 +8146,8 @@ public class Theme { 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); + avatarDrawables[18] = resources.getDrawable(R.drawable.large_hidden); + avatarDrawables[19] = resources.getDrawable(R.drawable.large_notes); if (dialogs_archiveAvatarDrawable != null) { dialogs_archiveAvatarDrawable.setCallback(null); @@ -8683,7 +8697,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); + chat_goIconDrawable = resources.getDrawable(R.drawable.filled_open_message); int rad = AndroidUtilities.dp(2); RectF rect = new RectF(); @@ -9867,7 +9881,7 @@ public class Theme { MotionBackgroundDrawable motionBackgroundDrawable = new MotionBackgroundDrawable(backgroundColor, gradientToColor1, gradientToColor2, gradientToColor3, false); Bitmap patternBitmap = null; - if (wallpaperFile != null && !isCustomTheme()) { + if (wallpaperFile != null) { if (wallpaperDocument != null) { File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(wallpaperDocument, true); patternBitmap = SvgHelper.getBitmap(f, AndroidUtilities.dp(360), AndroidUtilities.dp(640), false); 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 d3a508cc5..2aa4323e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -188,6 +188,8 @@ public class ThemeColors { defaultColors[key_actionBarDefaultSubmenuBackground] = 0xffffffff; defaultColors[key_actionBarDefaultSubmenuSeparator] = 0xfff5f5f5; defaultColors[key_actionBarActionModeDefaultSelector] = 0xffe2e2e2; + defaultColors[key_actionBarActionModeReaction] = 0xfff0f0f0; + defaultColors[key_actionBarActionModeReactionDot] = 0xffc0c0c0; defaultColors[key_actionBarTabActiveText] = 0xffffffff; defaultColors[key_actionBarTabUnactiveText] = 0xffd5e8f7; defaultColors[key_actionBarTabLine] = 0xffffffff; @@ -954,6 +956,8 @@ public class ThemeColors { colorKeysMap.put(key_actionBarActionModeDefaultTop, "actionBarActionModeDefaultTop"); colorKeysMap.put(key_actionBarActionModeDefaultIcon, "actionBarActionModeDefaultIcon"); colorKeysMap.put(key_actionBarActionModeDefaultSelector, "actionBarActionModeDefaultSelector"); + colorKeysMap.put(key_actionBarActionModeReaction, "actionBarActionModeReaction"); + colorKeysMap.put(key_actionBarActionModeReactionDot, "actionBarActionModeReactionDot"); colorKeysMap.put(key_actionBarDefaultTitle, "actionBarDefaultTitle"); colorKeysMap.put(key_actionBarDefaultSubtitle, "actionBarDefaultSubtitle"); colorKeysMap.put(key_actionBarDefaultSearch, "actionBarDefaultSearch"); 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 cc43dbee9..628a34cab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -151,6 +151,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { public interface DialogsSearchAdapterDelegate { void searchStateChanged(boolean searching, boolean animated); void didPressedOnSubDialog(long did); + void didPressedBlockedDialog(View view, long did); void needRemoveHint(long did); void needClearList(); void runResultsEnterAnimation(); @@ -164,12 +165,14 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private final int currentAccount; private boolean drawChecked; private boolean forceDarkTheme; + private boolean showPremiumBlock; private Theme.ResourcesProvider resourcesProvider; - public CategoryAdapterRecycler(Context context, int account, boolean drawChecked, Theme.ResourcesProvider resourcesProvider) { + public CategoryAdapterRecycler(Context context, int account, boolean drawChecked, boolean showPremiumBlock, Theme.ResourcesProvider resourcesProvider) { this.drawChecked = drawChecked; mContext = context; currentAccount = account; + this.showPremiumBlock = showPremiumBlock; this.resourcesProvider = resourcesProvider; } @@ -180,6 +183,9 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { HintDialogCell cell = new HintDialogCell(mContext, drawChecked, resourcesProvider); + if (showPremiumBlock) { + cell.showPremiumBlocked(); + } cell.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(80), AndroidUtilities.dp(86))); return new RecyclerListView.Holder(cell); } @@ -1374,7 +1380,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { View view; switch (viewType) { case VIEW_TYPE_PROFILE_CELL: - view = new ProfileSearchCell(mContext); + view = new ProfileSearchCell(mContext).showPremiumBlock(dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD); break; case VIEW_TYPE_GRAY_SECTION: view = new GraySectionCell(mContext); @@ -1422,8 +1428,14 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); //horizontalListView.setDisallowInterceptTouchEvents(true); - horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false, resourcesProvider)); + horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false, dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD, resourcesProvider)); horizontalListView.setOnItemClickListener((view1, position) -> { + if (view1 instanceof HintDialogCell && ((HintDialogCell) view1).isBlocked()) { + if (delegate != null) { + delegate.didPressedBlockedDialog(view1, ((HintDialogCell) view1).getDialogId()); + } + return; + } if (delegate != null) { delegate.didPressedOnSubDialog((Long) view1.getTag()); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java index da7039ba4..6e139588f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java @@ -36,6 +36,7 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.RecyclerListView; import java.text.SimpleDateFormat; @@ -786,15 +787,21 @@ public class FiltersView extends RecyclerListView { public static class MediaFilterData { - public final int iconResFilled; + public ReactionsLayoutInBubble.VisibleReaction reaction; + + public int iconResFilled; public int titleResId; private String title; - public final int filterType; - public final TLRPC.MessagesFilter filter; + public int filterType; + public TLRPC.MessagesFilter filter; public TLObject chat; public DateData dateData; public boolean removable = true; + public MediaFilterData(ReactionsLayoutInBubble.VisibleReaction reaction) { + this.reaction = reaction; + } + public MediaFilterData(int iconResFilled, String title, TLRPC.MessagesFilter filter, int filterType) { this.iconResFilled = iconResFilled; this.title = title; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java index 6f72d9341..d7919c427 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -83,7 +83,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter implement private int currentAccount = UserConfig.selectedAccount; private Context mContext; private long dialog_id; - private int threadMessageId; + private long threadMessageId; private TLRPC.ChatFull info; private SearchAdapterHelper searchAdapterHelper; private ArrayList searchResultUsernames; @@ -181,7 +181,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter implement } }; - public MentionsAdapter(Context context, boolean darkTheme, long did, int threadMessageId, MentionsAdapterDelegate mentionsAdapterDelegate, Theme.ResourcesProvider resourcesProvider) { + public MentionsAdapter(Context context, boolean darkTheme, long did, long threadMessageId, MentionsAdapterDelegate mentionsAdapterDelegate, Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; mContext = context; delegate = mentionsAdapterDelegate; @@ -1145,7 +1145,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter implement } } final TLRPC.Chat chat; - int threadId; + long threadId; if (parentFragment != null) { chat = parentFragment.getCurrentChat(); threadId = parentFragment.getThreadId(); @@ -1333,7 +1333,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter implement channelParticipantsMentions.q = usernameString; if (threadId != 0) { channelParticipantsMentions.flags |= 2; - channelParticipantsMentions.top_msg_id = threadId; + channelParticipantsMentions.top_msg_id = (int) threadId; } req.filter = channelParticipantsMentions; final int currentReqId = ++channelLastReqId; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index a518f2a76..170b4e95a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -4262,7 +4262,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg messageObject.messageOwner.media.webpage = webPage; TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); messagesRes.messages.add(messageObject.messageOwner); - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, messageObject.getDialogId(), -2, 0, false, messageObject.scheduled, 0); + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, messageObject.getDialogId(), -2, 0, false, messageObject.scheduled ? 1 : 0, 0); } pagesStack.set(0, webPage); if (pagesStack.size() == 1) { @@ -4295,7 +4295,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg if (messageObject != null) { TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); messagesRes.messages.add(messageObject.messageOwner); - MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, messageObject.getDialogId(), -2, 0, false, messageObject.scheduled, 0); + MessagesStorage.getInstance(currentAccount).putMessages(messagesRes, messageObject.getDialogId(), -2, 0, false, messageObject.scheduled ? 1 : 0, 0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java index 5181b1b87..e3040fc65 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java @@ -95,7 +95,7 @@ public class CalendarActivity extends BaseFragment implements NotificationCenter Paint blackoutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private long dialogId; - private int topicId; + private long topicId; private boolean loading; private boolean checkEnterItems; private boolean inSelectionMode; @@ -157,7 +157,7 @@ public class CalendarActivity extends BaseFragment implements NotificationCenter @Override public boolean onFragmentCreate() { dialogId = getArguments().getLong("dialog_id"); - topicId = getArguments().getInt("topic_id"); + topicId = getArguments().getLong("topic_id"); calendarType = getArguments().getInt("type"); if (calendarType == TYPE_PROFILE_STORIES) { 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 de8837a38..25ffd401f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -68,7 +68,6 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; -import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.TLObject; @@ -205,7 +204,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD return 0; } - default int getTopicId() { + default long getTopicId() { return 0; } @@ -1198,7 +1197,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD text = StoriesUtilities.createExpiredStoryString(true, "ExpiredStoryMentioned", R.string.ExpiredStoryMentioned, MessagesController.getInstance(currentAccount).getUser(messageObject.getDialogId()).first_name); } } else if (delegate.getTopicId() == 0 && MessageObject.isTopicActionMessage(messageObject)) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), MessageObject.getTopicId(messageObject.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true)); text = ForumUtilities.createActionTextWithTopic(topic, messageObject); } if (text == null) { 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 594f0761e..90374361f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -88,8 +88,6 @@ import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; -import com.google.android.exoplayer2.util.Log; - import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -139,7 +137,6 @@ import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioVisualizerDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable; -import org.telegram.ui.Components.BottomPagerTabs; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CheckBoxBase; import org.telegram.ui.Components.ClipRoundedDrawable; @@ -754,6 +751,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private TLRPC.TL_pollAnswer answer; } + public static final int INSTANT_BUTTON_TYPE_CONTACT_VIEW = 5; + public static final int INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE = 30; + public static final int INSTANT_BUTTON_TYPE_CONTACT_ADD = 31; + + private static class InstantViewButton { + private int type; + private int buttonWidth; + private float textX; + private StaticLayout layout; + private final RectF rect = new RectF(); + private ButtonBounce buttonBounce; + private Drawable selectorDrawable; + } + public boolean pinnedTop; public boolean pinnedBottom; public boolean drawPinnedTop; @@ -815,6 +826,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private Paint onceClearPaint; private RLottieDrawable onceFire; private Paint onceRadialPaint; + private Paint onceRadialCutPaint; private Paint onceRadialStrokePaint; private int onceRadialPaintColor; @@ -877,6 +889,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float instantViewLayoutWidth; private float instantViewLayoutLeft; private boolean drawInstantView; + private boolean drawContact, drawContactSendMessage, drawContactView, drawContactAdd; + private int drawnContactButtonsFlag = 0; + private ArrayList contactButtons; + private RectF contactRect; + private boolean contactPressed; private boolean pollInstantViewTouchesBottom; public int drawInstantViewType; public String instantViewButtonText; @@ -1114,6 +1131,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean invalidatesParent; public boolean isChat; + public boolean isSavedChat; + public boolean isSavedPreviewChat; public boolean isBot; public boolean isMegagroup; public boolean isForum; @@ -1219,7 +1238,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private TLRPC.PhotoSize currentReplyPhoto; public int instantDrawableColor; public Drawable instantDrawable; - public ReplyMessageLine quoteLine, linkLine, replyLine; + public ReplyMessageLine quoteLine, linkLine, replyLine, contactLine; private AnimatedFloat translationLoadingFloat; private LinkPath translationLoadingPath; @@ -1261,7 +1280,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private StaticLayout timeLayout; public int timeWidth; private int timeTextWidth; - private int timeX; + protected int timeX; private CharSequence currentTimeString; private boolean drawTime = true; private boolean forceNotDrawTime; @@ -1276,6 +1295,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float mediaSpoilerRevealY; private float mediaSpoilerRevealMaxRadius; private SpoilerEffect2 mediaSpoilerEffect2; + private Integer mediaSpoilerEffect2Index; private float unlockAlpha = 1f; private float unlockX; @@ -1313,7 +1333,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiStack; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiReplyStack; public AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiDescriptionStack; - public ButtonBounce replyBounce; + public ButtonBounce replyBounce, contactBounce; public float replyBounceX, replyBounceY; public Drawable replySelector; public LoadingDrawable replyLoadingDrawable; @@ -1361,6 +1381,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private FlagSecureReason flagSecure; + public boolean makeVisibleAfterChange; + private Runnable diceFinishCallback = new Runnable() { @Override public void run() { @@ -1668,7 +1690,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int id; TLRPC.Chat chat = currentChat; if (currentMessageObject.messageOwner.fwd_from != null) { - if ((currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { + if (chat == null && (currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id; } else { id = currentMessageObject.messageOwner.fwd_from.channel_post; @@ -2264,7 +2286,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (instantPressed) { - if (drawInstantView) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { + if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { + delegate.needPlayMessage(this, currentMessageObject, false); + } else { + MediaController.getInstance().pauseMessage(currentMessageObject); + } + } else if (drawInstantView) { if (delegate != null) { delegate.didPressInstantButton(this, drawInstantViewType); } @@ -2331,13 +2359,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate pressedEmoji = null; resetPressedLink(2); } else { - if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { - if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { - delegate.needPlayMessage(this, currentMessageObject, false); - } else { - MediaController.getInstance().pauseMessage(currentMessageObject); - } - } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && drawImageButton) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && drawImageButton) { if (buttonState == -1) { if (SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview) { delegate.didPressImage(this, lastTouchX, lastTouchY); @@ -2551,6 +2573,91 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return false; } + private boolean checkContactMotionEvent(MotionEvent event) { + if (currentMessageObject.type != MessageObject.TYPE_CONTACT) { + return false; + } + int x = (int) event.getX(); + int y = (int) event.getY(); + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (contactButtons != null && contactButtons.size() > 1) { + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + if (instantViewButton.rect.contains(x, y)) { + if (instantViewButton.buttonBounce == null) { + instantViewButton.buttonBounce = new ButtonBounce(this); + } + instantViewButton.buttonBounce.setPressed(true); + if (Build.VERSION.SDK_INT >= 21 && instantViewButton.selectorDrawable != null) { + instantViewButton.selectorDrawable.setHotspot(x, y); + instantViewButton.selectorDrawable.setState(pressedState); + } + invalidate(); + return true; + } + } + } + if (contactRect.contains(x, y)) { + contactPressed = true; + contactBounce.setPressed(true); + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { + selectorDrawable[0].setHotspot(x, y); + selectorDrawable[0].setState(pressedState); + } + invalidate(); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + if (contactPressed) { + if (delegate != null) { + if (contactButtons != null && contactButtons.size() == 1) { + delegate.didPressInstantButton(this, contactButtons.get(0).type); + } else { + delegate.didPressInstantButton(this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); + } + } + playSoundEffect(SoundEffectConstants.CLICK); + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { + selectorDrawable[0].setState(StateSet.NOTHING); + } + contactPressed = false; + contactBounce.setPressed(false); + invalidate(); + } else if (contactButtons != null && contactButtons.size() > 1) { + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + if (instantViewButton.buttonBounce != null && instantViewButton.buttonBounce.isPressed()) { + if (delegate != null) { + delegate.didPressInstantButton(this, instantViewButton.type); + } + if (Build.VERSION.SDK_INT >= 21 && instantViewButton.selectorDrawable != null) { + instantViewButton.selectorDrawable.setState(StateSet.NOTHING); + } + instantViewButton.buttonBounce.setPressed(false); + playSoundEffect(SoundEffectConstants.CLICK); + invalidate(); + } + } + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (contactPressed && Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { + selectorDrawable[0].setHotspot(x, y); + } else if (contactButtons != null && contactButtons.size() > 1) { + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + if (instantViewButton.buttonBounce != null && instantViewButton.buttonBounce.isPressed()) { + if (Build.VERSION.SDK_INT >= 21 && instantViewButton.selectorDrawable != null) { + instantViewButton.selectorDrawable.setHotspot(x, y); + } + break; + } + } + } + } + return false; + } + private void invalidateWithParent() { if (currentMessagesGroup != null && getParent() != null) { ((ViewGroup) getParent()).invalidate(); @@ -2713,6 +2820,27 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate instantButtonBounce.setPressed(instantButtonPressed = pressed); } + private void resetContactButtonsPressedState() { + contactPressed = false; + if (contactBounce != null) { + contactBounce.setPressed(false); + } + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { + selectorDrawable[0].setState(StateSet.NOTHING); + } + if (contactButtons != null) { + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + if (instantViewButton.buttonBounce != null) { + instantViewButton.buttonBounce.setPressed(false); + } + if (instantViewButton.selectorDrawable != null) { + instantViewButton.selectorDrawable.setState(StateSet.NOTHING); + } + } + } + } + private boolean checkDateMotionEvent(MotionEvent event) { if (!currentMessageObject.isImportedForward()) { return false; @@ -3321,6 +3449,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!result) { result = checkAudioMotionEvent(event); } + if (!result) { + result = checkContactMotionEvent(event); + } if (!result) { result = checkLinkPreviewMotionEvent(event); } @@ -3365,6 +3496,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate gamePreviewPressed = false; instantPressed = commentButtonPressed = false; setInstantButtonPressed(false); + resetContactButtonsPressedState(); if (Build.VERSION.SDK_INT >= 21) { for (int a = 0; a < selectorDrawable.length; a++) { if (selectorDrawable[a] != null) { @@ -3967,9 +4099,34 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - public void setVisiblePart(int position, int height, int parent, float parentOffset, float visibleTop, int parentW, int parentH, int blurredViewTopOffset, int blurredViewBottomOffset) { + public void copyVisiblePartTo(ChatMessageCell cell) { + if (cell == null) return; + cell.setVisiblePart(childPosition, visibleHeight, visibleParent, visibleParentOffset, visibleTop, parentWidth, parentHeight, blurredViewTopOffset, blurredViewBottomOffset); + } + + private int childPosition; + private int visibleHeight; + private int visibleParent; + private float visibleParentOffset; + private float visibleTop; + public void setVisiblePart( + int position, + int height, + int parent, + float parentOffset, + float visibleTop, + int parentW, + int parentH, + int blurredViewTopOffset, + int blurredViewBottomOffset + ) { + this.childPosition = position; + this.visibleHeight = height; + this.visibleParent = parent; this.parentWidth = parentW; this.parentHeight = parentH; + this.visibleTop = visibleTop; + this.visibleParentOffset = parentOffset; this.backgroundHeight = parentH; this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; @@ -4534,6 +4691,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaSpoilerEffect2 != null) { if (mediaSpoilerEffect2.destroyed) { mediaSpoilerEffect2 = SpoilerEffect2.getInstance(this); + if (mediaSpoilerEffect2Index != null) { + mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); + } } else { mediaSpoilerEffect2.attach(this); } @@ -4543,6 +4703,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + public void copySpoilerEffect2AttachIndexFrom(ChatMessageCell cell) { + if (cell != null && cell.mediaSpoilerEffect2 != null) { + mediaSpoilerEffect2Index = cell.mediaSpoilerEffect2.getAttachIndex(cell); + if (mediaSpoilerEffect2 != null) { + mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); + } + } + } + boolean imageReceiversAttachState; boolean imageReceiversVisibleState; @@ -4634,7 +4803,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (canDownload != 0) { if (document != null) { - FileLoader.getInstance(currentAccount).loadFile(document, messageObject, FileLoader.PRIORITY_NORMAL, MessageObject.isVideoDocument(document) && messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + FileLoader.getInstance(currentAccount).loadFile(document, messageObject, FileLoader.PRIORITY_NORMAL, (MessageObject.isVideoDocument(document) || messageObject.isVoiceOnce() || messageObject.isRoundOnce()) && messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); } else if (photo != null) { FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForObject(photo, messageObject.photoThumbsObject), messageObject, null, FileLoader.PRIORITY_NORMAL, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); } @@ -4802,6 +4971,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setCrossfadeByScale(0); photoImage.setGradientBitmap(null); photoImage.clearDecorators(); + photoImage.setInvalidateAll(false); + linkPreviewY = 0; lastTranslated = messageObject.translated; lastSendState = messageObject.messageOwner.send_state; lastDeleteDate = messageObject.messageOwner.destroyTime; @@ -4833,8 +5004,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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; - if (isPinnedChat || drawSideButton == 1 && messageObject.messageOwner.fwd_from != null && !messageObject.isOutOwner() && messageObject.messageOwner.fwd_from.saved_from_peer != null && messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId()) { + drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) ? 1 : 0; + if (isPinnedChat || drawSideButton == 1 && (messageObject.messageOwner.fwd_from != null && !messageObject.isOutOwner() && messageObject.messageOwner.fwd_from.saved_from_peer != null && messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId() || messageObject.isSaved)) { drawSideButton = 2; } } @@ -4890,6 +5061,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } + resetContactButtonsPressedState(); + drawnContactButtonsFlag = 0; + drawContact = false; + drawContactView = false; + drawContactSendMessage = false; + drawContactAdd = false; spoilerPressed = null; isSpoilerRevealing = false; linkPreviewPressed = false; @@ -5168,7 +5345,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { maxWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); } - drawName = isPinnedChat || (messageObject.messageOwner.peer_id != null && messageObject.messageOwner.peer_id.channel_id != 0 && (!messageObject.isOutOwner() || messageObject.isSupergroup())) || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; + drawName = isPinnedChat || isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || (messageObject.messageOwner.peer_id != null && messageObject.messageOwner.peer_id.channel_id != 0 && (!messageObject.isOutOwner() || messageObject.isSupergroup())) || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; } availableTimeWidth = maxWidth; @@ -5248,7 +5425,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if ("telegram_megagroup".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 2; - } else if ("telegram_message".equals(webpageType) || "photo".equals(webpageType) && webpage != null && webpage.url != null && Browser.isInternalUri(Uri.parse(webpage.url), null)) { + } else if ("telegram_message".equals(webpageType) || "photo".equals(webpageType) && webpage != null && Browser.isTMe(webpage.url)) { drawInstantView = true; drawInstantViewType = 3; } else if ("telegram_community".equals(webpageType) || "telegram_chatlist".equals(webpageType)) { @@ -5420,7 +5597,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); giveawayResultsMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); - backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? AndroidUtilities.dp(10) : 0); + if (messageObject.isSponsored()) { + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(getParentWidth() - AndroidUtilities.dp(50), AndroidUtilities.dp(270)); + } + } else { + backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? AndroidUtilities.dp(10) : 0); // todo! here we set + } if (messageObject.isSponsored()) { totalHeight = AndroidUtilities.dp(22.5f); } else { @@ -5521,7 +5706,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } duration = 0; type = null; - isSmallImage = true; + isSmallImage = photo != null || peerPhoto != null; linkPreviewAbove = false; smallImage = true; } else if (drawInstantViewType == 19) { @@ -6164,6 +6349,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int height; if (smallImage || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { width = height = maxPhotoWidth; + photoImage.setInvalidateAll(true); } else { if (hasGamePreview || hasInvoicePreview) { if (hasInvoicePreview) { @@ -6347,7 +6533,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate blurredPhotoImage.setImageBitmap((Bitmap) null); } if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed) { - blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap())); + blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } drawPhotoImage = true; @@ -6509,7 +6695,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate namesOffset -= AndroidUtilities.dp(1); } } else if (messageObject.type == MessageObject.TYPE_CONTACT) { - drawName = messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; + drawContact = true; + + drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; drawForwardedName = !isRepliesChat; drawPhotoImage = true; photoImage.setRoundRadius(AndroidUtilities.dp(22)); @@ -6560,8 +6748,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (user != null || !TextUtils.isEmpty(messageObject.vCardData) || MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaContact) { - drawInstantView = true; - drawInstantViewType = 5; + if (user != null) { + drawContactSendMessage = true; + drawContactAdd = !user.contact; + } else { + drawContactView = true; + } } CharSequence currentNameString = ContactsController.formatName(MessageObject.getMedia(messageObject.messageOwner).first_name, MessageObject.getMedia(messageObject.messageOwner).last_name).replace('\n', ' '); @@ -6581,13 +6773,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (drawNameLayout && messageObject.getReplyMsgId() == 0) { namesOffset += AndroidUtilities.dp(7); } - - totalHeight = AndroidUtilities.dp(70 - 15) + namesOffset + docTitleLayout.getHeight(); + totalHeight = AndroidUtilities.dp(65) + namesOffset + docTitleLayout.getHeight(); if (drawPinnedTop) { namesOffset -= AndroidUtilities.dp(1); } - if (drawInstantView) { - createInstantViewButton(); + if (drawContactSendMessage || drawContactAdd || drawContactView) { + createContactButtons(); } else { if (docTitleLayout.getLineCount() > 0) { int timeLeft = backgroundWidth - AndroidUtilities.dp(40 + 18 + 44 + 8) - (int) Math.ceil(docTitleLayout.getLineWidth(docTitleLayout.getLineCount() - 1)); @@ -6599,8 +6790,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!reactionsLayoutInBubble.isSmall) { if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.measure(backgroundWidth - AndroidUtilities.dp(32), Gravity.LEFT); - reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + AndroidUtilities.dp(12); - reactionsLayoutInBubble.positionOffsetY += -AndroidUtilities.dp(4); + reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height; if (backgroundWidth - AndroidUtilities.dp(32) - reactionsLayoutInBubble.lastLineX < timeWidth) { reactionsLayoutInBubble.totalHeight += AndroidUtilities.dp(12); reactionsLayoutInBubble.positionOffsetY += -AndroidUtilities.dp(12); @@ -6610,7 +6800,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (messageObject.type == MessageObject.TYPE_VOICE) { drawForwardedName = !isRepliesChat; - drawName = messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; + drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null; int maxWidth; if (AndroidUtilities.isTablet()) { backgroundWidth = maxWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(drawAvatar ? 102 : 50), AndroidUtilities.dp(270)); @@ -6650,7 +6840,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } else if (messageObject.type == MessageObject.TYPE_MUSIC) { - drawName = (messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); + drawName = isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || (messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); int maxWidth; if (AndroidUtilities.isTablet()) { backgroundWidth = maxWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(drawAvatar ? 102 : 50), AndroidUtilities.dp(270)); @@ -6872,7 +7062,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate button.count = answer.voters; button.correct = answer.correct; if ((pollVoted || pollClosed) && media.results.total_voters > 0) { - button.decimal = 100 * (answer.voters / (float) media.results.total_voters); + float percent = answer.voters / (float) media.results.total_voters; + button.decimal = 100 * percent; button.percent = (int) button.decimal; button.decimal -= button.percent; } else { @@ -6987,7 +7178,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { drawForwardedName = (messageObject.messageOwner.fwd_from != null && !(messageObject.isAnyKindOfSticker() && messageObject.isDice())) || messageObject.type == MessageObject.TYPE_STORY; if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { - drawName = (messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isRepostPreview || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); + drawName = (isSavedChat && !messageObject.isOutOwner() && (messageObject.getSavedDialogId() < 0 || messageObject.getSavedDialogId() == UserObject.ANONYMOUS) || messageObject.isFromGroup() && messageObject.isSupergroup() || messageObject.isRepostPreview || messageObject.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); } mediaBackground = isMedia = messageObject.type != MessageObject.TYPE_FILE; drawImageButton = true; @@ -7473,7 +7664,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate blurredPhotoImage.setImageBitmap((Bitmap) null); } if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed) { - blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap())); + blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } } else { @@ -7932,8 +8123,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ) { if (messageObject.needDrawBluredPreview()) { photoImage.setColorFilter(getFancyBlurFilter()); - currentPhotoFilter += "_b2"; - currentPhotoFilterThumb += "_b2"; + if (!messageObject.isRoundOnce()) { + currentPhotoFilter += "_b2"; + } + if (messageObject.isRoundOnce()) { + currentPhotoFilterThumb += "_b2r"; + } else { + currentPhotoFilterThumb += "_b2"; + } } else { currentPhotoFilterThumb += "_b"; } @@ -8056,7 +8253,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(videoSize, documentAttach), null, ImageLocation.getForDocument(currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb, documentAttach), currentPhotoObject != null ? currentPhotoFilter : currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } else { if (isRoundVideo && !messageIdChanged && photoImage.hasStaticThumb()) { - photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, null, null, photoImage.getStaticThumb(), document.size, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, null, null, photoImage.getStaticThumb(), document.size, null, messageObject, messageObject.isRoundOnce() ? cacheType : 0); } else { photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } @@ -8067,7 +8264,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForDocument(videoSize, documentAttach), null, ImageLocation.getForDocument(currentPhotoObject != null ? currentPhotoObject : currentPhotoObjectThumb, documentAttach), currentPhotoObject != null ? currentPhotoFilter : currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } else { - photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForDocument(document), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, messageObject.isRoundOnce() ? cacheType : 0); } } } else { @@ -8100,7 +8297,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate blurredPhotoImage.setImageBitmap((Bitmap) null); } if (photoImage.getBitmap() != null && !photoImage.getBitmap().isRecycled() && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed) { - blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap())); + blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(photoImage.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } setMessageObjectInternal(messageObject); @@ -8177,6 +8374,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageObject.hasMediaSpoilers() && SpoilerEffect2.supports()) { if (mediaSpoilerEffect2 == null) { mediaSpoilerEffect2 = SpoilerEffect2.getInstance(this); + if (mediaSpoilerEffect2Index != null) { + mediaSpoilerEffect2.reassignAttach(this, mediaSpoilerEffect2Index); + } } } else { if (mediaSpoilerEffect2 != null) { @@ -8634,7 +8834,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate updateButtonState(false, !messageIdChanged && !messageObject.cancelEditing, true); if (!currentMessageObject.loadingCancelled && buttonState == 2 && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO && DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject)) { - FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, 0); + FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); buttonState = 4; radialProgress.setIcon(getIconForCurrentState(), false, false); } @@ -8666,7 +8866,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Activity activity = AndroidUtilities.findActivity(getContext()); Window window = activity == null ? null : activity.getWindow(); if (window != null) { - flagSecure = new FlagSecureReason(window, () -> currentMessageObject != null && currentMessageObject.messageOwner != null && (currentMessageObject.messageOwner.noforwards || currentMessageObject.hasRevealedExtendedMedia())); + flagSecure = new FlagSecureReason(window, () -> currentMessageObject != null && currentMessageObject.messageOwner != null && (currentMessageObject.messageOwner.noforwards || currentMessageObject.isVoiceOnce() || currentMessageObject.hasRevealedExtendedMedia())); if (attachedToWindow) { flagSecure.attach(); } @@ -8823,6 +9023,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate giveawayMessageCell.setButtonPressed(false); giveawayResultsMessageCell.setButtonPressed(false); + resetContactButtonsPressedState(); + if (pressedVoteButton != -1 || pollHintPressed || psaHintPressed || instantPressed || otherPressed || commentButtonPressed) { instantPressed = commentButtonPressed = false; setInstantButtonPressed(false); @@ -9348,6 +9550,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) { + if (currentMessageObject.isSponsored()) { + backgroundWidth = maxChildWidth + AndroidUtilities.dp(31); + return; + } boolean newLineForTime; int lastLineWidth = (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) ? currentMessageObject.lastLineWidth : reactionsLayoutInBubble.lastLineX; if (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall) { @@ -9739,6 +9945,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outViews : Theme.key_chat_inViews); } else if (linkLine != null) { color = linkLine.getColor(); + } else if (contactLine != null) { + color = contactLine.getColor(); } else { color = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText); } @@ -9909,6 +10117,79 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private void createContactButtons() { + if (Build.VERSION.SDK_INT >= 21) { + createSelectorDrawable(0); + } + if (drawContact) { + int needDrawFlag = 0; + int buttonsCount = 0; + if (drawContactView) { + needDrawFlag |= 1; + buttonsCount++; + } + if (drawContactSendMessage) { + needDrawFlag |= 2; + buttonsCount++; + } + if (drawContactAdd) { + needDrawFlag |= 4; + buttonsCount++; + } + if (buttonsCount == 0) { + contactButtons = null; + drawnContactButtonsFlag = 0; + return; + } + totalHeight += AndroidUtilities.dp(60); + + boolean needRecreate = needDrawFlag != drawnContactButtonsFlag; + if (needRecreate) { + drawnContactButtonsFlag = 0; + int mWidth = (backgroundWidth - AndroidUtilities.dp(10 + 24 + 10 + 31)) / buttonsCount; + int parentWidth = (backgroundWidth - AndroidUtilities.dp(37)) / buttonsCount; + + if (contactButtons == null) { + contactButtons = new ArrayList<>(buttonsCount); + } else { + contactButtons.clear(); + } + + if (drawContactView) { + drawnContactButtonsFlag |= 1; + String str = LocaleController.getString("ViewContact", R.string.ViewContact); + InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_VIEW, str, mWidth, parentWidth); + contactButtons.add(instantViewButton); + } + if (drawContactSendMessage) { + drawnContactButtonsFlag |= 2; + String str = LocaleController.getString("SharedContactMessage", R.string.SharedContactMessage); + InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE, str, mWidth, parentWidth); + contactButtons.add(instantViewButton); + } + if (drawContactAdd) { + drawnContactButtonsFlag |= 4; + String str = LocaleController.getString("SharedContactAdd", R.string.SharedContactAdd); + InstantViewButton instantViewButton = createInstantViewButton(INSTANT_BUTTON_TYPE_CONTACT_ADD, str, mWidth, parentWidth); + contactButtons.add(instantViewButton); + } + } + } + } + + private InstantViewButton createInstantViewButton(int type, String str, int availableWidth, int parentWidth) { + InstantViewButton instantViewButton = new InstantViewButton(); + instantViewButton.type = type; + instantViewButton.layout = new StaticLayout(TextUtils.ellipsize(str, Theme.chat_instantViewPaint, availableWidth, TextUtils.TruncateAt.END), Theme.chat_instantViewPaint, availableWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + instantViewButton.buttonWidth = parentWidth; + if (instantViewButton.layout.getLineCount() > 0) { + instantViewButton.textX = (float) (instantViewButton.buttonWidth - Math.ceil(instantViewButton.layout.getLineWidth(0))) / 2; + int instantTextLeftX = (int) instantViewButton.layout.getLineLeft(0); + instantViewButton.textX -= instantTextLeftX; + } + return instantViewButton; + } + @Override public void requestLayout() { if (inLayout) { @@ -10165,7 +10446,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (!transitionParams.imageChangeBoundsTransition || transitionParams.updatePhotoImageX) { transitionParams.updatePhotoImageX = false; - photoImage.setImageCoords((float) x, photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); + photoImage.setImageCoords(x, currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO ? linkPreviewY : photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); } } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { @@ -10214,13 +10495,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { int x; if (currentMessageObject.isOutOwner()) { - x = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(26); } else if (needDrawAvatar()) { - x = AndroidUtilities.dp(72); + x = AndroidUtilities.dp(84); } else { - x = AndroidUtilities.dp(23); + x = AndroidUtilities.dp(35); } - photoImage.setImageCoords(x, AndroidUtilities.dp(13) + namesOffset, AndroidUtilities.dp(44), AndroidUtilities.dp(44)); + photoImage.setImageCoords(x, AndroidUtilities.dp(24) + namesOffset, AndroidUtilities.dp(46), AndroidUtilities.dp(46)); } else { int x; if (currentMessageObject.type == MessageObject.TYPE_TEXT && (hasLinkPreview || hasGamePreview || hasInvoicePreview)) { @@ -10619,7 +10900,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.restore(); } else { if (allowDrawPhotoImage()) { + boolean needRestore = false; + if (contactBounce != null) { + float contactScale = contactBounce.getScale(0.0125f); + if (contactScale != 1f) { + needRestore = true; + canvas.save(); + canvas.scale(contactScale, contactScale, contactRect.centerX(), contactRect.centerY()); + } + } imageDrawn = drawPhotoImage(canvas); + if (needRestore) { + canvas.restore(); + } } else { imageDrawn = true; } @@ -11231,7 +11524,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public boolean drawingToBitmap; - private void drawBlurredPhoto(Canvas canvas) { + public void drawBlurredPhoto(Canvas canvas) { if (currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress == 1f) { return; } @@ -11263,16 +11556,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate blurredPhotoImage.draw(canvas); } + drawBlurredPhotoParticles(canvas); + canvas.restore(); + } + + public void drawBlurredPhotoParticles(Canvas canvas) { if (mediaSpoilerEffect2 != null) { canvas.translate(photoImage.getImageX(), photoImage.getImageY()); mediaSpoilerEffect2.draw(canvas, this, (int) photoImage.getImageWidth(), (int) photoImage.getImageHeight(), photoImage.getAlpha(), drawingToBitmap); - canvas.restore(); } else { int sColor = Color.WHITE; mediaSpoilerEffect.setColor(ColorUtils.setAlphaComponent(sColor, (int) (Color.alpha(sColor) * 0.325f * photoImage.getAlpha()))); mediaSpoilerEffect.setBounds((int) photoImage.getImageX(), (int) photoImage.getImageY(), (int) photoImage.getImageX2(), (int) photoImage.getImageY2()); mediaSpoilerEffect.draw(canvas); - canvas.restore(); invalidate(); } } @@ -11362,7 +11658,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate onceClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } if (scale < 1f) { - canvas.saveLayerAlpha(radialProgress.progressRect, 0xFF, Canvas.ALL_SAVE_FLAG); + canvas.save(); final float s = (1f - scale) * .7f; canvas.scale(s, s, radialProgress.progressRect.centerX(), AndroidUtilities.lerp(radialProgress.progressRect.top, radialProgress.progressRect.bottom, .5f)); if (onceFire == null) { @@ -11371,6 +11667,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate onceFire.setAllowDecodeSingleFrame(true); onceFire.setAutoRepeat(1); onceFire.start(); + onceFire.scaleByCanvas = true; } onceFire.setBounds( (int) radialProgress.progressRect.left, @@ -11381,19 +11678,26 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (onceRadialPaint == null) { onceRadialPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } + if (onceRadialCutPaint == null) { + onceRadialCutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + onceRadialCutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + } if (onceRadialStrokePaint == null) { onceRadialStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); onceRadialStrokePaint.setStyle(Paint.Style.STROKE); } int iconColor = radialProgress.iconColorKey >= 0 ? getThemedColor(radialProgress.iconColorKey) : radialProgress.iconColor; - if (onceRadialPaintColor != iconColor) { - onceRadialPaint.setColorFilter(new PorterDuffColorFilter(onceRadialPaintColor = iconColor, PorterDuff.Mode.SRC_IN)); - onceRadialStrokePaint.setColorFilter(new PorterDuffColorFilter(onceRadialPaintColor, PorterDuff.Mode.SRC_IN)); - } + onceRadialPaint.setColor(iconColor); + onceRadialStrokePaint.setColor(iconColor); radialProgress.mediaActionDrawable.applyShaderMatrix(false); onceRadialPaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); onceRadialStrokePaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); - onceFire.draw(canvas, onceRadialPaint); + AndroidUtilities.rectTmp.set(onceFire.getBounds()); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); + AndroidUtilities.rectTmp.inset(1, 1); + canvas.drawRect(AndroidUtilities.rectTmp, onceRadialPaint); + onceFire.draw(canvas, onceRadialCutPaint); + canvas.restore(); canvas.restore(); onceRadialStrokePaint.setAlpha((int) (0xFF * (1f - scale))); @@ -11802,7 +12106,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } photoImage.setImageX(AndroidUtilities.lerp(transitionParams.photoImageFromCenterX, photoImage.getCenterX(), transitionParams.animateChangeProgress) - photoImage.getImageWidth() / 2f); photoImage.setImageY(AndroidUtilities.lerp(transitionParams.photoImageFromCenterY, photoImage.getCenterY(), transitionParams.animateChangeProgress) - photoImage.getImageHeight() / 2f); - } else if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { + } else if (!isSmallImage && documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { photoImage.setImageWidth(photoWidth); } if (!isSmallImage && drawImageButton) { @@ -11923,7 +12227,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate color = linkLine.getColor(); } if (this.instantDrawable == null) { - this.instantDrawable = getContext().getResources().getDrawable(R.drawable.msg_instant).mutate(); + if (drawInstantViewType == 16) { + this.instantDrawable = getContext().getResources().getDrawable(R.drawable.mini_external_link).mutate(); + } else { + this.instantDrawable = getContext().getResources().getDrawable(R.drawable.msg_instant).mutate(); + } } if (this.instantDrawableColor != color) { this.instantDrawable.setColorFilter(new PorterDuffColorFilter(this.instantDrawableColor = color, PorterDuff.Mode.SRC_IN)); @@ -11953,6 +12261,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate instantDrawable.setAlpha((int) (0xFF * alpha)); instantDrawable.draw(canvas); l += AndroidUtilities.dp(15); + } else if (drawInstantViewType == 16) { + l -= AndroidUtilities.dp(11f); + setDrawableBounds(instantDrawable, l + textWidth + AndroidUtilities.dp(4f), instantY - AndroidUtilities.dp(2f), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); + instantDrawable.setAlpha((int) (0xFF * alpha)); + instantDrawable.draw(canvas); } if (instantViewLayout != null) { canvas.save(); @@ -12044,6 +12357,111 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return (currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) && !hasLinkPreview && (currentMessageObject == null || !currentMessageObject.isRepostPreview); } + private void drawContact(Canvas canvas) { + if (contactLine == null) { + contactLine = new ReplyMessageLine(this); + } + int nameColor = contactLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_CONTACT); + if (contactBounce == null) { + contactBounce = new ButtonBounce(this, 2.0f, 2.0f); + } + int textX = (int) (photoImage.getImageX() - AndroidUtilities.dp(13)); + int instantY = layoutHeight - AndroidUtilities.dp(62); + if (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall) { + instantY -= reactionsLayoutInBubble.totalHeight; + } + if (drawCommentButton) { + instantY -= AndroidUtilities.dp(shouldDrawTimeOnMedia() ? 39.3f : 41); + } + if (contactRect == null) { + contactRect = new RectF(); + } + int width = getBackgroundDrawableRight() - (AndroidUtilities.dp(10) + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? AndroidUtilities.dp(6) : 0)) - getExtraTextX(); + contactRect.set(textX, photoImage.getImageY() - AndroidUtilities.dp(9), width, instantY + AndroidUtilities.dp(38f)); + final float scale = contactBounce.getScale(0.0125f); + boolean needContactViewScale = scale != 1f; + if (needContactViewScale) { + canvas.save(); + canvas.scale(scale, scale, contactRect.centerX(), contactRect.centerY()); + } + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable[0] != null) { + selectorDrawableMaskType[0] = 0; + selectorDrawable[0].setBounds(textX, (int) (photoImage.getImageY() - dp(9)), width, instantY + AndroidUtilities.dp(38f)); + selectorDrawable[0].draw(canvas); + } + float radF = (float) Math.floor(SharedConfig.bubbleRadius / 3f); + int rad = (int) radF; + contactLine.drawBackground(canvas, contactRect, radF, radF, radF, 1f); + contactLine.drawLine(canvas, contactRect, 1f); + Theme.chat_contactNamePaint.setColor(nameColor); + Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_inContactPhoneSelectedText)); + if (currentMessageObject.isOutOwner()) { + Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_messageTextOut)); + } else { + Theme.chat_contactPhonePaint.setColor(getThemedColor(Theme.key_chat_messageTextIn)); + } + if (titleLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(27) + namesOffset); + titleLayout.draw(canvas); + canvas.restore(); + } + if (docTitleLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(50) + namesOffset); + docTitleLayout.draw(canvas); + canvas.restore(); + } + if (contactButtons != null && contactButtons.size() > 0) { + Theme.chat_instantViewPaint.setColor(nameColor); + Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(nameColor, .10f)); + int wasAlpha = Theme.chat_instantViewPaint.getAlpha(); + Theme.chat_instantViewPaint.setAlpha((int) (wasAlpha * .18f)); + canvas.drawRect(contactRect.left + AndroidUtilities.dp(3 + 7), instantY + AndroidUtilities.dp(2), contactRect.right - AndroidUtilities.dp(7), instantY + AndroidUtilities.dp(2) + Math.max(1, AndroidUtilities.dp(0.66f)), Theme.chat_instantViewPaint); + Theme.chat_instantViewPaint.setAlpha(wasAlpha); + instantY += AndroidUtilities.dp(2); + textX += AndroidUtilities.dp(3); + boolean needCreateSelectorDrawable = contactButtons != null && contactButtons.size() > 1; + int rippleColor = contactLine.getBackgroundColor(); + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + instantViewButton.rect.set(textX, instantY, textX + instantViewButton.buttonWidth, instantY + AndroidUtilities.dp(36)); + if (needCreateSelectorDrawable && instantViewButton.selectorDrawable == null) { + instantViewButton.selectorDrawable = Theme.createRadSelectorDrawable(linkPreviewSelectorColor = rippleColor, 0, 0, i == (contactButtons.size() - 1) ? rad : 0, 0); + } + if (instantViewButton.selectorDrawable != null) { + instantViewButton.selectorDrawable.setBounds(textX, instantY, textX + instantViewButton.buttonWidth, instantY + AndroidUtilities.dp(36)); + instantViewButton.selectorDrawable.draw(canvas); + } + float buttonScale = 1f; + boolean needButtonScale = false; + if (!needContactViewScale) { + if (instantViewButton.buttonBounce != null) { + buttonScale = instantViewButton.buttonBounce.getScale(0.02f); + needButtonScale = buttonScale != 1; + } + } + if (needButtonScale) { + canvas.save(); + canvas.scale(buttonScale, buttonScale, instantViewButton.rect.centerX(), instantViewButton.rect.centerY()); + } + if (instantViewButton.layout != null) { + canvas.save(); + canvas.translate(textX + instantViewButton.textX, instantY + AndroidUtilities.dp(10.5f)); + instantViewButton.layout.draw(canvas); + canvas.restore(); + } + if (needButtonScale) { + canvas.restore(); + } + textX += instantViewButton.buttonWidth; + } + } + if (needContactViewScale) { + canvas.restore(); + } + } + private void drawBotButtons(Canvas canvas, ArrayList botButtons, int alpha) { int addX; if (currentMessageObject != null && currentMessageObject.isOutOwner()) { @@ -13227,7 +13645,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentMessageObject.putInDownloadsStore = true; } if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { - FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); + FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); currentMessageObject.loadingCancelled = false; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { createLoadingProgressLayout(documentAttach); @@ -13297,7 +13715,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (isRoundVideo) { if (currentMessageObject.isSecretMedia()) { - FileLoader.getInstance(currentAccount).loadFile(currentMessageObject.getDocument(), currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 1); + FileLoader.getInstance(currentAccount).loadFile(currentMessageObject.getDocument(), currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } else { currentMessageObject.gifState = 2; TLRPC.Document document = currentMessageObject.getDocument(); @@ -13409,7 +13827,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate wouldBeInPip = true; ChatMessageCell.this.invalidate(); } - } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { //asdf1 + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { radialProgress.setProgress(0, false); FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; @@ -13441,7 +13859,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate delegate.didPressImage(this, 0, 0); } } else if (buttonState == 4) { - if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { // asdf2 + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { if (currentMessageObject.isOut() && (currentMessageObject.isSending() || currentMessageObject.isEditing()) || currentMessageObject.isSendError()) { if (delegate != null && radialProgress.getIcon() != MediaActionDrawable.ICON_CHECK) { delegate.didPressCancelSendButton(this); @@ -13551,7 +13969,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate blurredPhotoImage.setImageBitmap((Bitmap) null); } if (currentMessageObject.hasMediaSpoilers() && imageReceiver.getBitmap() != null && !imageReceiver.getBitmap().isRecycled()) { - blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(imageReceiver.getBitmap())); + blurredPhotoImage.setImageBitmap(Utilities.stackBlurBitmapMax(imageReceiver.getBitmap(), currentMessageObject.isRoundVideo())); blurredPhotoImage.setColorFilter(getFancyBlurFilter()); } } @@ -13948,8 +14366,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.deleted && !currentMessageObject.deletedByThanos || currentMessageObject.isSponsored()) { return false; } - if (currentPosition != null) { - if (!currentMessagesGroup.isDocuments && !currentPosition.last) { + if (currentMessagesGroup != null && currentPosition != null) { + final boolean last = (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & (messageObject.isOutOwner() ? MessageObject.POSITION_FLAG_LEFT : MessageObject.POSITION_FLAG_RIGHT)) != 0; + if ((!currentMessagesGroup.reversed && !currentMessagesGroup.isDocuments && !last || currentMessagesGroup.reversed && !last)) { return false; } } @@ -13971,7 +14390,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentChat = MessagesController.getInstance(currentAccount).getChat(fwd_from.from_id.channel_id); } else if (fwd_from != null && fwd_from.saved_from_peer != null) { if (fwd_from.saved_from_peer.user_id != 0) { - if (fwd_from.from_id instanceof TLRPC.TL_peerUser) { + if (!isSavedChat && fwd_from.from_id instanceof TLRPC.TL_peerUser) { currentUser = messagesController.getUser(fwd_from.from_id.user_id); } else { currentUser = messagesController.getUser(fwd_from.saved_from_peer.user_id); @@ -14281,9 +14700,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } drawTopic = false; - if (!isThreadChat && (delegate != null && delegate.shouldShowTopicButton()) && !pinnedTop && (MessageObject.getTopicId(messageObject.messageOwner, true) != 0 || messageObject.replyToForumTopic != null)) { + if (!isThreadChat && (delegate != null && delegate.shouldShowTopicButton()) && !pinnedTop && (MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true) != 0 || messageObject.replyToForumTopic != null)) { if (currentPosition == null || currentPosition.minY == 0) { - int topicId = messageObject.replyToForumTopic == null ? MessageObject.getTopicId(messageObject.messageOwner, true) : messageObject.replyToForumTopic.id; + long topicId = messageObject.replyToForumTopic == null ? MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true) : messageObject.replyToForumTopic.id; TLRPC.TL_forumTopic topic = messageObject.replyToForumTopic == null ? MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), topicId) : messageObject.replyToForumTopic; if (topic != null) { drawTopic = true; @@ -14522,6 +14941,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable && messageObject.replyMessageObject.messageOwner != null) { MediaDataController.addTextStyleRuns(messageObject.replyMessageObject.messageOwner.entities, messageObject.replyMessageObject.caption, (Spannable) stringFinalText); + stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageText != null && messageObject.replyMessageObject.messageText.length() > 0) { String mess = messageObject.replyMessageObject.messageText.toString(); @@ -14536,6 +14956,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable) { MediaDataController.addTextStyleRuns(messageObject.replyMessageObject, (Spannable) stringFinalText); + stringFinalText = TextUtils.ellipsize(stringFinalText, textPaint, maxWidth, TextUtils.TruncateAt.END); } } } else { @@ -14629,7 +15050,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate replyTextWidth -= sz; maxWidth += sz; } - if (!isReplyQuote && (currentMessageObject.shouldDrawWithoutBackground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) { + if (changed || !isReplyQuote && (currentMessageObject.shouldDrawWithoutBackground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) { stringFinalText = TextUtils.ellipsize(sb, textPaint, maxWidth, TextUtils.TruncateAt.END); } else { stringFinalText = sb; @@ -14683,7 +15104,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } else if (!isThreadChat && messageObject.getReplyMsgId() != 0 && !messageObject.isGiveawayResults()) { - if (!(messageObject.replyMessageObject != null && (messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate))) { + if (!(messageObject.replyMessageObject != null && (messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate)) && messageObject.getDialogId() != UserObject.REPLY_BOT) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += AndroidUtilities.dp(14 + 4) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); if (messageObject.type != MessageObject.TYPE_TEXT) { @@ -14926,12 +15347,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate @Override public int getBoundsLeft() { - return Math.max(0, getBackgroundDrawableLeft() - (needDrawAvatar() ? dp(currentPosition != null ? 73 : (currentMessageObject.isRepostPreview ? 42 : 63)) : 0)); + return Math.max(0, getBackgroundDrawableLeft() - (needDrawAvatar() ? dp(currentPosition != null ? 73 : (currentMessageObject != null && currentMessageObject.isRepostPreview ? 42 : 63)) : 0) - (currentMessageObject != null && currentMessageObject.isOutOwner() && (checkNeedDrawShareButton(currentMessageObject) || useTranscribeButton) ? dp(48) : 0)); } @Override public int getBoundsRight() { - return getBackgroundDrawableRight() + (checkNeedDrawShareButton(currentMessageObject) ? dp(48) : 0); + return getBackgroundDrawableRight() + (currentMessageObject != null && !currentMessageObject.isOutOwner() && (checkNeedDrawShareButton(currentMessageObject) || useTranscribeButton) ? dp(48) : 0); } @SuppressLint("WrongCall") @@ -15746,7 +16167,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawAnimatedEmojis(canvas, 1f); } - if (currentNameStatusDrawable != null && drawNameLayout && nameLayout != null) { + if (currentNameStatusDrawable != null && drawNameLayout && nameLayout != null && (currentPosition == null || currentPosition.minX == 0 && currentPosition.minY == 0) && !(currentMessageObject.deleted && !drawingToBitmap && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1)) { int color; float nameX, nameY; if (currentMessageObject.shouldDrawWithoutBackground()) { @@ -15976,6 +16397,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private void drawSideButton(Canvas canvas) { if (drawSideButton != 0) { + if (currentPosition != null && currentMessagesGroup != null && currentMessagesGroup.isDocuments && !currentPosition.last) { + return; + } if (currentMessageObject.isOutOwner()) { sideStartX = transitionParams.lastBackgroundLeft - AndroidUtilities.dp(8 + 32); if (currentMessagesGroup != null) { @@ -16036,17 +16460,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (drawSideButton == 2) { Drawable goIconDrawable = getThemedDrawable(Theme.key_drawable_goIcon); - if (currentMessageObject.isOutOwner()) { - setDrawableBounds(goIconDrawable, sideStartX + AndroidUtilities.dp(10), sideStartY + AndroidUtilities.dp(9)); - canvas.save(); - canvas.scale(-1, 1, goIconDrawable.getBounds().centerX(), goIconDrawable.getBounds().centerY()); - } else { - setDrawableBounds(goIconDrawable, sideStartX + AndroidUtilities.dp(12), sideStartY + AndroidUtilities.dp(9)); - } + setDrawableBounds(goIconDrawable, sideStartX + AndroidUtilities.dp(16) - goIconDrawable.getIntrinsicWidth() / 2f, sideStartY + AndroidUtilities.dp(16) - goIconDrawable.getIntrinsicHeight() / 2f); goIconDrawable.draw(canvas); - if (currentMessageObject.isOutOwner()) { - canvas.restore(); - } } else if (drawSideButton == 4) { final int scx = (int) (sideStartX + AndroidUtilities.dp(16)), scy = (int) (sideStartY + AndroidUtilities.dp(16)); Drawable drawable = getThemedDrawable(Theme.key_drawable_closeIcon); @@ -16112,10 +16527,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int right = backgroundWidth; if (isRoundVideo) { right -= (int) (getVideoTranscriptionProgress() * AndroidUtilities.dp(3)); - if (drawPinnedBottom && currentMessageObject.isOutOwner()) { + if (drawPinnedBottom && (currentMessageObject != null && currentMessageObject.isOutOwner())) { right -= AndroidUtilities.dp(6) * (1f - getVideoTranscriptionProgress()); } - if (drawPinnedBottom && !currentMessageObject.isOutOwner()) { + if (drawPinnedBottom && !(currentMessageObject != null && currentMessageObject.isOutOwner())) { right -= AndroidUtilities.dp(6) * (1f - getVideoTranscriptionProgress()); } return getBackgroundDrawableLeft() + right; @@ -16150,7 +16565,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate additionalBottom += AndroidUtilities.dp(3); } if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { - additionalBottom += AndroidUtilities.dp((currentMessageObject.isOutOwner() ? 3 : 4)); + additionalBottom += AndroidUtilities.dp((currentMessageObject != null && currentMessageObject.isOutOwner() ? 3 : 4)); } } @@ -17686,7 +18101,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (overideShouldDrawTimeOnMedia != 0) { return overideShouldDrawTimeOnMedia == 1; } - return mediaBackground && captionLayout == null && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall || currentMessageObject.isAnyKindOfSticker() || currentMessageObject.isRoundVideo())/* || isMedia && drawCommentButton && !isRepliesChat*/; + return mediaBackground && captionLayout == null && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall || currentMessageObject != null && (currentMessageObject.isAnyKindOfSticker() || currentMessageObject.isRoundVideo()))/* || isMedia && drawCommentButton && !isRepliesChat*/; } public void drawTime(Canvas canvas, float alpha, boolean fromParent) { @@ -17844,7 +18259,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } float x1 = timeX - AndroidUtilities.dp(bigRadius ? 6 : 4); float timeY; - if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && (currentMessageObject == null || !currentMessageObject.isRoundOnce())) { timeY = layoutHeight - (AndroidUtilities.dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } else { timeY = photoImage.getImageY2() + additionalTimeOffsetY; @@ -17853,7 +18268,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate float timeHeight = Math.max(AndroidUtilities.dp(17), Theme.chat_timePaint.getTextSize() + AndroidUtilities.dp(5)); rect.set(x1, y1, x1 + timeWidth + AndroidUtilities.dp((bigRadius ? 12 : 8) + (currentMessageObject.isOutOwner() ? 20 + (currentMessageObject.type == MessageObject.TYPE_EMOJIS ? 4 : 0) : 0)), y1 + timeHeight); - if (currentMessageObject.hasMediaSpoilers()) { + if (currentMessageObject.hasMediaSpoilers() && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO) { rectPath.rewind(); rectPath.addRoundRect(rect, r, r, Path.Direction.CW); canvas.save(); @@ -18494,7 +18909,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate alpha = alpha * progress; } float timeY; - if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && (currentMessageObject == null || !currentMessageObject.isRoundOnce())) { timeY = layoutHeight - (AndroidUtilities.dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()); } else { timeY = photoImage.getImageY2() + additionalTimeOffsetY; @@ -19370,77 +19785,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate updatePollAnimations(dt); canvas.restore(); } else if (currentMessageObject.type == MessageObject.TYPE_CONTACT) { - if (currentMessageObject.isOutOwner()) { - Theme.chat_contactNamePaint.setColor(getThemedColor(Theme.key_chat_outContactNameText)); - Theme.chat_contactPhonePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outContactPhoneSelectedText : Theme.key_chat_outContactPhoneText)); - } else { - Theme.chat_contactNamePaint.setColor(getThemedColor(Theme.key_chat_inContactNameText)); - Theme.chat_contactPhonePaint.setColor(getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inContactPhoneSelectedText : Theme.key_chat_inContactPhoneText)); - } - if (titleLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(16) + namesOffset); - titleLayout.draw(canvas); - canvas.restore(); - } - if (docTitleLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(39) + namesOffset); - docTitleLayout.draw(canvas); - canvas.restore(); - } - - if (!currentMessageObject.isRepostPreview) { - Drawable menuDrawable; - if (currentMessageObject.isOutOwner()) { - menuDrawable = getThemedDrawable(isDrawSelectionBackground() ? Theme.key_drawable_msgOutMenuSelected : Theme.key_drawable_msgOutMenu); - } else { - menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; - } - setDrawableBounds(menuDrawable, otherX = (int) (photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(48)), otherY = (int) (photoImage.getImageY() - AndroidUtilities.dp(2))); - menuDrawable.draw(canvas); - } - - if (drawInstantView) { - int textX = (int) (photoImage.getImageX() - AndroidUtilities.dp(2)); - int instantY = layoutHeight - AndroidUtilities.dp(36 + 30); - if (!reactionsLayoutInBubble.isEmpty && !reactionsLayoutInBubble.isSmall) { - instantY -= reactionsLayoutInBubble.totalHeight; - } - if (drawCommentButton) { - instantY -= AndroidUtilities.dp(shouldDrawTimeOnMedia() ? 39.3f : 41); - } - if (currentMessageObject.isOutOwner()) { - Theme.chat_instantViewPaint.setColor(getThemedColor(Theme.key_chat_outPreviewInstantText)); - Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_chat_outPreviewInstantText), .10f)); - } else { - Theme.chat_instantViewPaint.setColor(getThemedColor(Theme.key_chat_inPreviewInstantText)); - Theme.chat_instantViewButtonPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_chat_inPreviewInstantText), .10f)); - } - - instantButtonRect.set(textX, instantY, textX + instantWidth, instantY + AndroidUtilities.dp(36)); - float scale = instantButtonBounce.getScale(.02f); - boolean scaleRestore = scale != 1; - if (scaleRestore) { - canvas.save(); - canvas.scale(scale, scale, instantButtonRect.centerX(), instantButtonRect.centerY()); - } - if (Build.VERSION.SDK_INT >= 21) { - selectorDrawableMaskType[0] = 0; - selectorDrawable[0].setBounds(textX, instantY, textX + instantWidth, instantY + AndroidUtilities.dp(36)); - selectorDrawable[0].draw(canvas); - } - canvas.drawRoundRect(instantButtonRect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_instantViewButtonPaint); - if (instantViewLayout != null) { - canvas.save(); - canvas.translate(textX + instantTextX, instantY + AndroidUtilities.dp(10.5f)); - instantViewLayout.draw(canvas); - canvas.restore(); - } - if (scaleRestore) { - canvas.restore(); - } - } + drawContact(canvas); } if (drawImageButton && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isRepostVideoPreview) { @@ -19454,12 +19799,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean restore = false; boolean on = false; - if (currentMessageObject != null && currentMessageObject.isRoundVideo() && !currentMessageObject.mediaExists) { + if (currentMessageObject != null && currentMessageObject.isRoundVideo() && (!currentMessageObject.mediaExists || currentMessageObject.isRoundOnce())) { radialProgress.setProgressRect( - photoImage.getImageX() + (photoImage.getImageWidth() - radialProgress.getRadius()) / 2f, - photoImage.getImageY() + (photoImage.getImageHeight() - radialProgress.getRadius()) / 2f, - photoImage.getImageX() + (photoImage.getImageWidth() + radialProgress.getRadius()) / 2f, - photoImage.getImageY() + (photoImage.getImageHeight() + radialProgress.getRadius()) / 2f + photoImage.getImageX() + (photoImage.getImageWidth() / 2f - radialProgress.getRadius()), + photoImage.getImageY() + (photoImage.getImageHeight() / 2f - radialProgress.getRadius()), + photoImage.getImageX() + (photoImage.getImageWidth() / 2f + radialProgress.getRadius()), + photoImage.getImageY() + (photoImage.getImageHeight() / 2f + radialProgress.getRadius()) ); } else if (currentMessageObject != null && currentMessageObject.isRoundVideo()) { radialProgress.setProgressRect( @@ -19473,34 +19818,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.scale(scale, scale, radialProgress.getProgressRect().centerX(), radialProgress.getProgressRect().centerY()); restore = true; } - if ((!isRoundVideo || !hasLinkPreview) && (!currentMessageObject.needDrawBluredPreview() || !MediaController.getInstance().isPlayingMessage(currentMessageObject)) && !(currentMessageObject.hasMediaSpoilers() && (!currentMessageObject.isMediaSpoilersRevealed || !currentMessageObject.revealingMediaSpoilers) && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && currentMessagesGroup == null && (radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY || radialProgress.getIcon() == MediaActionDrawable.ICON_NONE))) { + if ( + (!isRoundVideo || !hasLinkPreview) && + (!currentMessageObject.needDrawBluredPreview() || !MediaController.getInstance().isPlayingMessage(currentMessageObject)) && + !(currentMessageObject.hasMediaSpoilers() && (!currentMessageObject.isMediaSpoilersRevealed || !currentMessageObject.revealingMediaSpoilers) && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && currentMessagesGroup == null && (radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY || radialProgress.getIcon() == MediaActionDrawable.ICON_NONE)) + ) { if (currentMessageObject.needDrawBluredPreview()) { radialProgress.overrideCircleAlpha = 0f; } else if (isRoundVideo && !on) { radialProgress.overrideCircleAlpha = .25f + .75f * (1f - getVideoTranscriptionProgress()); } - if ((!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { + if (!currentMessageObject.isRoundOnce() && (!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { canvas.saveLayerAlpha(radialProgress.getProgressRect(), (int) (mediaSpoilerRevealProgress * 0xFF), Canvas.ALL_SAVE_FLAG); } - if (currentMessageObject.needDrawBluredPreview()) { - rectPath.rewind(); - rectPath.addRoundRect(radialProgress.getProgressRect(), AndroidUtilities.dp(48), AndroidUtilities.dp(48), Path.Direction.CW); - canvas.save(); - canvas.clipPath(rectPath); - float wasAlpha = photoImage.getAlpha(); - photoImage.setAlpha(.5f * wasAlpha); - photoImage.draw(canvas); - photoImage.setAlpha(wasAlpha); - canvas.restore(); - Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); - int oldAlpha2 = dimPaint.getAlpha(); - dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); - canvas.drawRoundRect(radialProgress.getProgressRect(), AndroidUtilities.dp(48), AndroidUtilities.dp(48), dimPaint); - dimPaint.setAlpha(oldAlpha2); - } - radialProgress.iconScale = 1f; - radialProgress.draw(canvas); - if ((!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { + drawRadialProgress(canvas); + if (!currentMessageObject.isRoundOnce() && (!SharedConfig.isAutoplayVideo() || currentMessagesGroup != null) && currentMessageObject.hasMediaSpoilers() && !currentMessageObject.isMediaSpoilersRevealed && radialProgress.getIcon() == MediaActionDrawable.ICON_PLAY) { canvas.restore(); } if (currentMessageObject.needDrawBluredPreview() || isRoundVideo && !on) { @@ -19566,8 +19898,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - x1 = backgroundDrawableLeft + transitionParams.deltaLeft + (!currentMessageObject.isOutOwner() && !drawPinnedBottom && drawBackground ? AndroidUtilities.dp(6) : 0) + AndroidUtilities.dp(8) + roundPlayingDrawableProgress + offsetX; - y1 = layoutHeight - AndroidUtilities.dp(28 - (drawPinnedBottom ? 2 : 0)); + if (currentMessageObject != null && currentMessageObject.isRoundOnce()) { + x1 = photoImage.getImageX(); + y1 = photoImage.getImageY2() - (AndroidUtilities.dp(drawPinnedBottom ? 4 : 5) + reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress)) * (1f - getVideoTranscriptionProgress()) - AndroidUtilities.dp(17); + } else { + x1 = backgroundDrawableLeft + transitionParams.deltaLeft + (!currentMessageObject.isOutOwner() && !drawPinnedBottom && drawBackground ? AndroidUtilities.dp(6) : 0) + AndroidUtilities.dp(8) + roundPlayingDrawableProgress + offsetX; + y1 = layoutHeight - AndroidUtilities.dp(28 - (drawPinnedBottom ? 2 : 0)); + } if (!reactionsLayoutInBubble.isEmpty) { y1 -= reactionsLayoutInBubble.totalHeight; } @@ -19652,8 +19989,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate x1 += AndroidUtilities.dp(4); y1 += AndroidUtilities.dp(1.7f); } else { - x1 = backgroundDrawableLeft + AndroidUtilities.dp(currentMessageObject.isOutOwner() || drawPinnedBottom ? 12 : 18); - y1 = layoutHeight - AndroidUtilities.dp(6.3f - (drawPinnedBottom ? 2 : 0)) - timeLayout.getHeight(); + x1 = photoImage.getImageX(); + y1 = photoImage.getImageY2() - (durationLayout != null ? durationLayout.getHeight() : 0); } if (durationLayout != null) { @@ -19667,6 +20004,80 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private Paint clipPaint; + protected float radialProgressAlpha = 1f; + protected void drawRadialProgress(Canvas canvas) { + final boolean withPeriod = currentMessageObject.isRoundOnce(); + if (withPeriod) { + AndroidUtilities.rectTmp.set(radialProgress.getProgressRect()); + AndroidUtilities.rectTmp.inset(-dp(15), -dp(15)); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * radialProgressAlpha), Canvas.ALL_SAVE_FLAG); + } + + if (currentMessageObject.needDrawBluredPreview()) { + drawPhotoBlurRect(canvas, radialProgress.getProgressRect()); + } + radialProgress.iconScale = 1f; + radialProgress.draw(canvas); + + if (withPeriod) { + canvas.save(); + drawPhotoBlurRect(canvas, getRadialProgress().getProgressRect()); + getRadialProgress().draw(canvas); + + RectF pr = getRadialProgress().getProgressRect(); + final float cx = pr.centerX() + dp(18); + final float cy = pr.centerY() + dp(18); + final float r = dp(10), cr = r + dp(1.33f); + + if (clipPaint == null) { + clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + canvas.drawCircle(cx, cy, cr, clipPaint); + + AndroidUtilities.rectTmp.set(cx - r, cy - r, cx + r, cy + r); + drawPhotoBlurRect(canvas, AndroidUtilities.rectTmp); + + if (oncePeriod == null) { + oncePeriod = new CaptionContainerView.PeriodDrawable(3); + oncePeriod.updateColors(0xffffffff, 0, 0); + oncePeriod.diameterDp = 14; + oncePeriod.setTextSize(10); + oncePeriod.strokePaint.setStrokeWidth(dpf2(1.5f)); + oncePeriod.setValue(1, false, false); + oncePeriod.textOffsetX = -dpf2(.33f); + oncePeriod.textOffsetY = dpf2(.33f); + } + oncePeriod.diameterDp = 14; + oncePeriod.setTextSize(10); + oncePeriod.setClear(false); + oncePeriod.setCenterXY(cx, cy); + oncePeriod.draw(canvas, 1f); + + canvas.restore(); + + canvas.restore(); + } + } + + protected void drawPhotoBlurRect(Canvas canvas, RectF rect) { + rectPath.rewind(); + rectPath.addRoundRect(rect, rect.width() / 2f, rect.height() / 2f, Path.Direction.CW); + canvas.save(); + canvas.clipPath(rectPath); + float wasAlpha = photoImage.getAlpha(); + photoImage.setAlpha((currentMessageObject.isRoundOnce() ? 1f : .5f) * wasAlpha); + photoImage.draw(canvas); + photoImage.setAlpha(wasAlpha); + canvas.restore(); + Paint dimPaint = getThemedPaint(Theme.key_paint_chatTimeBackground); + int oldAlpha2 = dimPaint.getAlpha(); + dimPaint.setAlpha((int) (oldAlpha2 * controlsAlpha * .4f)); + canvas.drawRoundRect(rect, rect.width() / 2f, rect.height() / 2f, dimPaint); + dimPaint.setAlpha(oldAlpha2); + } + @Override public int getObserverTag() { return TAG; @@ -20059,6 +20470,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public static final int POLL_HINT = 495; public static final int FORWARD = 494; public static final int TRANSCRIBE = 493; + public static final int CONTACT = 492; + public static final int CONTACT_VIEW = 491; + public static final int CONTACT_ADD = 490; + public static final int CONTACT_MESSAGE = 489; private Path linkPath = new Path(); private RectF rectF = new RectF(); private Rect rect = new Rect(); @@ -20377,6 +20792,22 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (drawInstantView && !instantButtonRect.isEmpty()) { info.addChild(ChatMessageCell.this, INSTANT_VIEW); } + if (drawContact && !contactRect.isEmpty()) { + info.addChild(ChatMessageCell.this, CONTACT); + if (contactButtons != null && contactButtons.size() > 1) { + for (InstantViewButton instantViewButton : contactButtons) { + if (drawContactView && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_VIEW && !instantViewButton.rect.isEmpty()) { + info.addChild(ChatMessageCell.this, CONTACT_VIEW); + } + if (drawContactAdd && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_ADD && !instantViewButton.rect.isEmpty()) { + info.addChild(ChatMessageCell.this, CONTACT_ADD); + } + if (drawContactSendMessage && instantViewButton.type == INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE && !instantViewButton.rect.isEmpty()) { + info.addChild(ChatMessageCell.this, CONTACT_MESSAGE); + } + } + } + } if (commentLayout != null) { info.addChild(ChatMessageCell.this, COMMENT); } @@ -20578,6 +21009,56 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate rect.offset(pos[0], pos[1]); info.setBoundsInScreen(rect); info.setClickable(true); + } else if (virtualViewId == CONTACT) { + info.setClassName("android.widget.Button"); + info.setEnabled(true); + if (titleLayout != null) { + info.setText(titleLayout.getText()); + } + info.addAction(AccessibilityNodeInfo.ACTION_CLICK); + contactRect.round(rect); + if (contactButtons != null && contactButtons.size() > 1) { + InstantViewButton instantViewButton = contactButtons.get(0); + if (!instantViewButton.rect.isEmpty()) { + rect.set(rect.left, rect.top, rect.right, (int) (rect.bottom - instantViewButton.rect.height())); + } + } + info.setBoundsInParent(rect); + if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { + accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); + } + rect.offset(pos[0], pos[1]); + info.setBoundsInScreen(rect); + info.setClickable(true); + } else if (virtualViewId == CONTACT_VIEW || virtualViewId == CONTACT_ADD || virtualViewId == CONTACT_MESSAGE) { + int requiredType; + if (virtualViewId == CONTACT_VIEW) { + requiredType = INSTANT_BUTTON_TYPE_CONTACT_VIEW; + } else if (virtualViewId == CONTACT_ADD) { + requiredType = INSTANT_BUTTON_TYPE_CONTACT_ADD; + } else { + requiredType = INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE; + } + for (int i = 0; i < contactButtons.size(); i++) { + InstantViewButton instantViewButton = contactButtons.get(i); + if (instantViewButton.type == requiredType) { + info.setClassName("android.widget.Button"); + info.setEnabled(true); + if (instantViewButton.layout != null) { + info.setText(instantViewButton.layout.getText()); + } + info.addAction(AccessibilityNodeInfo.ACTION_CLICK); + instantViewButton.rect.round(rect); + info.setBoundsInParent(rect); + if (accessibilityVirtualViewBounds.get(virtualViewId) == null || !accessibilityVirtualViewBounds.get(virtualViewId).equals(rect)) { + accessibilityVirtualViewBounds.put(virtualViewId, new Rect(rect)); + } + rect.offset(pos[0], pos[1]); + info.setBoundsInScreen(rect); + info.setClickable(true); + break; + } + } } else if (virtualViewId == SHARE) { info.setClassName("android.widget.ImageButton"); info.setEnabled(true); @@ -20740,6 +21221,22 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (delegate != null) { delegate.didPressInstantButton(ChatMessageCell.this, drawInstantViewType); } + } else if (virtualViewId == CONTACT) { + if (delegate != null) { + delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); + } + } else if (virtualViewId == CONTACT_VIEW) { + if (delegate != null) { + delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_VIEW); + } + } else if (virtualViewId == CONTACT_ADD) { + if (delegate != null) { + delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_ADD); + } + } else if (virtualViewId == CONTACT_MESSAGE) { + if (delegate != null) { + delegate.didPressInstantButton(ChatMessageCell.this, INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE); + } } else if (virtualViewId == SHARE) { if (delegate != null) { delegate.didPressSideButton(ChatMessageCell.this); @@ -20810,6 +21307,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + public void setImageCoords(RectF rect) { + setImageCoords(rect.left, rect.top, rect.width(), rect.height()); + } + public void setImageCoords(float x, float y, float w, float h) { photoImage.setImageCoords(x, y, w, h); if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { @@ -21118,7 +21619,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentBackgroundDrawable != null) { lastDrawingBackgroundRect.set(currentBackgroundDrawable.getBounds()); } - lastDrawingTextBlocks = currentMessageObject.textLayoutBlocks; + lastDrawingTextBlocks = currentMessageObject != null ? currentMessageObject.textLayoutBlocks : null; lastDrawingEdited = edited; lastDrawingCaptionX = captionX; @@ -21180,7 +21681,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastDrawnForwardedNameLayout[0] = forwardedNameLayout[0]; lastDrawnForwardedNameLayout[1] = forwardedNameLayout[1]; - lastDrawnForwardedName = currentMessageObject.needDrawForwarded(); + lastDrawnForwardedName = currentMessageObject != null && currentMessageObject.needDrawForwarded(); lastForwardNameX = forwardNameX; lastForwardedNamesOffset = namesOffset; lastForwardNameWidth = forwardedNameWidth; @@ -21188,7 +21689,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentBackgroundDrawable != null) { lastBackgroundRight = currentBackgroundDrawable.getBounds().right; } - lastTextXOffset = currentMessageObject.textXOffset; + lastTextXOffset = currentMessageObject != null ? currentMessageObject.textXOffset : 0; lastDrawingReplyTextHeight = replyTextHeight; lastDrawnReplyTextLayout = replyTextLayout; @@ -21702,7 +22203,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public boolean needDrawAvatar() { - return isChat && !isThreadPost && currentMessageObject != null && !currentMessageObject.isOutOwner() && currentMessageObject.needDrawAvatar() || currentMessageObject != null && currentMessageObject.forceAvatar; + return isChat && !isSavedPreviewChat && !isThreadPost && currentMessageObject != null && !currentMessageObject.isOutOwner() && currentMessageObject.needDrawAvatar() || currentMessageObject != null && currentMessageObject.forceAvatar; } protected boolean drawPhotoImage(Canvas canvas) { 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 d6d2bc29d..c52f1c644 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -68,6 +70,7 @@ import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; @@ -81,6 +84,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DialogsAdapter; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BubbleCounterPath; import org.telegram.ui.Components.CanvasButton; @@ -166,6 +170,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava private Paint timerPaint; private Paint timerPaint2; SharedResources sharedResources; + public boolean isSavedDialog; public final StoriesUtilities.AvatarStoryParams storyParams = new StoriesUtilities.AvatarStoryParams(false) { @Override @@ -399,6 +404,13 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava private int printingStringType; private TLRPC.DraftMessage draftMessage; + private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean premiumBlocked; + + public boolean isBlocked() { + return premiumBlocked; + } + protected CheckBox2 checkBox; public boolean useForceThreeLines; @@ -596,6 +608,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava currentDialogFolderId = 0; } dialogsType = type; + showPremiumBlocked(dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD); folderId = folder; messageId = 0; if (update(0, false)) { @@ -1469,7 +1482,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava messageString = message.messageText; } if (message.topicIconDrawable[0] instanceof ForumBubbleDrawable) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(message.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(currentAccount, message.messageOwner, true)); if (topic != null) { ((ForumBubbleDrawable) message.topicIconDrawable[0]).setColor(topic.icon_color); } @@ -1621,7 +1634,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } } - if (message.isForwarded()) { + if (message.isForwarded() && message.needDrawForwarded()) { drawForwardIcon = true; SpannableStringBuilder builder = new SpannableStringBuilder(messageString); builder.insert(0, "d "); @@ -1647,10 +1660,10 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava timeString = LocaleController.stringForMessageListDate(message.messageOwner.date); } - if (message == null) { + if (message == null || isSavedDialog) { drawCheck1 = false; drawCheck2 = false; - drawClock = false; + drawClock = message != null && message.isSending() && currentDialogId == UserConfig.getInstance(currentAccount).getClientUserId(); drawCount = false; drawMention = false; drawReactionMention = false; @@ -1775,8 +1788,12 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } else if (user != null) { if (UserObject.isReplyUser(user)) { nameString = LocaleController.getString("RepliesTitle", R.string.RepliesTitle); + } else if (UserObject.isAnonymous(user)) { + nameString = LocaleController.getString(R.string.AnonymousForward); } else if (UserObject.isUserSelf(user)) { - if (useMeForMyMessages) { + if (isSavedDialog) { + nameString = LocaleController.getString(R.string.MyNotes); + } else if (useMeForMyMessages) { nameString = LocaleController.getString("FromYou", R.string.FromYou); } else { if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { @@ -2918,6 +2935,12 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); + } else if (UserObject.isAnonymous(user)) { + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_ANONYMOUS); + avatarImage.setImage(null, null, avatarDrawable, null, user, 0); + } else if (UserObject.isUserSelf(user) && isSavedDialog) { + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_MY_NOTES); + avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else if (UserObject.isUserSelf(user) && !useMeForMyMessages) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); @@ -3050,6 +3073,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava updateLayout = true; } } + updatePremiumBlocked(animated); return requestLayout; } @@ -3568,7 +3592,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava }); } - if (lastTopicMessageUnread && topMessageTopicEndIndex != topMessageTopicStartIndex) { + if (lastTopicMessageUnread && topMessageTopicEndIndex != topMessageTopicStartIndex && (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_7 || dialogsType == DialogsActivity.DIALOGS_TYPE_8)) { canvasButton.setColor(ColorUtils.setAlphaComponent(currentMessagePaint.getColor(), Theme.isCurrentThemeDark() ? 36 : 26)); if (!buttonCreated) { canvasButton.rewind(); @@ -4021,8 +4045,39 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } + private PremiumGradient.PremiumGradientTools premiumGradient; + private Drawable lockDrawable; + public boolean drawAvatarOverlays(Canvas canvas) { boolean needInvalidate = false; + float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + float top = avatarImage.getCenterY() + dp(18); + float left = avatarImage.getCenterX() + dp(18); + + canvas.save(); + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + canvas.drawCircle(left, top, dp(10 + 1.33f) * lockT, Theme.dialogs_onlineCirclePaint); + if (premiumGradient == null) { + premiumGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + premiumGradient.gradientMatrix((int) (left - dp(10)), (int) (top - dp(10)), (int) (left + dp(10)), (int) (top + dp(10)), 0, 0); + canvas.drawCircle(left, top, dp(10) * lockT, premiumGradient.paint); + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (left - lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top - lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT), + (int) (left + lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top + lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT) + ); + lockDrawable.setAlpha((int) (0xFF * lockT)); + lockDrawable.draw(canvas); + canvas.restore(); + return false; + } if (isDialogCell && currentDialogFolderId == 0) { showTtl = ttlPeriod > 0 && !isOnline() && !hasCall; if (rightFragmentOpenedProgress != 1f && (showTtl || ttlProgress > 0)) { @@ -4534,6 +4589,8 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } else if (user != null) { if (UserObject.isReplyUser(user)) { sb.append(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); + } else if (UserObject.isAnonymous(user)) { + sb.append(LocaleController.getString(R.string.AnonymousForward)); } else { if (user.bot) { sb.append(LocaleController.getString("Bot", R.string.Bot)); @@ -4740,6 +4797,12 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava TLRPC.User fromUser = null; TLRPC.Chat fromChat = null; long fromId = message.getFromChatId(); + if (isSavedDialog && message.messageOwner != null && message.messageOwner.fwd_from != null) { + fromId = DialogObject.getPeerDialogId(message.messageOwner.fwd_from.saved_from_id); + if (fromId == 0) { + fromId = DialogObject.getPeerDialogId(message.messageOwner.fwd_from.from_id); + } + } if (DialogObject.isUserDialog(fromId)) { fromUser = MessagesController.getInstance(currentAccount).getUser(fromId); } else { @@ -4748,7 +4811,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava if (message.isOutOwner()) { return LocaleController.getString("FromYou", R.string.FromYou); - } else if (message != null && message.messageOwner != null && message.messageOwner.from_id instanceof TLRPC.TL_peerUser && (user = MessagesController.getInstance(currentAccount).getUser(message.messageOwner.from_id.user_id)) != null) { + } else if (!isSavedDialog && message != null && message.messageOwner != null && message.messageOwner.from_id instanceof TLRPC.TL_peerUser && (user = MessagesController.getInstance(currentAccount).getUser(message.messageOwner.from_id.user_id)) != null) { return UserObject.getFirstName(user).replace("\n", ""); } else if (message != null && message.messageOwner != null && message.messageOwner.fwd_from != null && message.messageOwner.fwd_from.from_name != null) { return message.messageOwner.fwd_from.from_name; @@ -4786,7 +4849,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava if (MessageObject.isTopicActionMessage(message)) { stringBuilder = formatInternal(messageFormatType, mess, messageNameString); if (message.topicIconDrawable[0] instanceof ForumBubbleDrawable) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(message.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(currentAccount, message.messageOwner, true)); if (topic != null) { ((ForumBubbleDrawable) message.topicIconDrawable[0]).setColor(topic.icon_color); } @@ -4957,7 +5020,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava return true; } if (delegate == null || delegate.canClickButtonInside()) { - if (lastTopicMessageUnread && canvasButton != null && buttonLayout != null && canvasButton.checkTouchEvent(event)) { + if (lastTopicMessageUnread && canvasButton != null && buttonLayout != null && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && canvasButton.checkTouchEvent(event)) { return true; } } @@ -5193,10 +5256,10 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava topics = new ArrayList<>(topics); Collections.sort(topics, Comparator.comparingInt(o -> -o.top_message)); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); - int topMessageTopicId = 0; + long topMessageTopicId = 0; int boldLen = 0; if (message != null) { - topMessageTopicId = MessageObject.getTopicId(message.messageOwner, true); + topMessageTopicId = MessageObject.getTopicId(currentAccount, message.messageOwner, true); TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(chat.id, topMessageTopicId); if (topic != null) { CharSequence topicString = ForumUtilities.getTopicSpannedName(topic, currentMessagePaint, false); @@ -5272,4 +5335,29 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } return adaptiveEmojiColorFilter[n]; } + + private Runnable unsubscribePremiumBlocked; + public void showPremiumBlocked(boolean show) { + if (show != (unsubscribePremiumBlocked != null)) { + if (!show && unsubscribePremiumBlocked != null) { + unsubscribePremiumBlocked.run(); + unsubscribePremiumBlocked = null; + } else if (show) { + unsubscribePremiumBlocked = NotificationCenter.getInstance(currentAccount).listen(this, NotificationCenter.userIsPremiumBlockedUpadted, args -> { + updatePremiumBlocked(true); + }); + } + } + } + + private void updatePremiumBlocked(boolean animated) { + final boolean wasPremiumBlocked = premiumBlocked; + premiumBlocked = (unsubscribePremiumBlocked != null) && user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(user.id); + if (wasPremiumBlocked != premiumBlocked) { + if (!animated) { + premiumBlockedT.set(premiumBlocked, true); + } + invalidate(); + } + } } 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 53b5ccfb3..d3736c617 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -8,12 +8,18 @@ package org.telegram.ui.Cells; +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.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.view.Gravity; import android.view.accessibility.AccessibilityNodeInfo; @@ -33,11 +39,13 @@ 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.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumGradient; public class GroupCreateUserCell extends FrameLayout { @@ -71,6 +79,34 @@ public class GroupCreateUserCell extends FrameLayout { private boolean showSelfAsSaved; Theme.ResourcesProvider resourcesProvider; + private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean premiumBlocked; + private boolean showPremiumBlocked; + + public boolean isBlocked() { + return premiumBlocked; + } + + public GroupCreateUserCell showPremiumBlocked() { + if (showPremiumBlocked) return this; + showPremiumBlocked = true; + NotificationCenter.getInstance(currentAccount).listen(this, NotificationCenter.userIsPremiumBlockedUpadted, args -> { + updatePremiumBlocked(true); + }); + return this; + } + + private void updatePremiumBlocked(boolean animated) { + final boolean wasPremiumBlocked = premiumBlocked; + premiumBlocked = showPremiumBlocked && currentObject instanceof TLRPC.User && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(((TLRPC.User) currentObject).id); + if (wasPremiumBlocked != premiumBlocked) { + if (!animated) { + premiumBlockedT.set(premiumBlocked, true); + } + invalidate(); + } + } + public GroupCreateUserCell(Context context, int checkBoxType, int pad, boolean selfAsSaved) { this(context, checkBoxType, pad, selfAsSaved, false, null); } @@ -414,19 +450,26 @@ public class GroupCreateUserCell extends FrameLayout { } } - avatarImageView.setRoundRadius(currentChat != null && currentChat.forum ? AndroidUtilities.dp(14) : AndroidUtilities.dp(24)); if (currentStatus != null) { statusTextView.setText(currentStatus, true); statusTextView.setTag(Theme.key_windowBackgroundWhiteGrayText); statusTextView.setTextColor(Theme.getColor(forceDarkTheme ? Theme.key_voipgroup_lastSeenText : Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); } + + updatePremiumBlocked(false); } + private PremiumGradient.PremiumGradientTools premiumGradient; + private Drawable lockDrawable; + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (checkBoxType == 2 && (isChecked || checkProgress > 0.0f)) { + float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + + } else if (checkBoxType == 2 && (isChecked || checkProgress > 0.0f)) { paint.setColor(Theme.getColor(Theme.key_checkboxSquareBackground, resourcesProvider)); float cx = avatarImageView.getLeft() + avatarImageView.getMeasuredWidth() / 2; float cy = avatarImageView.getTop() + avatarImageView.getMeasuredHeight() / 2; @@ -444,6 +487,39 @@ public class GroupCreateUserCell extends FrameLayout { } } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + float top = avatarImageView.getY() + avatarImageView.getHeight() / 2f + dp(18); + float left = avatarImageView.getX() + avatarImageView.getWidth() / 2f + dp(18); + + canvas.save(); + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + canvas.drawCircle(left, top, dp(10 + 1.33f) * lockT, Theme.dialogs_onlineCirclePaint); + if (premiumGradient == null) { + premiumGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + premiumGradient.gradientMatrix((int) (left - dp(10)), (int) (top - dp(10)), (int) (left + dp(10)), (int) (top + dp(10)), 0, 0); + canvas.drawCircle(left, top, dp(10) * lockT, premiumGradient.paint); + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (left - lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top - lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT), + (int) (left + lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top + lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT) + ); + lockDrawable.setAlpha((int) (0xFF * lockT)); + lockDrawable.draw(canvas); + canvas.restore(); + } + } + @Override public boolean hasOverlappingRendering() { return false; 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 280caf3af..f0a54875c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java @@ -8,9 +8,15 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -23,16 +29,20 @@ import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; 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.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.CounterView; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumGradient; public class HintDialogCell extends FrameLayout { @@ -54,6 +64,14 @@ public class HintDialogCell extends FrameLayout { CheckBox2 checkBox; private final boolean drawCheckbox; + private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean showPremiumBlocked; + private boolean premiumBlocked; + + public boolean isBlocked() { + return premiumBlocked; + } + public HintDialogCell(Context context, boolean drawCheckbox, Theme.ResourcesProvider resourcesProvider) { super(context); this.drawCheckbox = drawCheckbox; @@ -100,6 +118,25 @@ public class HintDialogCell extends FrameLayout { } } + public void showPremiumBlocked() { + if (showPremiumBlocked) return; + showPremiumBlocked = true; + NotificationCenter.getInstance(currentAccount).listen(this, NotificationCenter.userIsPremiumBlockedUpadted, args -> { + updatePremiumBlocked(true); + }); + } + + private void updatePremiumBlocked(boolean animated) { + final boolean wasPremiumBlocked =premiumBlocked; + premiumBlocked = showPremiumBlocked && currentUser != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(currentUser.id); + if (wasPremiumBlocked != premiumBlocked) { + if (!animated) { + premiumBlockedT.set(premiumBlocked, true); + } + invalidate(); + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(86), MeasureSpec.EXACTLY)); @@ -138,6 +175,7 @@ public class HintDialogCell extends FrameLayout { avatarDrawable.setInfo(currentAccount, chat); currentUser = null; } + updatePremiumBlocked(true); } public void setColors(int textColorKey, int backgroundColorKey) { @@ -176,6 +214,7 @@ public class HintDialogCell extends FrameLayout { currentUser = null; imageView.setForUserOrChat(chat, avatarDrawable); } + updatePremiumBlocked(false); if (counter) { update(0); } @@ -183,11 +222,14 @@ public class HintDialogCell extends FrameLayout { private int backgroundColorKey = Theme.key_windowBackgroundWhite; + private PremiumGradient.PremiumGradientTools premiumGradient; + private Drawable lockDrawable; + @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result = super.drawChild(canvas, child, drawingTime); if (child == imageView) { - boolean showOnline = currentUser != null && !currentUser.bot && (currentUser.status != null && currentUser.status.expires > ConnectionsManager.getInstance(currentAccount).getCurrentTime() || MessagesController.getInstance(currentAccount).onlinePrivacy.containsKey(currentUser.id)); + boolean showOnline = !premiumBlocked && currentUser != null && !currentUser.bot && (currentUser.status != null && currentUser.status.expires > ConnectionsManager.getInstance(currentAccount).getCurrentTime() || MessagesController.getInstance(currentAccount).onlinePrivacy.containsKey(currentUser.id)); if (!wasDraw) { showOnlineProgress = showOnline ? 1f : 0f; } @@ -204,7 +246,34 @@ public class HintDialogCell extends FrameLayout { } invalidate(); } - if (showOnlineProgress != 0) { + + final float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + float top = child.getY() + child.getHeight() / 2f + dp(18); + float left = child.getX() + child.getWidth() / 2f + dp(18); + + canvas.save(); + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(backgroundColorKey, resourcesProvider)); + canvas.drawCircle(left, top, dp(10 + 1.33f) * lockT, Theme.dialogs_onlineCirclePaint); + if (premiumGradient == null) { + premiumGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + premiumGradient.gradientMatrix((int) (left - dp(10)), (int) (top - dp(10)), (int) (left + dp(10)), (int) (top + dp(10)), 0, 0); + canvas.drawCircle(left, top, dp(10) * lockT, premiumGradient.paint); + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (left - lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top - lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT), + (int) (left + lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top + lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT) + ); + lockDrawable.setAlpha((int) (0xFF * lockT)); + lockDrawable.draw(canvas); + canvas.restore(); + } else if (showOnlineProgress != 0) { int top = AndroidUtilities.dp(53); int left = AndroidUtilities.dp(59); canvas.save(); 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 fe844a1e9..a7d995bc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -8,9 +8,14 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.text.Layout; @@ -40,10 +45,12 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.CanvasButton; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.NotificationsSettingsActivity; @@ -101,6 +108,10 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No private boolean drawCheck; private boolean drawPremium; + private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean showPremiumBlocked; + private boolean premiumBlocked; + private int statusLeft; private StaticLayout statusLayout; private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable statusDrawable; @@ -132,6 +143,11 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No statusDrawable.setCallback(this); } + public ProfileSearchCell showPremiumBlock(boolean show) { + showPremiumBlocked = show; + return this; + } + private boolean customPaints; private TextPaint namePaint, statusPaint; public ProfileSearchCell useCustomPaints() { @@ -150,14 +166,17 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No user = (TLRPC.User) object; chat = null; contact = null; + premiumBlocked = showPremiumBlocked && user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(user.id); } else if (object instanceof TLRPC.Chat) { chat = (TLRPC.Chat) object; user = null; contact = null; + premiumBlocked = false; } else if (object instanceof ContactsController.Contact) { contact = (ContactsController.Contact) object; chat = null; user = null; + premiumBlocked = showPremiumBlocked && contact != null && contact.user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(contact.user.id); } encryptedChat = ec; subLabel = s; @@ -235,6 +254,9 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No super.onDetachedFromWindow(); avatarImage.onDetachedFromWindow(); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); + if (showPremiumBlocked) { + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); + } statusDrawable.detach(); } @@ -243,6 +265,9 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No super.onAttachedToWindow(); avatarImage.onAttachedToWindow(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); + if (showPremiumBlocked) { + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); + } statusDrawable.attach(); } @@ -250,6 +275,12 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.emojiLoaded) { invalidate(); + } else if (id == NotificationCenter.userIsPremiumBlockedUpadted) { + final boolean wasPremiumBlocked = premiumBlocked; + premiumBlocked = showPremiumBlocked && (user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(user.id) || contact != null && contact.user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(contact.user.id)); + if (premiumBlocked != wasPremiumBlocked) { + invalidate(); + } } } @@ -709,6 +740,9 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No postInvalidate(); } + private PremiumGradient.PremiumGradientTools premiumGradient; + private Drawable lockDrawable; + @Override protected void onDraw(Canvas canvas) { if (user == null && chat == null && encryptedChat == null && contact == null) { @@ -786,6 +820,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No actionLayout.draw(canvas); canvas.restore(); } + if (user != null) { StoriesUtilities.drawAvatarWithStory(user.id, canvas, avatarImage, avatarStoryParams); } else if (chat != null) { @@ -794,6 +829,38 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No avatarImage.setImageCoords(avatarStoryParams.originalAvatarRect); avatarImage.draw(canvas); } + + final float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + float top = avatarImage.getCenterY() + dp(14); + float left = avatarImage.getCenterX() + dp(16); + + canvas.save(); + Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + canvas.drawCircle(left, top, dp(10 + 1.33f) * lockT, Theme.dialogs_onlineCirclePaint); + if (premiumGradient == null) { + premiumGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + premiumGradient.gradientMatrix((int) (left - dp(10)), (int) (top - dp(10)), (int) (left + dp(10)), (int) (top + dp(10)), 0, 0); + canvas.drawCircle(left, top, dp(10) * lockT, premiumGradient.paint); + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (left - lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top - lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT), + (int) (left + lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top + lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT) + ); + lockDrawable.setAlpha((int) (0xFF * lockT)); + lockDrawable.draw(canvas); + canvas.restore(); + } + } + + public boolean isBlocked() { + return premiumBlocked; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java index f99c37a3f..70f5b0c5c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java @@ -12,6 +12,7 @@ import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -75,6 +76,10 @@ public class RadioCell extends FrameLayout { addView(radioButton, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, (LocaleController.isRTL ? padding + 1 : 0), 14, (LocaleController.isRTL ? 0 : padding + 1), 0)); } + public void setRadioIcon(Drawable icon) { + radioButton.setIcon(icon); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(50) + (needDivider ? 1 : 0)); 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 f7dd2b022..d0dbf4a52 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -10,6 +10,7 @@ package org.telegram.ui.Cells; import static org.telegram.messenger.AndroidUtilities.dp; +import android.app.Notification; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -51,14 +52,17 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RLottieDrawable; -public class ShareDialogCell extends FrameLayout { +public class ShareDialogCell extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { private final BackupImageView imageView; private final TextView nameTextView; @@ -88,6 +92,13 @@ public class ShareDialogCell extends FrameLayout { public static final int TYPE_CALL = 1; public static final int TYPE_CREATE = 2; + private final AnimatedFloat premiumBlockedT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean premiumBlocked; + + public boolean isBlocked() { + return premiumBlocked; + } + public BackupImageView getImageView() { return imageView; } @@ -115,7 +126,7 @@ public class ShareDialogCell extends FrameLayout { } }; NotificationCenter.listenEmojiLoading(nameTextView); - nameTextView.setTextColor(getThemedColor(type == TYPE_CALL ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); + nameTextView.setTextColor(getThemedColor(premiumBlocked ? Theme.key_windowBackgroundWhiteGrayText5 : currentType == TYPE_CALL ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); nameTextView.setMaxLines(2); nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); @@ -146,6 +157,30 @@ public class ShareDialogCell extends FrameLayout { setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), dp(2), dp(2))); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.userIsPremiumBlockedUpadted) { + final boolean wasPremiumBlocked = premiumBlocked; + premiumBlocked = user != null && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(user.id); + nameTextView.setTextColor(getThemedColor(premiumBlocked ? Theme.key_windowBackgroundWhiteGrayText5 : currentType == TYPE_CALL ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); + if (premiumBlocked != wasPremiumBlocked) { + invalidate(); + } + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); @@ -164,6 +199,10 @@ public class ShareDialogCell extends FrameLayout { imageView.setImage(null, null, repostStoryDrawable, null); } else if (DialogObject.isUserDialog(uid)) { user = MessagesController.getInstance(currentAccount).getUser(uid); + premiumBlocked = MessagesController.getInstance(currentAccount).isUserPremiumBlocked(uid); + nameTextView.setTextColor(getThemedColor(premiumBlocked ? Theme.key_windowBackgroundWhiteGrayText5 : currentType == TYPE_CALL ? Theme.key_voipgroup_nameText : Theme.key_dialogTextBlack)); + premiumBlockedT.set(premiumBlocked, true); + invalidate(); avatarDrawable.setInfo(currentAccount, user); if (currentType != TYPE_CREATE && UserObject.isReplyUser(user)) { nameTextView.setText(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); @@ -186,6 +225,8 @@ public class ShareDialogCell extends FrameLayout { imageView.setRoundRadius(dp(28)); } else { user = null; + premiumBlocked = false; + premiumBlockedT.set(0, true); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); if (name != null) { nameTextView.setText(name); @@ -263,6 +304,9 @@ public class ShareDialogCell extends FrameLayout { } } + private PremiumGradient.PremiumGradientTools premiumGradient; + private Drawable lockDrawable; + @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result = super.drawChild(canvas, child, drawingTime); @@ -275,31 +319,59 @@ public class ShareDialogCell extends FrameLayout { } lastUpdateTime = newTime; - 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() - dp(6); - int left = imageView.getRight() - dp(10); + final float lockT = premiumBlockedT.set(premiumBlocked); + if (lockT > 0) { + int top = imageView.getBottom() - dp(9); + int left = imageView.getRight() - dp(9.33f); + + canvas.save(); Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(currentType == TYPE_CALL ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_windowBackgroundWhite)); - canvas.drawCircle(left, top, dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); - Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(Theme.key_chats_onlineCircle)); - canvas.drawCircle(left, top, dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); - if (isOnline) { - if (onlineProgress < 1.0f) { - onlineProgress += dt / 150.0f; - if (onlineProgress > 1.0f) { - onlineProgress = 1.0f; + canvas.drawCircle(left, top, dp(12) * lockT, Theme.dialogs_onlineCirclePaint); + if (premiumGradient == null) { + premiumGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + premiumGradient.gradientMatrix(left - dp(10), top - dp(10), left + dp(10), top + dp(10), 0, 0); + canvas.drawCircle(left, top, dp(10) * lockT, premiumGradient.paint); + if (lockDrawable == null) { + lockDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); + lockDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + lockDrawable.setBounds( + (int) (left - lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top - lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT), + (int) (left + lockDrawable.getIntrinsicWidth() / 2f * .875f * lockT), + (int) (top + lockDrawable.getIntrinsicHeight() / 2f * .875f * lockT) + ); + lockDrawable.setAlpha((int) (0xFF * lockT)); + lockDrawable.draw(canvas); + canvas.restore(); + } else { + boolean isOnline = !premiumBlocked && !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() - 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, dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); + Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(Theme.key_chats_onlineCircle)); + canvas.drawCircle(left, top, dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); + if (isOnline) { + if (onlineProgress < 1.0f) { + onlineProgress += dt / 150.0f; + if (onlineProgress > 1.0f) { + onlineProgress = 1.0f; + } + imageView.invalidate(); + invalidate(); } - imageView.invalidate(); - invalidate(); - } - } else { - if (onlineProgress > 0.0f) { - onlineProgress -= dt / 150.0f; - if (onlineProgress < 0.0f) { - onlineProgress = 0.0f; + } else { + if (onlineProgress > 0.0f) { + onlineProgress -= dt / 150.0f; + if (onlineProgress < 0.0f) { + onlineProgress = 0.0f; + } + imageView.invalidate(); + invalidate(); } - imageView.invalidate(); - invalidate(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 5f02c4186..c33fffe3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -189,6 +189,7 @@ import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Adapters.MessagesSearchAdapter; import org.telegram.ui.Cells.BotHelpCell; import org.telegram.ui.Cells.BotSwitchCell; @@ -208,7 +209,6 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugController; import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; -import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; import org.telegram.ui.Components.Premium.boosts.BoostDialogs; @@ -221,9 +221,9 @@ import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.voip.CellFlickerDrawable; import org.telegram.ui.Components.voip.VoIPHelper; import org.telegram.ui.Delegates.ChatActivityMemberRequestsDelegate; -import org.telegram.ui.Stories.DialogStoriesCell; import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoriesUtilities; +import org.telegram.ui.Stories.recorder.HintView2; import org.telegram.ui.Stories.recorder.PreviewView; import org.telegram.ui.Stories.recorder.StoryEntry; import org.telegram.ui.Stories.recorder.StoryRecorder; @@ -311,6 +311,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private GridLayoutManagerFixed chatLayoutManager; private ChatActivityAdapter chatAdapter; private UnreadCounterTextView bottomOverlayChatText; + private boolean bottomOverlayLinks; + private LinkSpanDrawable.LinksTextView bottomOverlayLinksText; + private TextView bottomOverlayText; private TextView bottomOverlayStartButton; private ImageView bottomOverlayImage; private RadialProgressView bottomOverlayProgress; @@ -329,7 +332,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ChatBigEmptyView bigEmptyView; private ArrayList actionModeViews = new ArrayList<>(); private ChatAvatarContainer avatarContainer; - private TextView bottomOverlayText; private NumberTextView selectedMessagesCountTextView; private RecyclerListView.OnItemClickListener mentionsOnItemClickListener; private SuggestEmojiView suggestEmojiPanel; @@ -351,6 +353,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ImageView mentiondownButtonImage; private Bulletin messageSeenPrivacyBulletin; TextView webBotTitle; + public SearchTagsList actionBarSearchTags; + + private HintView2 savedMessagesHint; private int reactionsMentionCount; private FrameLayout reactionsMentiondownButton; @@ -444,6 +449,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ImageView searchUpButton; private ImageView searchDownButton; private SearchCounterView searchCountText; + private AnimatedTextView searchOtherButton; private ChatActionCell floatingDateView; private ChatActionCell infoTopView; private int hideDateDelay = 500; @@ -458,6 +464,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean searchingForUser; private TLRPC.User searchingUserMessages; private TLRPC.Chat searchingChatMessages; + private ReactionsLayoutInBubble.VisibleReaction searchingReaction; private UndoView undoView; private UndoView topUndoView; private Bulletin pinBulletin; @@ -477,19 +484,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public static final int MODE_DEFAULT = 0; public static final int MODE_SCHEDULED = 1; public static final int MODE_PINNED = 2; + public static final int MODE_SAVED = 3; private int chatMode; private int scheduledMessagesCount = -1; private int reportType = -1; + @Nullable private MessageObject threadMessageObject; private MessageObject topicStarterMessageObject; private boolean threadMessageVisible = true; private ArrayList threadMessageObjects; private MessageObject replyMessageHeaderObject; private TLRPC.TL_forumTopic forumTopic; - private int threadMessageId; + private long threadMessageId; private int replyOriginalMessageId; private TLRPC.Chat replyOriginalChat; private boolean isComments; @@ -1064,8 +1073,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } - public int getTopicId() { - return isTopic ? threadMessageId : 0; + public long getTopicId() { + return isTopic ? threadMessageId : 0L; + } + + public long getSavedDialogId() { + return chatMode == MODE_SAVED ? threadMessageId : 0L; } public boolean isForumInViewAsMessagesMode() { @@ -1323,6 +1336,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void startMultiselect(int position) { + if (chatMode == MODE_SAVED) { + return; + } int indexOfMessage = position - chatAdapter.messagesStartRow; if (indexOfMessage < 0 || indexOfMessage >= messages.size()) { return; @@ -1429,10 +1445,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } wasManualScroll = true; if (view instanceof ChatActionCell && ((ChatActionCell) view).getMessageObject().isDateObject) { + if (isInsideContainer) { + return; + } Bundle bundle = new Bundle(); int date = ((ChatActionCell) view).getMessageObject().messageOwner.date; bundle.putLong("dialog_id", dialog_id); - bundle.putInt("topic_id", getTopicId()); + bundle.putLong("topic_id", getTopicId()); bundle.putInt("type", CalendarActivity.TYPE_CHAT_ACTIVITY); CalendarActivity calendarActivity = new CalendarActivity(bundle, SharedMediaLayout.FILTER_PHOTOS_AND_VIDEOS, date); presentFragment(calendarActivity); @@ -1598,7 +1617,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (ChatObject.isForum(currentChat) && !isTopic && replyingMessageObject != null) { - int topicId = replyingMessageObject.replyToForumTopic != null ? replyingMessageObject.replyToForumTopic.id : MessageObject.getTopicId(replyingMessageObject.messageOwner, true); + long topicId = replyingMessageObject.replyToForumTopic != null ? replyingMessageObject.replyToForumTopic.id : MessageObject.getTopicId(currentAccount, replyingMessageObject.messageOwner, true); if (topicId != 0) { getMediaDataController().cleanDraft(dialog_id, topicId, false); } @@ -1675,7 +1694,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not editTextItem.setTag(1); if (editTextItem.getVisibility() != View.VISIBLE) { - if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { + if (chatMode == MODE_SAVED && getSavedDialogId() == getUserConfig().getClientUserId() || chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { editTextItem.setVisibility(View.VISIBLE); checkEditTextItemMenu(); headerItem.setVisibility(View.GONE); @@ -1709,7 +1728,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (editTextItem.getTag() != null) { editTextItem.setTag(null); if (editTextItem.getVisibility() != View.GONE) { - if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { + if (chatMode == MODE_SAVED && getSavedDialogId() == getUserConfig().getClientUserId() || chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { editTextItem.setVisibility(View.GONE); if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer())) { @@ -1904,12 +1923,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openAttachMenu(); } + @Override + public void toggleVideoRecordingPause() { + if (instantCameraView != null) { + instantCameraView.togglePause(); + } + } + @Override public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { checkInstantCameraView(); if (instantCameraView != null) { if (state == 0) { - instantCameraView.showCamera(); + instantCameraView.showCamera(false); chatListView.stopScroll(); chatAdapter.updateRowsSafe(); } else if (state == 1 || state == 3 || state == 4) { @@ -2102,6 +2128,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scheduledHintShown = true; }; + public boolean isInsideContainer; + public boolean reversed; + public ChatActivity(Bundle args) { super(args); } @@ -2356,6 +2385,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); getNotificationCenter().addObserver(this, NotificationCenter.updateTranscriptionLock); + getNotificationCenter().addObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + if (actionBarSearchTags != null) { + actionBarSearchTags.attach(); + } super.onFragmentCreate(); @@ -2514,7 +2547,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (isTopic) { getMessagesController().getTopicsController().getTopicRepliesCount(dialog_id, getTopicId()); } - + getMessagesController().getSavedMessagesController().preloadDialogs(); return true; } @@ -2530,9 +2563,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not startLoadFromMessageIdSaved = startLoadFromMessageId; if (migrated_to != 0) { mergeDialogId = migrated_to; - getMessagesController().loadMessages(mergeDialogId, 0, loadInfo, initialMessagesSize, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++, isTopic); + getMessagesController().loadMessages(mergeDialogId, 0, loadInfo, initialMessagesSize, startLoadFromMessageId, 0, true, 0, classGuid, MessagesController.LOAD_AROUND_MESSAGE, 0, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++, isTopic); } else { - getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, initialMessagesSize, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++, isTopic); + getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, initialMessagesSize, startLoadFromMessageId, 0, true, 0, classGuid, MessagesController.LOAD_AROUND_MESSAGE, 0, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++, isTopic); } } else { if (historyPreloaded) { @@ -2725,6 +2758,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); getNotificationCenter().removeObserver(this, NotificationCenter.updateTranscriptionLock); + getNotificationCenter().removeObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + if (actionBarSearchTags != null) { + actionBarSearchTags.detach(); + } if (currentEncryptedChat != null) { getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } @@ -2888,6 +2925,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionBar.setTitleColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); actionBar.setSubtitleColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); } + if (isInsideContainer) { + actionBar.setVisibility(View.GONE); + } actionBarBackgroundPaint.setColor(getThemedColor(Theme.key_actionBarDefault)); sharedResources = new ChatMessageSharedResources(context); @@ -3031,6 +3071,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null) { return; } + if (chatMode == MODE_SAVED) { + String dialogName = ""; + long dialogId = getSavedDialogId(); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (dialogId >= 0) { + user = getMessagesController().getUser(dialogId); + } else { + chat = getMessagesController().getChat(-dialogId); + } + if (UserObject.isAnonymous(user)) { + dialogName = LocaleController.getString(R.string.AnonymousForward); + } else if (chat != null) { + dialogName = chat.title; + } else if (user != null) { + dialogName = UserObject.getUserName(user); + } + AlertDialog dialog = new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.formatString(R.string.ClearHistoryTitleSingle, dialogName)) + .setMessage(LocaleController.formatString(R.string.ClearHistoryMessageSingle, dialogName)) + .setPositiveButton(LocaleController.getString(R.string.Delete), (di, w) -> { + getMessagesController().deleteSavedDialog(getSavedDialogId()); + finishFragment(); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + } + return; + } boolean canDeleteHistory = chatInfo != null && chatInfo.can_delete_channel; if (id == auto_delete_timer || id == clear_history && currentEncryptedChat == null && ((currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isDeleted(currentUser)) || (chatInfo != null && chatInfo.can_delete_channel))) { AlertsCreator.createClearDaysDialogAlert(ChatActivity.this, -1, currentUser, currentChat, canDeleteHistory, new MessagesStorage.BooleanCallback() { @@ -3248,14 +3321,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (avatarContainer != null) { avatarContainer.onDestroy(); } - avatarContainer = new ChatAvatarContainer(context, this, currentEncryptedChat != null, themeDelegate); + avatarContainer = new ChatAvatarContainer(context, this, currentEncryptedChat != null, themeDelegate) { + @Override + protected boolean useAnimatedSubtitle() { + return chatMode == MODE_SAVED; + } + }; avatarContainer.allowShorterStatus = true; avatarContainer.premiumIconHiddable = true; avatarContainer.allowDrawStories = dialog_id < 0; avatarContainer.setClipChildren(false); AndroidUtilities.updateViewVisibilityAnimated(avatarContainer, true, 1f, false); updateTopicTitleIcon(); - if (inPreviewMode || inBubbleMode) { + if (inPreviewMode || inBubbleMode || isInsideContainer) { avatarContainer.setOccupyStatusBar(false); } if (reportType >= 0) { @@ -3328,14 +3406,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ActionBarMenu menu = actionBar.createMenu(); - if (currentEncryptedChat == null && chatMode == 0 && reportType < 0) { + if (currentEncryptedChat == null && (chatMode == 0 || chatMode == MODE_SAVED) && reportType < 0) { searchIconItem = menu.addItem(search, R.drawable.ic_ab_search); searchIconItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); searchItem = menu.addItem(chat_menu_search, R.drawable.ic_ab_search, themeDelegate); searchItem.setIsSearchField(true); searchItem.setActionBarMenuItemSearchListener(getSearchItemListener()); searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); - if (threadMessageId == 0 && !UserObject.isReplyUser(currentUser) || threadMessageObject != null && threadMessageObject.getRepliesCount() < 10) { + if (chatMode == MODE_SAVED || threadMessageId == 0 && !UserObject.isReplyUser(currentUser) || threadMessageObject != null && threadMessageObject.getRepliesCount() < 10) { searchItem.setVisibility(View.GONE); } else { searchItem.setVisibility(View.VISIBLE); @@ -3367,7 +3445,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not editTextItem.setTag(null); editTextItem.setVisibility(View.GONE); - if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { + if (chatMode == MODE_SAVED || (chatMode == 0 && (threadMessageId == 0 || isTopic)) && !UserObject.isReplyUser(currentUser) && reportType < 0) { TLRPC.UserFull userFull = null; if (currentUser != null) { userFull = getMessagesController().getUserFull(currentUser.id); @@ -3375,7 +3453,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not headerItem = menu.addItem(chat_menu_options, R.drawable.ic_ab_other, themeDelegate); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - if (currentUser == null || !currentUser.self) { + if (chatMode != MODE_SAVED && (currentUser == null || !currentUser.self)) { chatNotificationsPopupWrapper = new ChatNotificationsPopupWrapper(context, currentAccount, headerItem.getPopupLayout().getSwipeBack(), false, false, new ChatNotificationsPopupWrapper.Callback() { @Override public void dismiss() { @@ -3412,14 +3490,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void showCustomize() { - if (dialog_id != 0) { + if (dialog_id != 0 && chatMode != MODE_SAVED) { if (currentUser != null) { getMessagesController().putUser(currentUser, true); } Bundle args = new Bundle(); args.putLong("dialog_id", dialog_id); if (getTopicId() != 0) { - args.putInt("topic_id", getTopicId()); + args.putLong("topic_id", getTopicId()); } presentFragment(new ProfileNotificationsActivity(args, themeDelegate)); } @@ -3449,7 +3527,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); muteItemGap = headerItem.lazilyAddColoredGap(); } - if (currentUser != null) { + if (currentUser != null && chatMode != MODE_SAVED) { headerItem.lazilyAddSubItem(call, R.drawable.msg_callback, LocaleController.getString("Call", R.string.Call)); if (Build.VERSION.SDK_INT >= 18) { headerItem.lazilyAddSubItem(video_call, R.drawable.msg_videocall, LocaleController.getString("VideoCall", R.string.VideoCall)); @@ -3468,30 +3546,36 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (searchItem != null) { - headerItem.lazilyAddSubItem(search, R.drawable.msg_search, LocaleController.getString("Search", R.string.Search)); + headerItem.lazilyAddSubItem(search, R.drawable.msg_search, LocaleController.getString(R.string.Search)); } - translateItem = headerItem.lazilyAddSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); - updateTranslateItemVisibility(); - if (currentChat != null && !currentChat.creator && !ChatObject.hasAdminRights(currentChat)) { - headerItem.lazilyAddSubItem(report, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat)); - } - if (currentUser != null) { - addContactItem = headerItem.lazilyAddSubItem(share_contact, R.drawable.msg_addcontact, ""); - } - if (currentEncryptedChat != null) { - timeItem2 = headerItem.lazilyAddSubItem(chat_enc_timer, R.drawable.msg_autodelete, LocaleController.getString("SetTimer", R.string.SetTimer)); - } - if (currentChat != null && !isTopic) { - viewAsTopics = headerItem.lazilyAddSubItem(view_as_topics, R.drawable.msg_topics, LocaleController.getString("TopicViewAsTopics", R.string.TopicViewAsTopics)); - } - if (themeDelegate.isThemeChangeAvailable(true)) { - headerItem.lazilyAddSubItem(change_colors, R.drawable.msg_colors, LocaleController.getString("SetWallpapers", R.string.SetWallpapers)); - } - if (!isTopic) { - clearHistoryItem = headerItem.lazilyAddSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory)); + if (chatMode != MODE_SAVED) { + translateItem = headerItem.lazilyAddSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage)); + updateTranslateItemVisibility(); + if (currentChat != null && !currentChat.creator && !ChatObject.hasAdminRights(currentChat)) { + headerItem.lazilyAddSubItem(report, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat)); + } + if (currentUser != null) { + addContactItem = headerItem.lazilyAddSubItem(share_contact, R.drawable.msg_addcontact, ""); + } + if (currentEncryptedChat != null) { + timeItem2 = headerItem.lazilyAddSubItem(chat_enc_timer, R.drawable.msg_autodelete, LocaleController.getString("SetTimer", R.string.SetTimer)); + } + if (currentChat != null && !isTopic) { + viewAsTopics = headerItem.lazilyAddSubItem(view_as_topics, R.drawable.msg_topics, LocaleController.getString("TopicViewAsTopics", R.string.TopicViewAsTopics)); + } + if (themeDelegate.isThemeChangeAvailable(true)) { + headerItem.lazilyAddSubItem(change_colors, R.drawable.msg_colors, LocaleController.getString("SetWallpapers", R.string.SetWallpapers)); + } + if (!isTopic) { + clearHistoryItem = headerItem.lazilyAddSubItem(clear_history, R.drawable.msg_clear, LocaleController.getString("ClearHistory", R.string.ClearHistory)); + } } boolean addedSettings = false; - if (!isTopic) { + if (chatMode == MODE_SAVED) { + if (threadMessageId != getUserConfig().getClientUserId()) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_delete, LocaleController.getString("DeleteChatUser", R.string.DeleteChatUser)); + } + } else if (!isTopic) { if (ChatObject.isChannel(currentChat) && !currentChat.creator) { if (!ChatObject.isNotInChat(currentChat)) { if (currentChat.megagroup) { @@ -3512,15 +3596,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - if (currentUser != null && currentUser.self) { - headerItem.lazilyAddSubItem(add_shortcut, R.drawable.msg_home, LocaleController.getString("AddShortcut", R.string.AddShortcut)); - } - if (currentUser != null && currentEncryptedChat == null && currentUser.bot) { - if (!addedSettings) { - headerItem.lazilyAddSubItem(bot_settings, R.drawable.msg_settings_old, LocaleController.getString("BotSettings", R.string.BotSettings)); + if (chatMode != MODE_SAVED) { + if (currentUser != null && currentUser.self) { + headerItem.lazilyAddSubItem(add_shortcut, R.drawable.msg_home, LocaleController.getString("AddShortcut", R.string.AddShortcut)); + } + if (currentUser != null && currentEncryptedChat == null && currentUser.bot) { + if (!addedSettings) { + headerItem.lazilyAddSubItem(bot_settings, R.drawable.msg_settings_old, LocaleController.getString("BotSettings", R.string.BotSettings)); + } + headerItem.lazilyAddSubItem(bot_help, R.drawable.msg_help, LocaleController.getString("BotHelp", R.string.BotHelp)); + updateBotButtons(); } - headerItem.lazilyAddSubItem(bot_help, R.drawable.msg_help, LocaleController.getString("BotHelp", R.string.BotHelp)); - updateBotButtons(); } } if (ChatObject.isForum(currentChat) && isTopic && getParentLayout() != null && getParentLayout().getFragmentStack() != null && chatMode == MODE_DEFAULT) { @@ -3574,7 +3660,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragmentView = contentView = new ChatActivityFragmentView(context, parentLayout); contentView.needBlur = true; contentView.needBlurBottom = true; - if (inBubbleMode) { + if (inBubbleMode || isInsideContainer) { contentView.setOccupyStatusBar(false); } @@ -3598,7 +3684,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView = new RecyclerListViewInternal(context, themeDelegate) { - private int lastWidth; private final ArrayList drawTimeAfter = new ArrayList<>(); @@ -3687,7 +3772,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected boolean allowSelectChildAtPosition(View child) { - if (child != null && child.getVisibility() == View.INVISIBLE) return false; + if (child != null && (child.getVisibility() == View.INVISIBLE || child.getVisibility() == View.GONE)) return false; return super.allowSelectChildAtPosition(child); } @@ -4182,7 +4267,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not drawReplyButton(c); } - if (pullingDownOffset != 0 && !isInPreviewMode()) { + if (pullingDownOffset != 0 && !isInPreviewMode() && !isInsideContainer && chatMode != MODE_SAVED) { c.save(); float transitionOffset = 0; if (pullingDownAnimateProgress != 0) { @@ -4450,7 +4535,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not invalidated = false; canvas.save(); - if (fragmentTransition == null || (fromPullingDownTransition && !toPullingDownTransition)) { + if ((fragmentTransition == null || (fromPullingDownTransition && !toPullingDownTransition)) && !isInsideContainer) { canvas.clipRect(0, chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4), getMeasuredWidth(), getMeasuredHeight() - blurredViewBottomOffset); } selectorRect.setEmpty(); @@ -4815,7 +4900,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ChatMessageCell cell; ChatActionCell actionCell = null; float cilpTop = chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4); - if (child.getY() > getMeasuredHeight() || child.getY() + child.getMeasuredHeight() < cilpTop || child.getVisibility() == View.INVISIBLE || child.getVisibility() == View.GONE) { skipDraw = true; } @@ -5291,7 +5375,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListItemAnimator.setOnSnapMessage(this::supportsThanosEffect, this::getChatThanosEffect); } - chatLayoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, true) { + chatLayoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, !reversed) { boolean computingScroll; @@ -5440,7 +5524,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int i = 0; i < n; i++) { View child = chatListView.getChildAt(i); float padding = chatListViewPaddingTop; - if (chatListView.getChildAdapterPosition(child) == chatAdapter.getItemCount() - 1) { + if (chatListView.getChildAdapterPosition(child) == (reversed ? 0 : chatAdapter.getItemCount() - 1)) { int dyLocal = dy; if (child.getTop() - dy > padding) { dyLocal = (int) (child.getTop() - padding); @@ -5453,7 +5537,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!foundTopView) { scrolled = super.scrollVerticallyBy(dy, recycler, state); } - if (dy > 0 && scrolled == 0 && ChatObject.isChannel(currentChat) && !currentChat.megagroup && chatListView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING && !chatListView.isFastScrollAnimationRunning() && !chatListView.isMultiselect() && reportType < 0) { + if (dy > 0 && scrolled == 0 && ChatObject.isChannel(currentChat) && chatMode != MODE_SAVED && !currentChat.megagroup && chatListView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING && !chatListView.isFastScrollAnimationRunning() && !chatListView.isMultiselect() && reportType < 0) { if (pullingDownOffset == 0 && pullingDownDrawable != null) { pullingDownDrawable.updateDialog(); } @@ -5837,7 +5921,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not req.peer = getMessagesController().getInputPeer(dialog_id); req.limit = 1; if (isTopic) { - req.top_msg_id = threadMessageId; + req.top_msg_id = (int) threadMessageId; req.flags |= 1; } req.add_offset = newMentionsCount - 1; @@ -6352,19 +6436,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not reactionsMentiondownButton.addView(reactionsMentiondownButtonCounter, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, Gravity.TOP | Gravity.LEFT)); reactionsMentiondownButton.setContentDescription(LocaleController.getString("AccDescrReactionMentionDown", R.string.AccDescrReactionMentionDown)); - fragmentLocationContextView = new FragmentContextView(context, this, true, themeDelegate); - fragmentContextView = new FragmentContextView(context, this, false, themeDelegate); - contentView.addView(fragmentLocationContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); - contentView.addView(fragmentContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + if (!isInsideContainer) { + fragmentLocationContextView = new FragmentContextView(context, this, true, themeDelegate); + fragmentContextView = new FragmentContextView(context, this, false, themeDelegate); + contentView.addView(fragmentLocationContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + contentView.addView(fragmentContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); - fragmentContextView.setAdditionalContextView(fragmentLocationContextView); - fragmentLocationContextView.setAdditionalContextView(fragmentContextView); + fragmentContextView.setAdditionalContextView(fragmentLocationContextView); + fragmentLocationContextView.setAdditionalContextView(fragmentContextView); - fragmentContextView.setEnabled(!inPreviewMode); - fragmentLocationContextView.setEnabled(!inPreviewMode); + fragmentContextView.setEnabled(!inPreviewMode); + fragmentLocationContextView.setEnabled(!inPreviewMode); - if (chatMode != 0) { - fragmentContextView.setSupportsCalls(false); + if (chatMode != 0) { + fragmentContextView.setSupportsCalls(false); + } } messagesSearchListView = new RecyclerListView(context, themeDelegate); @@ -6603,7 +6689,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setFieldText(inlineQueryForInput); inlineQueryForInput = null; } - if (inPreviewMode) { + if (inPreviewMode || isInsideContainer) { chatActivityEnterView.setVisibility(View.INVISIBLE); } if (!ChatObject.isChannel(currentChat) || currentChat.megagroup) { @@ -6674,7 +6760,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (messagePreviewParams != null) { forbidForwardingWithDismiss = false; if (fieldPanelShown == 2) { - if (DialogObject.isEncryptedDialog(dialog_id)) { + if (DialogObject.isEncryptedDialog(dialog_id) || messagePreviewParams.hasSecretMessages) { if (replyingMessageObject != null) { scrollToMessageId(replyingMessageObject.getId(), 0, true, 0, true, 0); } @@ -6725,7 +6811,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fallbackFieldPanel(); } else { if (ChatObject.isForum(currentChat) && !isTopic && replyingMessageObject != null) { - int topicId = MessageObject.getTopicId(replyingMessageObject.messageOwner, true); + long topicId = MessageObject.getTopicId(currentAccount, replyingMessageObject.messageOwner, true); if (topicId != 0) { getMediaDataController().cleanDraft(dialog_id, topicId, false); } @@ -6874,7 +6960,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bottomOverlayText.setEllipsize(TextUtils.TruncateAt.END); bottomOverlayText.setLineSpacing(AndroidUtilities.dp(2), 1); bottomOverlayText.setTextColor(getThemedColor(Theme.key_chat_secretChatStatusText)); - bottomOverlay.addView(bottomOverlayText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 14, 0, 14, 0)); + bottomOverlay.addView(bottomOverlayText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 24, 0, 24, 0)); bottomOverlayChat = new BlurredFrameLayout(context, contentView) { @Override @@ -6946,11 +7032,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bottomOverlayStartButton.setOnClickListener(v -> bottomOverlayChatText.callOnClick()); bottomOverlayChat.addView(bottomOverlayStartButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER, 8, 8, 8, 8)); - if (currentUser != null && currentUser.bot && !UserObject.isReplyUser(currentUser) && !isInScheduleMode() && chatMode != MODE_PINNED) { + if (currentUser != null && currentUser.bot && !UserObject.isReplyUser(currentUser) && !isInScheduleMode() && chatMode != MODE_PINNED && chatMode != MODE_SAVED) { bottomOverlayStartButton.setVisibility(View.VISIBLE); bottomOverlayChat.setVisibility(View.VISIBLE); } + bottomOverlayLinksText = new LinkSpanDrawable.LinksTextView(context, themeDelegate); + bottomOverlayLinksText.setVisibility(View.GONE); + bottomOverlayLinksText.setTextColor(getThemedColor(Theme.key_graySectionText)); + bottomOverlayLinksText.setGravity(Gravity.CENTER); + bottomOverlayLinksText.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + bottomOverlayLinksText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + bottomOverlayChat.addView(bottomOverlayLinksText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 0)); + bottomOverlayChatText = new UnreadCounterTextView(context) { @Override protected void updateCounter() { @@ -6984,7 +7078,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null || pullingDownOffset != 0) { return; } - if (reportType >= 0) { + if (chatMode == MODE_SAVED) { + Bundle args = new Bundle(); + long dialogId = getSavedDialogId(); + if (dialogId >= 0) { + args.putLong("user_id", dialogId); + } else { + args.putLong("chat_id", -dialogId); + } + presentFragment(new ChatActivity(args)); + } else if (reportType >= 0) { showDialog(new ReportAlert(getParentActivity(), reportType, getResourceProvider()) { @Override protected void onSend(int type, String message) { @@ -7311,45 +7414,126 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + if (getDialogId() == getUserConfig().getClientUserId() && chatMode != MODE_SAVED) { + savedMessagesHint = new HintView2(context, HintView2.DIRECTION_TOP); + savedMessagesHint.setMultilineText(true); + savedMessagesHint.setTextAlign(Layout.Alignment.ALIGN_CENTER); + savedMessagesHint.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.SavedMessagesHint))); + savedMessagesHint.setMaxWidthPx(HintView2.cutInFancyHalf(savedMessagesHint.getText(), savedMessagesHint.getTextPaint())); + savedMessagesHint.setJoint(0.5f, 0); + savedMessagesHint.setCloseButton(true); + savedMessagesHint.setDuration(-1); + contentView.addView(savedMessagesHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 120, Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, -8, 0, 0)); + } + + if (getDialogId() == getUserConfig().getClientUserId()) { + actionBarSearchTags = new SearchTagsList(context, contentView, currentAccount, themeDelegate) { + @Override + protected void setFilter(ReactionsLayoutInBubble.VisibleReaction reaction) { + actionBar.clearSearchFilters(); +// if (reaction != null) { +// actionBar.setSearchFilter(new FiltersView.MediaFilterData(reaction)); +// } + searchingReaction = reaction; +// showSearchShowOther(searchingReaction != null); + getMediaDataController().searchMessagesInChat(searchItem.getSearchField().getText().toString(), dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); + } + + @Override + public void updateTags() { + super.updateTags(); +// showActionBarSearchTags(searchItem != null && searchItem.isSearchFieldVisible() && hasFilters()); + } + }; + actionBarSearchTags.setVisibility(View.GONE); + actionBarSearchTags.attach(); + contentView.addView(actionBarSearchTags, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.FILL_HORIZONTAL | Gravity.TOP)); + } + return fragmentView; } + private void setFilterMessages(boolean filter) { + if (chatAdapter.isFiltered == filter) return; + chatAdapter.isFiltered = filter; + if (filter) { + updateFilteredMessages(); + } else { + chatAdapter.updateRowsSafe(); + chatAdapter.notifyDataSetChanged(true); + } + } + + private void updateFilteredMessages() { + ArrayList results = new ArrayList<>(MediaDataController.getInstance(currentAccount).getFoundMessageObjects()); + chatAdapter.filteredMessages.clear(); + for (int i = 0; i < results.size(); ++i) { + MessageObject msg = results.get(i); + MessageObject from = null; + for (int j = 0; j < messages.size(); ++j) { + MessageObject m = messages.get(j); + if (m.getDialogId() == msg.getDialogId() && m.getId() == msg.getId()) { + from = m; + break; + } + } + if (msg.stableId == 0) { + msg.checkMediaExistance(); + if (from != null) { + msg.copyStableParams(from); + } else { + msg.stableId = lastStableId++; + } + } + msg.isOutOwnerCached = null; + if (msg.messageOwner != null) { + msg.messageOwner.out = true; + } + chatAdapter.filteredMessages.add(msg); + } + chatAdapter.filteredEndReached = MediaDataController.getInstance(currentAccount).searchEndReached(); + chatAdapter.updateRowsSafe(); + chatAdapter.notifyDataSetChanged(true); + } + private void createBottomMessagesActionButtons() { if (replyButton != null || getContext() == null) { return; } - replyButton = new TextView(getContext()); - replyButton.setText(LocaleController.getString("Reply", R.string.Reply)); - replyButton.setGravity(Gravity.CENTER_VERTICAL); - replyButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - replyButton.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(21), 0); - replyButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 3)); - replyButton.setTextColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); - replyButton.setCompoundDrawablePadding(AndroidUtilities.dp(7)); - replyButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - Drawable image = getContext().getResources().getDrawable(R.drawable.input_reply).mutate(); - image.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarActionModeDefaultIcon), PorterDuff.Mode.MULTIPLY)); - replyButton.setCompoundDrawablesWithIntrinsicBounds(image, null, null, null); - replyButton.setOnClickListener(v -> { - MessageObject messageObject = null; - for (int a = 1; a >= 0; a--) { - if (messageObject == null && selectedMessagesIds[a].size() != 0) { - messageObject = messagesDict[a].get(selectedMessagesIds[a].keyAt(0)); + if (!isInsideContainer) { + replyButton = new TextView(getContext()); + replyButton.setText(LocaleController.getString("Reply", R.string.Reply)); + replyButton.setGravity(Gravity.CENTER_VERTICAL); + replyButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + replyButton.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(21), 0); + replyButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 3)); + replyButton.setTextColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); + replyButton.setCompoundDrawablePadding(AndroidUtilities.dp(7)); + replyButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + Drawable image = getContext().getResources().getDrawable(R.drawable.input_reply).mutate(); + image.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarActionModeDefaultIcon), PorterDuff.Mode.MULTIPLY)); + replyButton.setCompoundDrawablesWithIntrinsicBounds(image, null, null, null); + replyButton.setOnClickListener(v -> { + MessageObject messageObject = null; + for (int a = 1; a >= 0; a--) { + if (messageObject == null && selectedMessagesIds[a].size() != 0) { + messageObject = messagesDict[a].get(selectedMessagesIds[a].keyAt(0)); + } + selectedMessagesIds[a].clear(); + selectedMessagesCanCopyIds[a].clear(); + selectedMessagesCanStarIds[a].clear(); } - selectedMessagesIds[a].clear(); - selectedMessagesCanCopyIds[a].clear(); - selectedMessagesCanStarIds[a].clear(); - } - hideActionMode(); - if (messageObject != null && (messageObject.messageOwner.id > 0 || messageObject.messageOwner.id < 0 && currentEncryptedChat != null)) { - showFieldPanelForReply(messageObject); - } - updatePinnedMessageView(true); - updateVisibleRows(); - updateSelectedMessageReactions(); - }); - bottomMessagesActionContainer.addView(replyButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + hideActionMode(); + if (messageObject != null && (messageObject.messageOwner.id > 0 || messageObject.messageOwner.id < 0 && currentEncryptedChat != null)) { + showFieldPanelForReply(messageObject); + } + updatePinnedMessageView(true); + updateVisibleRows(); + updateSelectedMessageReactions(); + }); + bottomMessagesActionContainer.addView(replyButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + } forwardButton = new TextView(getContext()); forwardButton.setText(LocaleController.getString("Forward", R.string.Forward)); @@ -7360,7 +7544,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not forwardButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 3)); forwardButton.setTextColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); forwardButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - image = getContext().getResources().getDrawable(R.drawable.input_forward).mutate(); + Drawable image = getContext().getResources().getDrawable(R.drawable.input_forward).mutate(); image.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarActionModeDefaultIcon), PorterDuff.Mode.MULTIPLY)); forwardButton.setCompoundDrawablesWithIntrinsicBounds(image, null, null, null); forwardButton.setOnClickListener(v -> openForward(false)); @@ -7769,7 +7953,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchUpButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 1)); searchContainer.addView(searchUpButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 48, 0)); searchUpButton.setOnClickListener(view -> { - getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, threadMessageId, searchingUserMessages, searchingChatMessages); + getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); showMessagesSearchListView(false); if (!SharedConfig.searchMessagesAsListUsed && SharedConfig.searchMessagesAsListHintShows < 3 && !searchAsListHintShown && Math.random() <= 0.25) { showSearchAsListHint(); @@ -7786,7 +7970,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchDownButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 1)); searchContainer.addView(searchDownButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 0, 0)); searchDownButton.setOnClickListener(view -> { - getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, threadMessageId, searchingUserMessages, searchingChatMessages); + getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); showMessagesSearchListView(false); }); searchDownButton.setContentDescription(LocaleController.getString("AccDescrSearchPrev", R.string.AccDescrSearchPrev)); @@ -7840,6 +8024,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchCountText.setGravity(Gravity.LEFT); searchContainer.addView(searchCountText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 108, 0)); contentView.addView(searchContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, searchContainerHeight, Gravity.BOTTOM)); + + searchOtherButton = new AnimatedTextView(getContext(), true, true, true); + searchOtherButton.setGravity(Gravity.CENTER); + searchOtherButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + searchOtherButton.setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); + searchOtherButton.setTextSize(AndroidUtilities.dp(15)); + searchOtherButton.setBackground(Theme.createSelectorWithBackgroundDrawable(getThemedColor(Theme.key_windowBackgroundWhite), Theme.blendOver(getThemedColor(Theme.key_windowBackgroundWhite), getThemedColor(Theme.key_listSelector)))); + searchOtherButton.setVisibility(View.GONE); + searchOtherButton.setAlpha(0f); + searchContainer.addView(searchOtherButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + } + + private void showSearchShowOther(boolean show) { + searchOtherButton.setVisibility(View.VISIBLE); + searchOtherButton.animate().alpha(show ? 1f : 0f).withEndAction(() -> { + searchOtherButton.setVisibility(show ? View.VISIBLE : View.GONE); + }).start(); } public void onPageDownClicked() { @@ -7912,7 +8113,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (instantCameraView != null || getContext() == null) { return; } - instantCameraView = new InstantCameraView(getContext(), this, themeDelegate); + instantCameraView = new InstantCameraView(getContext(), this, themeDelegate) { + @Override + protected void clipBlur(Canvas canvas) { + canvas.clipRect(0, 0, getWidth(), getHeight() - dp(1.5f)); + } + }; contentView.addView(instantCameraView, 21, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); } @@ -8403,7 +8609,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionContainer.getAdapter().searchUsernameOrHashtag(null, 0, null, false, true); searchItem.setSearchFieldHint(null); searchItem.clearSearchText(); - getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); + getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); } private void updateTranslateItemVisibility() { @@ -8592,7 +8798,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageView.setOnClickListener(v -> { wasManualScroll = true; if (isThreadChat() && !isTopic) { - scrollToMessageId(threadMessageId, 0, true, 0, true, 0); + scrollToMessageId((int) threadMessageId, 0, true, 0, true, 0); } else if (currentPinnedMessageId != 0) { int currentPinned = currentPinnedMessageId; @@ -8880,7 +9086,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArrayList objects = new ArrayList<>(pinnedMessageObjects.values()); if (hide) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("pin_" + dialog_id, pinnedMessageIds.get(0)).commit(); + if (pinnedMessageIds.isEmpty()) { + preferences.edit().remove("pin_" + dialog_id).commit(); + } else { + preferences.edit().putInt("pin_" + dialog_id, pinnedMessageIds.get(0)).commit(); + } updatePinnedMessageView(true); } else { getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialog_id, ids, false, null, null, 0, 0, true); @@ -9110,6 +9320,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListViewPaddingVisibleOffset = 0; chatListViewPaddingTop += contentPanTranslation + bottomPanelTranslationY; float searchExpandOffset = 0; + if (actionBarSearchTags != null && actionBarSearchTags.shown()) { + chatListViewPaddingTop += actionBarSearchTags.getMeasuredHeight(); + } if (searchExpandProgress != 0 && chatActivityEnterView.getVisibility() == View.VISIBLE) { chatListViewPaddingTop -= (searchExpandOffset = searchExpandProgress * (chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(searchContainerHeight))); } @@ -9137,7 +9350,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not floatingDateView.setTranslationY(chatListView.getTranslationY() - searchExpandOffset + chatListViewPaddingTop + floatingDateViewOffset - AndroidUtilities.dp(4)); } - int p = chatListView.getMeasuredHeight() * 2 / 3; + int p = isInsideContainer ? 0 : chatListView.getMeasuredHeight() * 2 / 3; if (chatListView != null && chatLayoutManager != null && chatAdapter != null) { if (chatListView.getPaddingTop() != p) { @@ -9541,14 +9754,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ObjectAnimator.ofFloat(bottomOverlayProgress, View.ALPHA, 1.0f)); bottomOverlayAnimation.setStartDelay(200); } else { - bottomOverlayChatText.setVisibility(View.VISIBLE); + View text = bottomOverlayLinks ? bottomOverlayLinksText : bottomOverlayChatText; bottomOverlayAnimation.playTogether( ObjectAnimator.ofFloat(bottomOverlayProgress, View.SCALE_X, 0.1f), ObjectAnimator.ofFloat(bottomOverlayProgress, View.SCALE_Y, 0.1f), ObjectAnimator.ofFloat(bottomOverlayProgress, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(bottomOverlayChatText, View.SCALE_X, 1.0f), - ObjectAnimator.ofFloat(bottomOverlayChatText, View.SCALE_Y, 1.0f), - ObjectAnimator.ofFloat(bottomOverlayChatText, View.ALPHA, 1.0f)); + ObjectAnimator.ofFloat(text, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(text, View.SCALE_Y, 1.0f), + ObjectAnimator.ofFloat(text, View.ALPHA, 1.0f)); } bottomOverlayAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -9557,7 +9770,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!show) { bottomOverlayProgress.setVisibility(View.INVISIBLE); } else { - bottomOverlayChatText.setVisibility(View.INVISIBLE); + (bottomOverlayLinks ? bottomOverlayLinksText : bottomOverlayChatText).setVisibility(View.INVISIBLE); } } } @@ -9576,10 +9789,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not bottomOverlayProgress.setScaleX(show ? 1.0f : 0.1f); bottomOverlayProgress.setScaleY(show ? 1.0f : 0.1f); bottomOverlayProgress.setAlpha(show ? 1.0f : 1.0f); - bottomOverlayChatText.setVisibility(show ? View.INVISIBLE : View.VISIBLE); - bottomOverlayChatText.setScaleX(show ? 0.1f : 1.0f); - bottomOverlayChatText.setScaleY(show ? 0.1f : 1.0f); - bottomOverlayChatText.setAlpha(show ? 0.0f : 1.0f); + bottomOverlayChatText.setVisibility(show || bottomOverlayLinks ? View.INVISIBLE : View.VISIBLE); + bottomOverlayLinksText.setVisibility(show || !bottomOverlayLinks ? View.INVISIBLE : View.VISIBLE); + bottomOverlayChatText.setScaleX(show || bottomOverlayLinks ? 0.1f : 1.0f); + bottomOverlayLinksText.setScaleX(show || !bottomOverlayLinks ? 0.1f : 1.0f); + bottomOverlayChatText.setScaleY(show || bottomOverlayLinks ? 0.1f : 1.0f); + bottomOverlayLinksText.setScaleY(show || !bottomOverlayLinks ? 0.1f : 1.0f); + bottomOverlayChatText.setAlpha(show || bottomOverlayLinks ? 0.0f : 1.0f); + bottomOverlayLinksText.setAlpha(show || !bottomOverlayLinks ? 0.0f : 1.0f); } } @@ -10701,8 +10918,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private boolean removingFromParent; @Override public void onRemoveFromParent() { + removingFromParent = true; MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); if (messageObject != null && messageObject.isVideo()) { MediaController.getInstance().cleanupPlayer(true, true); @@ -10731,6 +10950,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatLayoutManager == null || paused || chatAdapter.isFrozen || waitingForGetDifference) { return; } + if (chatAdapter.isFiltered) { + getMediaDataController().loadMoreSearchMessages(); + return; + } int firstVisibleItem = RecyclerListView.NO_POSITION; int visibleItemCount = 0; for (int i = 0; i < chatListView.getChildCount(); i++) { @@ -11667,7 +11890,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not // 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); + long topicId = MessageObject.getTopicId(currentAccount, messageObjectToReply.messageOwner, true); if (topicId != 0) { TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); if (topic != null && topic.topicStartMessage != null) { @@ -11742,7 +11965,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyIconImageView.setImageResource(R.drawable.filled_reply_quote); nameText = AndroidUtilities.replaceCharSequence("%s", LocaleController.getString(R.string.ReplyToQuote), name == null ? "" : name); } else { - replyIconImageView.setImageResource(R.drawable.filled_reply_settings); + if (messagePreviewParams == null || messagePreviewParams.hasSecretMessages) { + replyIconImageView.setImageResource(R.drawable.ic_ab_reply); + } else { + replyIconImageView.setImageResource(R.drawable.filled_reply_settings); + } nameText = AndroidUtilities.replaceCharSequence("%s", LocaleController.getString(R.string.ReplyTo), name == null ? "" : name); } nameText = Emoji.replaceEmoji(nameText, replyNameTextView.getPaint().getFontMetricsInt(), false); @@ -12200,9 +12427,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } final long taskId = getMessagesController().createDeleteShowOnceTask(dialog_id, messageObject.getId()); messageObject.forceExpired = true; - ArrayList msgs = new ArrayList<>(); - msgs.add(messageObject); - updateMessages(msgs, true); + if (messageObject.isOutOwner() || !messageObject.isRoundOnce() && !messageObject.isVoiceOnce()) { + ArrayList msgs = new ArrayList<>(); + msgs.add(messageObject); + updateMessages(msgs, true); + } return () -> getMessagesController().doDeleteShowOnceTask(taskId, dialog_id, messageObject.getId()); } @@ -12493,7 +12722,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not threadMessageVisible = firstLoading; Integer currentReadMaxId = null; - int threadId = threadMessageId; + long threadId = threadMessageId; if (threadId != 0 && currentChat != null) { currentReadMaxId = replyMaxReadId; } else { @@ -12505,7 +12734,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int maxPositiveUnreadId = Integer.MIN_VALUE; int maxNegativeUnreadId = Integer.MAX_VALUE; int maxUnreadDate = Integer.MIN_VALUE; - int recyclerChatViewHeight = (contentView.getHeightWithKeyboard() - (inPreviewMode ? 0 : AndroidUtilities.dp(48)) - chatListView.getTop()); + int recyclerChatViewHeight = (contentView.getHeightWithKeyboard() - (inPreviewMode || isInsideContainer ? 0 : AndroidUtilities.dp(48)) - chatListView.getTop()); pollsToCheck.clear(); float clipTop = chatListViewPaddingTop; long currentTime = System.currentTimeMillis(); @@ -12668,7 +12897,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (bottom <= clipTop) { - if (view instanceof ChatActionCell && messageObject.isDateObject) { + if (view instanceof ChatActionCell && messageObject != null && messageObject.isDateObject) { view.setAlpha(0); } continue; @@ -12682,7 +12911,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not minChild = view; } if (chatListItemAnimator == null || (!chatListItemAnimator.willRemoved(view) && !chatListItemAnimator.willAddedFromAlpha(view))) { - if (view instanceof ChatActionCell && messageObject.isDateObject) { + if (view instanceof ChatActionCell && messageObject != null && messageObject.isDateObject) { if (view.getAlpha() != 1.0f) { view.setAlpha(1.0f); } @@ -12765,7 +12994,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (minDateChild.getAlpha() != 1.0f) { minDateChild.setAlpha(1.0f); } - if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + messages.size() - 1) { + if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + (reversed ? 0 : messages.size() - 1)) { if (minDateChild.getAlpha() != 1.0f) { minDateChild.setAlpha(1.0f); } @@ -12787,7 +13016,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } float offset = minDateChild.getY() + minDateChild.getMeasuredHeight() - clipTop; if (offset > floatingDateView.getMeasuredHeight() && offset < floatingDateView.getMeasuredHeight() * 2) { - if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + messages.size() - 1) { + if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + (reversed ? 0 : messages.size() - 1)) { showFloatingView = false; if (minDateChild.getAlpha() != 1.0f) { minDateChild.setAlpha(1.0f); @@ -13062,6 +13291,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dummyMessageCell = new ChatMessageCell(getParentActivity(), true, sharedResources, themeDelegate); } dummyMessageCell.isChat = currentChat != null || UserObject.isUserSelf(currentUser); + dummyMessageCell.isSavedChat = chatMode == MODE_SAVED; + dummyMessageCell.isSavedPreviewChat = chatMode == MODE_SAVED && isInsideContainer; dummyMessageCell.isBot = currentUser != null && currentUser.bot; dummyMessageCell.isMegagroup = ChatObject.isChannel(currentChat) && currentChat.megagroup; return dummyMessageCell.computeHeight(object, groupedMessagesMap.get(object.getGroupId()), withGroupCaption); @@ -13342,7 +13573,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (pagedownButton == null) { return; } - boolean show = canShowPagedownButton && !textSelectionHelper.isInSelectionMode() && !chatActivityEnterView.isRecordingAudioVideo(); + boolean show = canShowPagedownButton && !textSelectionHelper.isInSelectionMode() && !chatActivityEnterView.isRecordingAudioVideo() && !isInsideContainer; if (show) { if (animated && (openAnimationStartTime == 0 || SystemClock.elapsedRealtime() < openAnimationStartTime + 150)) { animated = false; @@ -13526,6 +13757,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not setNonNoveTranslation(y); } else { actionBar.setTranslationY(y); + if (actionBarSearchTags != null) { + actionBarSearchTags.setTranslationY(y); + } if (emptyViewContainer != null) { emptyViewContainer.setTranslationY(y / 2); } @@ -13896,7 +14130,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (child == actionBar && parentLayout != null) { - parentLayout.drawHeaderShadow(canvas, actionBar.getVisibility() == VISIBLE ? (int) actionBar.getTranslationY() + actionBar.getMeasuredHeight() + (inPreviewMode && Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) : 0); + parentLayout.drawHeaderShadow(canvas, actionBar.getVisibility() == VISIBLE ? (int) actionBar.getTranslationY() + actionBar.getMeasuredHeight() + (actionBarSearchTags != null ? actionBarSearchTags.getCurrentHeight() : 0) + (inPreviewMode && Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) : 0); } return result; } @@ -14287,9 +14521,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int heightSize = allHeight = View.MeasureSpec.getSize(heightMeasureSpec); if (lastWidth != widthSize) { - globalIgnoreLayout = true; + globalIgnoreLayout = false; lastWidth = widthMeasureSpec; - if (!inPreviewMode && currentUser != null && currentUser.self) { + if (chatMode == MODE_SAVED) { + showSearchAsIcon = false; + } else if (!inPreviewMode && currentUser != null && currentUser.self) { SimpleTextView textView = avatarContainer.getTitleTextView(); int textWidth = (int) textView.getPaint().measureText(textView.getText(), 0, textView.getText().length()); if (widthSize - AndroidUtilities.dp(96 + 56) > textWidth + AndroidUtilities.dp(10)) { @@ -14397,7 +14633,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not measureChildWithMargins(chatActivityEnterView, widthMeasureSpec, 0, heightMeasureSpec, 0); int listViewTopHeight; - if (inPreviewMode) { + if (inPreviewMode || isInsideContainer) { inputFieldHeight = 0; listViewTopHeight = 0; } else { @@ -14407,7 +14643,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not blurredViewTopOffset = 0; blurredViewBottomOffset = 0; - if (SharedConfig.chatBlurEnabled()) { + if (SharedConfig.chatBlurEnabled() && !isInsideContainer) { blurredViewTopOffset = actionBarHeight; blurredViewBottomOffset = AndroidUtilities.dp(203); } @@ -14650,7 +14886,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not childTop -= inputFieldHeight; } else if (child == chatListView || child == chatListThanosEffect || child == floatingDateView || child == infoTopView) { childTop -= blurredViewTopOffset; - if (!inPreviewMode) { + if (!inPreviewMode && !isInsideContainer) { childTop -= (inputFieldHeight - AndroidUtilities.dp(51)); } childTop -= paddingBottom; @@ -14698,6 +14934,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void setNonNoveTranslation(float y) { contentView.setTranslationY(y); actionBar.setTranslationY(0); + if (actionBarSearchTags != null) { + actionBarSearchTags.setTranslationY(0); + } emptyViewContainer.setTranslationY(0); progressView.setTranslationY(0); contentPanTranslation = 0; @@ -14747,7 +14986,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } boolean hideKeyboard = false; - if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !ChatObject.canSendAnyMedia(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { + if (chatMode == MODE_SAVED && getSavedDialogId() == UserObject.ANONYMOUS) { + bottomOverlayText.setText(LocaleController.getString(R.string.AuthorHiddenDescription)); + bottomOverlay.setVisibility(View.VISIBLE); + if (mentionListAnimation != null) { + mentionListAnimation.cancel(); + mentionListAnimation = null; + } + mentionContainer.setVisibility(View.GONE); + mentionContainer.setTag(null); + updateMessageListAccessibilityVisibility(); + hideKeyboard = true; + if (suggestEmojiPanel != null) { + suggestEmojiPanel.forceClose(); + } + } else if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !ChatObject.canSendAnyMedia(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { if (currentChat.default_banned_rights != null && currentChat.default_banned_rights.send_messages) { bottomOverlayText.setText(LocaleController.getString("GlobalSendMessageRestricted", R.string.GlobalSendMessageRestricted)); } else if (AndroidUtilities.isBannedForever(currentChat.banned_rights)) { @@ -14795,7 +15048,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideKeyboard = true; } else if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { bottomOverlay.setVisibility(View.INVISIBLE); - if (!inPreviewMode) { + if (!inPreviewMode && !isInsideContainer && chatMode != MODE_SAVED) { chatActivityEnterView.setVisibility(View.VISIBLE); } } @@ -15158,7 +15411,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (messageObject.isMusic() && !noforwards) { canSaveMusicCount++; - } else if (messageObject.isDocument() && !noforwards) { + } else if (messageObject.isDocument() && !messageObject.isRoundOnce() && !messageObject.isVoiceOnce() && !noforwards) { canSaveDocumentsCount++; } else { cantSaveMessagesCount++; @@ -15484,7 +15737,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (avatarContainer == null) { return; } - if (isThreadChat()) { + if (chatMode == MODE_SAVED) { + long dialogId = threadMessageId; + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (dialogId > 0) { + user = getMessagesController().getUser(dialogId); + } else { + chat = getMessagesController().getChat(-dialogId); + } + if (UserObject.isReplyUser(user)) { + avatarContainer.setTitle(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); + } else if (UserObject.isAnonymous(user)) { + avatarContainer.setTitle(LocaleController.getString(R.string.AnonymousForward)); + } else if (UserObject.isUserSelf(user)) { + avatarContainer.setTitle(LocaleController.getString(R.string.MyNotes)); + } else if (user != null) { + avatarContainer.setTitle(UserObject.getUserName(user)); + } else if (chat != null) { + avatarContainer.setTitle(chat.title); + } else { + avatarContainer.setTitle(""); + } + } else if (isThreadChat()) { if (isTopic) { updateTopicHeader(); } else if (isComments) { @@ -15498,6 +15773,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (UserObject.isReplyUser(currentUser)) { avatarContainer.setTitle(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); + } else if (UserObject.isAnonymous(currentUser)) { + avatarContainer.setTitle(LocaleController.getString(R.string.AnonymousForward)); } else if (chatMode == MODE_SCHEDULED) { if (UserObject.isUserSelf(currentUser)) { avatarContainer.setTitle(LocaleController.getString("Reminders", R.string.Reminders)); @@ -16224,7 +16501,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragmentTransitionRunnable.run(); return; } - if (chatMode != mode) { + if (chatMode != mode && chatMode != MODE_SAVED) { if (chatMode != MODE_SCHEDULED) { if (isTopic) { ForumUtilities.filterMessagesByTopic(threadMessageId, messArr); @@ -16467,7 +16744,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (isThreadChat() && !isTopic && (load_type == 2 || load_type == 3) && !isCache) { if (load_type == 3 && scrollToThreadMessage) { - startLoadFromMessageId = threadMessageId; + startLoadFromMessageId = (int) threadMessageId; } int beforMax = 0; int afterMax = 0; @@ -16739,24 +17016,38 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (groupedMessages != null) { if (messages.size() > 1) { MessageObject previous; - if (load_type == 1) { + if (load_type == MessagesController.LOAD_FORWARD) { previous = messages.get(0); } else { - previous = messages.get(messages.size() - 2); + previous = messages.get(messages.size() - (reversed ? 1 : 2)); } if (previous.getGroupIdForUse() == obj.getGroupIdForUse()) { if (previous.localGroupId != 0) { obj.localGroupId = previous.localGroupId; groupedMessages = groupedMessagesMap.get(previous.localGroupId); } - } else if (previous.getGroupIdForUse() != obj.getGroupIdForUse()) { - obj.localGroupId = Utilities.random.nextLong(); - groupedMessages = null; + } else { + if (reversed) { + previous = messages.get(messages.size() - 2); + if (previous.getGroupIdForUse() == obj.getGroupIdForUse()) { + if (previous.localGroupId != 0) { + obj.localGroupId = previous.localGroupId; + groupedMessages = groupedMessagesMap.get(previous.localGroupId); + } + } else { + obj.localGroupId = Utilities.random.nextLong(); + groupedMessages = null; + } + } else { + obj.localGroupId = Utilities.random.nextLong(); + groupedMessages = null; + } } } } if (groupedMessages == null) { groupedMessages = new MessageObject.GroupedMessages(); + groupedMessages.reversed = reversed; groupedMessages.groupId = obj.getGroupId(); groupedMessagesMap.put(groupedMessages.groupId, groupedMessages); } else if (newGroups == null || newGroups.indexOfKey(obj.getGroupId()) < 0) { @@ -16791,7 +17082,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messages.add(0, obj); } else { messages.get(messages.size() - 1).stableId = lastStableId++; - messages.add(messages.size() - 1, obj); + if (reversed) { + messages.add(obj); + } else { + messages.add(messages.size() - 1, obj); + } } MessageObject prevObj; if (currentEncryptedChat == null) { @@ -16813,7 +17108,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not prevObj = null; } } - if (load_type == 2 && messageId != 0 && messageId == first_unread_id) { + if (load_type == 2 && messageId != 0 && messageId == first_unread_id && chatMode != MODE_SAVED) { if ((approximateHeightSum > AndroidUtilities.displaySize.y / 2 || isThreadChat()) || !forwardEndReached[0]) { if (!isThreadChat() || threadMaxInboxReadId != 0) { TLRPC.Message dateMsg = new TLRPC.TL_message(); @@ -16852,7 +17147,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (load_type != 2 && unreadMessageObject == null && createUnreadMessageAfterId != 0 && (currentEncryptedChat == null && (!obj.isOut() || obj.messageOwner.from_scheduled) && messageId >= createUnreadMessageAfterId || currentEncryptedChat != null && (!obj.isOut() || obj.messageOwner.from_scheduled) && messageId <= createUnreadMessageAfterId) && - (load_type == 1 || prevObj != null || prevObj == null && createUnreadLoading && a == messArr.size() - 1)) { + (load_type == 1 || prevObj != null || prevObj == null && createUnreadLoading && a == messArr.size() - 1) && chatMode != MODE_SAVED) { TLRPC.Message dateMsg = new TLRPC.TL_message(); dateMsg.message = ""; dateMsg.id = 0; @@ -16874,6 +17169,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not newRowsCount++; } } + checkGroupMessagesOrder(); if (createUnreadLoading) { createUnreadMessageAfterId = 0; } @@ -17228,17 +17524,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (did == dialog_id && !messages.isEmpty() && currentUser != null && (bottomOverlayStartButton != null && bottomOverlayStartButton.getVisibility() == View.VISIBLE)) { - if (!TextUtils.isEmpty(botUser) && !sentBotStart) { + if (!TextUtils.isEmpty(botUser) && !sentBotStart && chatMode == 0) { sentBotStart = true; getMessagesController().sendBotStart(currentUser, botUser); bottomOverlayChat.setVisibility(View.GONE); - chatActivityEnterView.setVisibility(View.VISIBLE); + if (!isInsideContainer) { + chatActivityEnterView.setVisibility(View.VISIBLE); + } chatActivityEnterView.setBotInfo(botInfo); } } checkNewMessagesOnQuoteEdit(true); + invalidatePremiumBlocked(); } else if (id == NotificationCenter.invalidateMotionBackground) { if (chatListView != null) { chatListView.invalidateViews(); @@ -17357,6 +17656,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (id == NotificationCenter.didReceiveNewMessages) { long did = (Long) args[0]; ArrayList arr = (ArrayList) args[1]; + if (isInsideContainer) return; if (did == dialog_id) { boolean scheduled = (Boolean) args[2]; if (scheduled != (chatMode == MODE_SCHEDULED)) { @@ -17482,7 +17782,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else if (id == NotificationCenter.messagesRead) { - if (chatMode == MODE_SCHEDULED) { + if (chatMode == MODE_SCHEDULED || chatMode == MODE_SAVED) { return; } LongSparseIntArray inbox = (LongSparseIntArray) args[0]; @@ -17627,7 +17927,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } ArrayList markAsDeletedMessages = (ArrayList) args[0]; long channelId = (Long) args[1]; - processDeletedMessages(markAsDeletedMessages, channelId); + boolean sent = args.length > 3 && (boolean) args[3]; + processDeletedMessages(markAsDeletedMessages, channelId, sent); } else if (id == NotificationCenter.messageReceivedByServer) { Boolean scheduled = (Boolean) args[6]; if (scheduled != (chatMode == MODE_SCHEDULED)) { @@ -18107,7 +18408,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (MediaController.getInstance().isPlayingMessage(messageObject1)) { boolean keyboardIsVisible = contentView.getKeyboardHeight() >= AndroidUtilities.dp(20); float topPadding = chatListViewPaddingTop - (contentPanTranslation + bottomPanelTranslationY); - int offset = (int) ((chatListView.getMeasuredHeight() - topPadding - blurredViewBottomOffset) / 2 - (keyboardIsVisible ? AndroidUtilities.roundMessageSize : AndroidUtilities.roundPlayingMessageSize) / 2 - (cell.reactionsLayoutInBubble == null ? 0 : cell.reactionsLayoutInBubble.totalHeight)); + int offset = (int) ((chatListView.getMeasuredHeight() - topPadding - blurredViewBottomOffset) / 2 - (cell.reactionsLayoutInBubble == null ? 0 : cell.reactionsLayoutInBubble.totalHeight)); + if (messageObject1.type != MessageObject.TYPE_ROUND_VIDEO) { + offset -= cell.getPhotoImage().getImageY(); + } else { + offset -= (keyboardIsVisible ? AndroidUtilities.roundMessageSize : AndroidUtilities.roundPlayingMessageSize) / 2; + } chatLayoutManager.scrollToPositionWithOffset(position, offset, false); } chatAdapter.notifyItemChanged(position); @@ -18357,6 +18663,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject messageObject = null; if (idx > 0 && idx < groupedMessages.messages.size() - 1) { MessageObject.GroupedMessages slicedGroup = new MessageObject.GroupedMessages(); + slicedGroup.reversed = reversed; slicedGroup.groupId = Utilities.random.nextLong(); slicedGroup.messages.addAll(groupedMessages.messages.subList(idx + 1, groupedMessages.messages.size())); for (int b = 0; b < slicedGroup.messages.size(); b++) { @@ -18403,7 +18710,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not transcriptionId = (Long) args[1]; transcriptionText = (String) args[2]; } - ArrayList messages = chatAdapter.isFrozen ? chatAdapter.frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (chatAdapter.isFrozen) { + messages = chatAdapter.frozenMessages; + } else if (chatAdapter.isFiltered) { + messages = chatAdapter.filteredMessages; + } else { + messages = ChatActivity.this.messages; + } if (messages != null && !messages.contains(messageObject) && args.length > 1 && args[1] != null) { for (int a = 0; a < messages.size(); ++a) { if (messages.get(a) != null && messages.get(a).messageOwner != null && (messages.get(a).messageOwner.voiceTranscriptionId == transcriptionId || messageObject != null && messageObject.getId() == messages.get(a).getId() && messageObject.getDialogId() == messages.get(a).getDialogId())) { @@ -18451,7 +18765,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatAdapter != null) { MessageObject messageObject = (MessageObject) args[0]; if (messageObject != null) { - ArrayList messages = chatAdapter.isFrozen ? chatAdapter.frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (chatAdapter.isFrozen) { + messages = chatAdapter.frozenMessages; + } else if (chatAdapter.isFiltered) { + messages = chatAdapter.filteredMessages; + } else { + messages = ChatActivity.this.messages; + } int index = messages.indexOf(messageObject); if (index >= 0 && index < messages.size()) { int position = index + chatAdapter.messagesStartRow; @@ -18482,7 +18803,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messagePreviewParams != null) { messagePreviewParams.checkEdits(messageObjects); } - if (did != dialog_id && did != mergeDialogId) { + if (did != dialog_id && did != mergeDialogId || chatMode == MODE_SAVED) { return; } int loadIndex = did == dialog_id ? 0 : 1; @@ -18571,7 +18892,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (object == null && replaceObjects != null) { object = replaceObjects.get(mid); } - if (object != null && (!isTopic || getTopicId() == MessageObject.getTopicId(object.messageOwner, ChatObject.isForum(currentChat)))) { + if (object != null && (!isTopic || getTopicId() == MessageObject.getTopicId(currentAccount, object.messageOwner, ChatObject.isForum(currentChat)))) { pinnedMessageIds.add(mid); pinnedMessageObjects.put(mid, object); if (replaceObjects == null) { @@ -18627,7 +18948,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not processNewMessages(arrayList); } } else { - processDeletedMessages(ids, ChatObject.isChannel(currentChat) ? dialog_id : 0); + processDeletedMessages(ids, ChatObject.isChannel(currentChat) ? dialog_id : 0, false); } } } else { @@ -18794,9 +19115,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (jumpToMessage) { int messageId = (Integer) args[1]; long did = (Long) args[3]; +// if (searchingReaction != null) { +// if (chatAdapter.isFiltered) { +// updateFilteredMessages(); +// } else { +// setFilterMessages(true); +// } +// } else if (messageId != 0) { + setFilterMessages(false); scrollToMessageId(messageId, 0, true, did == dialog_id ? 0 : 1, true, 0); } else { + setFilterMessages(false); updateVisibleRows(); } updateSearchButtons((Integer) args[2], (Integer) args[4], (Integer) args[5]); @@ -18804,6 +19134,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchItem.setShowSearchProgress(false); } } +// else if (searchingReaction != null) { +// if (chatAdapter.isFiltered) { +// updateFilteredMessages(); +// } else { +// setFilterMessages(true); +// } +// } if (messagesSearchAdapter != null) { messagesSearchAdapter.notifyDataSetChanged(); } @@ -18995,7 +19332,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not continue; } - int messageTopicId = MessageObject.getTopicId(messageObject.messageOwner, true); + long messageTopicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true); if (getTopicId() != messageTopicId) { pinnedMessageObjects.remove(messageId); pinnedMessageIds.remove(i); @@ -19019,6 +19356,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Long uid = (Long) args[0]; if (currentUser != null && currentUser.id == uid) { userInfo = (TLRPC.UserFull) args[1]; + if (greetingsViewContainer != null) { + greetingsViewContainer.setPremiumLock(userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium(), dialog_id); + } + updateBottomOverlay(); checkThemeEmoticonOrWallpaper(); if (chatActivityEnterView != null) { chatActivityEnterView.checkChannelRights(); @@ -19131,7 +19472,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.updateMentionsCount) { long dialogId = (Long) args[0]; - int topicId = (Integer) args[1]; + long topicId = (Long) args[1]; if (dialog_id == dialogId && this.getTopicId() == topicId) { int count = (int) args[2]; if (newMentionsCount > count) { @@ -19220,13 +19561,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.chatAvailableReactionsUpdated) { long chatId = (long) args[0]; - int topicId = (int) args[1]; + long topicId = (long) args[1]; if (chatId == -dialog_id && (!isTopic || getTopicId() == topicId)) { chatInfo = getMessagesController().getChatFull(chatId); } } else if (id == NotificationCenter.dialogsUnreadReactionsCounterChanged) { long dialogId = (long) args[0]; - int topicId = (int) args[1]; + long topicId = (long) args[1]; if (dialogId == dialog_id && (!isTopic || topicId == getTopicId())) { reactionsMentionCount = (int) args[2]; ArrayList messages = null; @@ -19422,6 +19763,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + } else if (id == NotificationCenter.savedMessagesDialogsUpdate) { + if (checkedSavedMessagesHint && !savedMessagesHintShown && chatMode == 0 && savedMessagesHint != null && MessagesController.getGlobalMainSettings().getInt("savedhint", 0) < 1 && !getMessagesController().getSavedMessagesController().unsupported && getMessagesController().getSavedMessagesController().getAllCount() > 2) { + savedMessagesHint.show(); + savedMessagesHintShown = true; + MessagesController.getGlobalMainSettings().edit().putInt("savedhint", MessagesController.getGlobalMainSettings().getInt("savedhint", 0) + 1).apply(); + } + + if (avatarContainer != null) { + avatarContainer.updateSubtitle(true); + } + + if (chatMode == MODE_SAVED && !isInsideContainer && getUserConfig().getClientUserId() != getSavedDialogId() && !getMessagesController().getSavedMessagesController().containsDialog(getSavedDialogId())) { + finishFragment(); + } } } @@ -20049,7 +20404,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } int messageId = messageObject.getId(); - if (threadMessageId != 0) { + if (chatMode != MODE_SAVED && threadMessageId != 0) { if (messageId > 0 && messageId <= (messageObject.isOut() ? threadMaxOutboxReadId : threadMaxInboxReadId)) { messageObject.setIsRead(); } @@ -20167,8 +20522,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (obj.isOut()) { rotateMotionBackgroundDrawable(); } - if (threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { - continue; + if (chatMode == MODE_SAVED) { + if (MessageObject.getSavedDialogId(getUserConfig().getClientUserId(), obj.messageOwner) != threadMessageId) { + continue; + } + } else { + if (threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { + continue; + } } int messageId = obj.getId(); @@ -20264,9 +20625,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int lastAdIndex = -1; for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); - if (obj.scheduled != (chatMode == MODE_SCHEDULED) || threadMessageId != 0 && (!ChatObject.isForum(currentChat) || (!isTopic || getTopicId() != MessageObject.getTopicId(obj.messageOwner, ChatObject.isForum(currentChat)))) && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { + if (obj.scheduled != (chatMode == MODE_SCHEDULED)) { continue; } + if (chatMode == MODE_SAVED) { + if (MessageObject.getSavedDialogId(getUserConfig().getClientUserId(), obj.messageOwner) != threadMessageId) { + continue; + } + } else { + if (threadMessageId != 0 && (!ChatObject.isForum(currentChat) || (!isTopic || getTopicId() != MessageObject.getTopicId(currentAccount, obj.messageOwner, ChatObject.isForum(currentChat)))) && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { + continue; + } + } if (obj.isOut() && messagesDict[0].indexOfKey(obj.getId()) < 0) { rotateMotionBackgroundDrawable(); } @@ -20337,6 +20707,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not groupedMessages = groupedMessagesMap.get(obj.getGroupId()); if (groupedMessages == null) { groupedMessages = new MessageObject.GroupedMessages(); + groupedMessages.reversed = reversed; groupedMessages.groupId = obj.getGroupId(); groupedMessagesMap.put(groupedMessages.groupId, groupedMessages); } @@ -20506,7 +20877,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAdapter.notifyItemInserted(placeToPaste); } } - if (!(obj.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (!obj.isOut() || obj.messageOwner.from_scheduled)) { + if (!(obj.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (!obj.isOut() || obj.messageOwner.from_scheduled) && chatMode != MODE_SAVED) { if (paused && placeToPaste == 0) { if (!scrollToTopUnReadOnResume && unreadMessageObject != null) { removeMessageObject(unreadMessageObject); @@ -20586,7 +20957,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not setChatThemeEmoticon(action.emoticon); } if (webpagesToReload != null) { - getMessagesController().reloadWebPages(dialog_id, webpagesToReload, chatMode == MODE_SCHEDULED); + getMessagesController().reloadWebPages(dialog_id, webpagesToReload, chatMode); } if (newGroups != null) { for (int a = 0; a < newGroups.size(); a++) { @@ -20691,6 +21062,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!isAd && notPushedSponsoredMessages != null && !notPushedSponsoredMessages.isEmpty() && arr != notPushedSponsoredMessages) { processNewMessages(notPushedSponsoredMessages); } + invalidatePremiumBlocked(); } private int getStableIdForDateObject(int date) { @@ -20739,9 +21111,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return sponsoredMessagesCount; } - private void processDeletedMessages(ArrayList markAsDeletedMessages, long channelId) { + private void processDeletedMessages(ArrayList markAsDeletedMessages, long channelId, boolean sent) { ArrayList removedIndexes = new ArrayList<>(); - ArrayList messagesIndexes = new ArrayList<>(); + ArrayList thanosMessagesIndexes = new ArrayList<>(); + final int currentTime = getConnectionsManager().getCurrentTime(); int loadIndex = 0; if (ChatObject.isChannel(currentChat)) { if (channelId == 0 && mergeDialogId != 0) { @@ -20826,6 +21199,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } obj.deleted = true; + if (obj.scheduled && sent) { + obj.scheduledSent = true; + } if (editingMessageObject == obj) { hideFieldPanel(true); } @@ -20842,8 +21218,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject removed = messages.remove(index); if (chatAdapter != null) { removedIndexes.add(chatAdapter.messagesStartRow + index); - if (removed != null && removed.messageOwner != null && removed.messageOwner.send_state == MessageObject.MESSAGE_SEND_STATE_SENT) { - messagesIndexes.add(chatAdapter.messagesStartRow + index); + if (!sent && !obj.scheduledSent && removed != null && removed.messageOwner != null && removed.messageOwner.send_state == MessageObject.MESSAGE_SEND_STATE_SENT && currentTime - removed.messageOwner.date >= (currentChat != null || currentUser != null && currentUser.bot ? 2 : 0)) { + thanosMessagesIndexes.add(chatAdapter.messagesStartRow + index); removed.deletedByThanos = LiteMode.isEnabled(LiteMode.FLAG_CHAT_THANOS); } } @@ -20962,7 +21338,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int prevLoadingDownRow = chatAdapter.loadingDownRow; for (int a = 0, N = removedIndexes.size(); a < N; a++) { final int pos = removedIndexes.get(a); - chatAdapter.notifyItemRemoved(pos, messagesIndexes.contains(pos)); + chatAdapter.notifyItemRemoved(pos, thanosMessagesIndexes.contains(pos)); } if (!isThreadChat() || messages.size() <= 3) { removeUnreadPlane(false); @@ -20989,6 +21365,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (updateScheduled) { updateScheduledInterface(true); } + invalidatePremiumBlocked(); } private void replaceMessageObjects(ArrayList messageObjects, int loadIndex, boolean remove) { @@ -21088,6 +21465,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not newGroups.put(groupedMessages.groupId, groupedMessages); if (idx > 0 && idx < groupedMessages.messages.size() - 1) { MessageObject.GroupedMessages slicedGroup = new MessageObject.GroupedMessages(); + slicedGroup.reversed = reversed; slicedGroup.groupId = Utilities.random.nextLong(); slicedGroup.messages.addAll(groupedMessages.messages.subList(idx + 1, groupedMessages.messages.size())); for (int b = 0; b < slicedGroup.messages.size(); b++) { @@ -21112,6 +21490,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + if (chatMode == MODE_SAVED) { + messageObject.isSaved = true; + } if (messageObject.type >= 0) { messageObject.copyStableParams(old); messages.set(index, messageObject); @@ -21324,6 +21705,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } keyboardWasVisible = false; } + if (savedMessagesHint != null) { + AndroidUtilities.runOnUIThread(this::checkSavedMessagesHint, 600); + } + } + + private boolean checkedSavedMessagesHint; + private boolean savedMessagesHintShown; + private void checkSavedMessagesHint() { + if (checkedSavedMessagesHint) + return; + checkedSavedMessagesHint = true; + if (!savedMessagesHintShown && savedMessagesHint != null && chatMode == 0 && MessagesController.getGlobalMainSettings().getInt("savedhint", 0) < 1 && !getMessagesController().getSavedMessagesController().unsupported && getMessagesController().getSavedMessagesController().getAllCount() > 2) { + savedMessagesHint.show(); + savedMessagesHintShown = true; + MessagesController.getGlobalMainSettings().edit().putInt("savedhint", MessagesController.getGlobalMainSettings().getInt("savedhint", 0) + 1).apply(); + } } @Override @@ -21733,7 +22130,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } bottomOverlayChatWaitsReply = false; - if (reportType >= 0) { + bottomOverlayLinks = false; + if (chatMode == MODE_DEFAULT && userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium()) { + bottomOverlayLinks = true; + bottomOverlayChatText.setVisibility(View.GONE); + bottomOverlayLinksText.setVisibility(View.VISIBLE); + bottomOverlayLinksText.setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.OnlyPremiumCanMessage, UserObject.getFirstName(currentUser)), Theme.key_chat_messageLinkIn, 0, () -> { + ChatGreetingsView.showPremiumSheet(getContext(), currentAccount, dialog_id, themeDelegate); + })); + showBottomOverlayProgress(false, false); + } else if (chatMode == MODE_SAVED && getSavedDialogId() != getUserConfig().getClientUserId()) { + if (getSavedDialogId() == UserObject.ANONYMOUS) { + bottomOverlayChat.setVisibility(View.GONE); + chatActivityEnterView.setVisibility(View.INVISIBLE); + return; + } else { + bottomOverlayChatText.setTag(null); + bottomOverlayChatText.setText(LocaleController.getString(currentUser != null ? R.string.SavedOpenChat : (ChatObject.isChannelAndNotMegaGroup(currentChat) ? R.string.SavedOpenChannel : R.string.SavedOpenGroup))); + showBottomOverlayProgress(false, false); + } + } else if (reportType >= 0) { updateActionModeTitle(); } else if (chatMode == MODE_PINNED) { boolean allowPin; @@ -21864,13 +22280,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { bottomOverlayImage.setVisibility(View.INVISIBLE); } - if (inPreviewMode) { + if (inPreviewMode || isInsideContainer) { if (searchContainer != null) { searchContainer.setVisibility(View.INVISIBLE); } bottomOverlayChat.setVisibility(View.INVISIBLE); chatActivityEnterView.setFieldFocused(false); chatActivityEnterView.setVisibility(View.INVISIBLE); + } else if (bottomOverlayLinks) { + bottomOverlayChat.setVisibility(View.VISIBLE); + chatActivityEnterView.setVisibility(View.INVISIBLE); } else if (searchItem != null && searchItemVisible) { createSearchContainer(); if (searchContainer == null) { @@ -22010,7 +22429,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not headerItem.setVisibility(View.VISIBLE); } } else { - if (botUser != null && currentUser.bot) { + if (botUser != null && currentUser.bot || chatMode == MODE_SAVED && getSavedDialogId() != getUserConfig().getClientUserId()) { bottomOverlayChat.setVisibility(View.VISIBLE); chatActivityEnterView.setVisibility(View.INVISIBLE); } else { @@ -22039,7 +22458,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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)); + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, MessageObject.getTopicId(currentAccount, message.messageOwner, true)); return canSendMessageToTopic(topic); } return false; @@ -22058,16 +22477,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public void updateReplyMessageHeader(boolean notify) { + if (chatMode == MODE_SAVED) { + return; + } if (avatarContainer != null && threadMessageId != 0) { if (isTopic) { updateTopicHeader(); } else if (isComments) { - if (threadMessageObject.hasReplies()) { + if (threadMessageObject != null && threadMessageObject.hasReplies()) { avatarContainer.setTitle(LocaleController.formatPluralString("Comments", threadMessageObject.getRepliesCount())); } else { avatarContainer.setTitle(LocaleController.getString("CommentsTitle", R.string.CommentsTitle)); } - } else { + } else if (threadMessageObject != null) { avatarContainer.setTitle(LocaleController.formatPluralString("Replies", threadMessageObject.getRepliesCount())); } } @@ -22400,7 +22822,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (isThreadChat() && !isTopic) { if (!threadMessageVisible) { pinnedMessageObject = threadMessageObject; - pinned_msg_id = threadMessageId; + pinned_msg_id = (int) threadMessageId; } else { pinnedMessageObject = null; pinned_msg_id = 0; @@ -22985,23 +23407,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedNextAnimation[1].start(); } } else { - if (!showCounter || currentPinnedMessageIndex[0] == 0) { - if (pinnedCounterTextView.getTag() == null) { - pinnedCounterTextView.setAlpha(0.0f); - pinnedCounterTextView.setVisibility(View.INVISIBLE); - pinnedCounterTextView.setTag(1); - } - } else { - if (pinnedCounterTextView.getTag() != null) { - pinnedCounterTextView.setVisibility(View.VISIBLE); - pinnedCounterTextView.setAlpha(1.0f); - pinnedCounterTextView.setTag(null); + if (pinnedCounterTextView != null) { + if (!showCounter || currentPinnedMessageIndex[0] == 0) { + if (pinnedCounterTextView.getTag() == null) { + pinnedCounterTextView.setAlpha(0.0f); + pinnedCounterTextView.setVisibility(View.INVISIBLE); + pinnedCounterTextView.setTag(1); + } + } else { + if (pinnedCounterTextView.getTag() != null) { + pinnedCounterTextView.setVisibility(View.VISIBLE); + pinnedCounterTextView.setAlpha(1.0f); + pinnedCounterTextView.setTag(null); + } } + pinnedCounterTextView.setTranslationY(0.0f); + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + pinnedCounterTextView.setAlpha(shouldAnimateName || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); } - pinnedCounterTextView.setTranslationY(0.0f); - pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); - - pinnedCounterTextView.setAlpha(shouldAnimateName || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); messageTextView.setVisibility(View.VISIBLE); messageTextView.setAlpha(1.0f); @@ -23024,14 +23447,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not BackupImageView backupImageView = pinnedMessageImageView[1]; pinnedMessageImageView[1] = pinnedMessageImageView[0]; pinnedMessageImageView[0] = backupImageView; - pinnedMessageImageView[0].setAlpha(1.0f); - pinnedMessageImageView[0].setScaleX(1f); - pinnedMessageImageView[0].setScaleY(1f); - pinnedMessageImageView[0].setTranslationY(0); - pinnedMessageImageView[1].setAlpha(1.0f); - pinnedMessageImageView[1].setScaleX(1f); - pinnedMessageImageView[1].setScaleY(1f); - pinnedMessageImageView[1].setTranslationY(0); + if (pinnedMessageImageView[0] != null) { + pinnedMessageImageView[0].setAlpha(1.0f); + pinnedMessageImageView[0].setScaleX(1f); + pinnedMessageImageView[0].setScaleY(1f); + pinnedMessageImageView[0].setTranslationY(0); + } + if (pinnedMessageImageView[1] != null) { + pinnedMessageImageView[1].setAlpha(1.0f); + pinnedMessageImageView[1].setScaleX(1f); + pinnedMessageImageView[1].setScaleY(1f); + pinnedMessageImageView[1].setTranslationY(0); + } } if (isThreadChat() && !isTopic) { pinnedLineView.set(0, 1, false); @@ -23040,8 +23467,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedLineView.set(pinnedMessageIds.size() - 1 - position, pinnedMessageIds.size(), animated); } } else { - pinnedCounterTextView.setVisibility(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? View.INVISIBLE : View.VISIBLE); - pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); + if (pinnedCounterTextView != null) { + pinnedCounterTextView.setVisibility(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? View.INVISIBLE : View.VISIBLE); + pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); + } pinnedImageLocation = null; pinnedImageLocationObject = null; changed = hidePinnedMessageView(animated); @@ -23615,10 +24044,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateSecretStatus(); if (fragmentContextView != null) { - fragmentContextView.setEnabled(!value); + fragmentContextView.setEnabled(!value && !isInsideContainer); } if (fragmentLocationContextView != null) { - fragmentLocationContextView.setEnabled(!value); + fragmentLocationContextView.setEnabled(!value && !isInsideContainer); } if (pinnedMessageView != null) { pinnedMessageView.setEnabled(!isInPreviewMode()); @@ -23667,8 +24096,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { height = chatActivityEnterView.getHeight(); } - } else { + } else if (!isInsideContainer) { height = AndroidUtilities.dp(51); + } else { + height = 0; } if (chatActivityEnterView.panelAnimationInProgress()) { float translationY = bottomPanelTranslationY - chatActivityEnterView.getEmojiPadding(); @@ -23802,7 +24233,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scrimPopupWindow.setPauseNotifications(false); closeMenu(); } - int replyId = threadMessageId; + long replyId = threadMessageId; getMessagesController().markDialogAsReadNow(dialog_id, replyId); MediaController.getInstance().stopRaiseToEarSensors(this, true, true); paused = true; @@ -23835,12 +24266,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatMode == 0) { CharSequence[] message = new CharSequence[]{ignoreDraft ? null : draftMessage}; ArrayList entities = getMediaDataController().getEntities(message, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101); - int draftThreadId; + long draftThreadId; if (ChatObject.isForum(currentChat) && !isTopic && replyMessage != null) { if (replyMessage.replyToForumTopic != null) { draftThreadId = replyMessage.replyToForumTopic.id; } else { - draftThreadId = MessageObject.getTopicId(replyMessage.messageOwner, ChatObject.isForum(currentChat)); + draftThreadId = MessageObject.getTopicId(currentAccount, replyMessage.messageOwner, ChatObject.isForum(currentChat)); } } else { draftThreadId = threadMessageId; @@ -23945,9 +24376,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } TLRPC.DraftMessage draftMessage = null; - Integer topicId = null; + Long topicId = null; if (isForumInViewAsMessagesMode()) { - Pair pair = getMediaDataController().getOneThreadDraft(dialog_id); + Pair pair = getMediaDataController().getOneThreadDraft(dialog_id); if (pair != null) { topicId = pair.first; draftMessage = pair.second; @@ -24203,6 +24634,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ChatMessageCell messageCell = (ChatMessageCell) child; MessageObject messageObject = messageCell.getMessageObject(); boolean isRoundVideo = messageObject.isRoundVideo(); + if (messageObject.isRoundOnce() || messageObject.isVoiceOnce()) { + continue; + } if ((!messageObject.isVideo() && !isRoundVideo) || messageObject.videoEditedInfo != null) { continue; } @@ -24294,7 +24728,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (finalSelectedObject == null && (selectedMessagesIds[0].size() + selectedMessagesIds[1].size()) == 0) { return; } - AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, chatMode == MODE_SCHEDULED, loadParticipant, () -> { + AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, chatMode == MODE_SCHEDULED, chatMode == MODE_SAVED, loadParticipant, () -> { hideActionMode(); updatePinnedMessageView(true); }, hideDimAfter ? () -> dimBehindView(false) : null, themeDelegate); @@ -24491,7 +24925,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean allowChatActions = true; boolean allowPin; - if (chatMode == MODE_SCHEDULED || (isThreadChat() && !isTopic)) { + if (chatMode == MODE_SAVED) { + allowPin = false; + } else if (chatMode == MODE_SCHEDULED || (isThreadChat() && !isTopic)) { allowPin = false; } else if (currentChat != null) { allowPin = message.getDialogId() != mergeDialogId && ChatObject.canPinMessages(currentChat); @@ -24527,7 +24963,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not message.isSponsored() || type == 1 && message.getDialogId() == mergeDialogId || message.messageOwner.action instanceof TLRPC.TL_messageActionSecureValuesSent || currentEncryptedChat == null && message.getId() < 0 || - bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE && !(bottomOverlayChatWaitsReply && selectedObject != null && (MessageObject.getTopicId(selectedObject.messageOwner, ChatObject.isForum(currentChat)) != 0 || selectedObject.wasJustSent)) || + bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE && !(bottomOverlayChatWaitsReply && selectedObject != null && (MessageObject.getTopicId(currentAccount, selectedObject.messageOwner, ChatObject.isForum(currentChat)) != 0 || selectedObject.wasJustSent)) || currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat))) { allowChatActions = false; } @@ -24541,13 +24977,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final ArrayList options = new ArrayList<>(); View optionsView = null; - if (AndroidUtilities.isAccessibilityScreenReaderEnabled() && message.messageOwner != null && message.messageOwner.from_id != null && message.messageOwner.from_id.user_id != getUserConfig().clientUserId) { + if (AndroidUtilities.isAccessibilityScreenReaderEnabled() && message.messageOwner != null && message.messageOwner.from_id != null && message.messageOwner.from_id.user_id != getUserConfig().clientUserId && chatMode != MODE_SAVED) { items.add(LocaleController.getString(R.string.OpenProfile)); options.add(OPTION_OPEN_PROFILE); icons.add(R.drawable.msg_user_search); } - if (!getUserConfig().isPremium() && !getMessagesController().premiumFeaturesBlocked() && message.getDocument() != null && message.getDocument().size >= 150 * 1024 * 1024 && FileLoader.getInstance(currentAccount).isLoadingFile(FileLoader.getAttachFileName(message.getDocument()))) { + if (!getUserConfig().isPremium() && !getMessagesController().premiumFeaturesBlocked() && message.getDocument() != null && message.getDocument().size >= 150 * 1024 * 1024 && FileLoader.getInstance(currentAccount).isLoadingFile(FileLoader.getAttachFileName(message.getDocument())) && chatMode != MODE_SAVED) { items.add(LocaleController.getString(R.string.PremiumSpeedPromo)); options.add(OPTION_SPEED_PROMO); icons.add(R.drawable.msg_speed); @@ -24644,7 +25080,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(selectedObject.messageOwner.ttl_period != 0 ? R.drawable.msg_delete_auto : R.drawable.msg_delete); } else if (type == 1) { if (currentChat != null) { - if (allowChatActions) { + if (allowChatActions && !isInsideContainer) { items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(OPTION_REPLY); icons.add(R.drawable.msg_reply); @@ -24684,7 +25120,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.msg_report); } } else { - if (selectedObject.getId() > 0 && allowChatActions) { + if (selectedObject.getId() > 0 && allowChatActions && !isInsideContainer) { items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(OPTION_REPLY); icons.add(R.drawable.msg_reply); @@ -24725,7 +25161,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.msg_fave); } } - if (allowChatActions || !noforwards && ChatObject.isChannelAndNotMegaGroup(currentChat) && !selectedObject.isSponsored() && selectedObject.contentType == 0 && chatMode == MODE_DEFAULT) { + if ((allowChatActions || !noforwards && ChatObject.isChannelAndNotMegaGroup(currentChat) && !selectedObject.isSponsored() && selectedObject.contentType == 0 && chatMode == MODE_DEFAULT) && !isInsideContainer) { items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(OPTION_REPLY); icons.add(R.drawable.msg_reply); @@ -24969,7 +25405,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(selectedObject.messageOwner.ttl_period != 0 ? R.drawable.msg_delete_auto : R.drawable.msg_delete); } } else { - if (allowChatActions) { + if (allowChatActions && !isInsideContainer) { items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(OPTION_REPLY); icons.add(R.drawable.msg_reply); @@ -25090,8 +25526,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { 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 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 showPrivateMessageSeen = !isReactionsViewAvailable && currentChat == null && currentEncryptedChat == null && (currentUser != null && !UserObject.isUserSelf(currentUser) && !UserObject.isReplyUser(currentUser) && !UserObject.isAnonymous(currentUser) && !currentUser.bot && !UserObject.isService(currentUser.id)) && (userInfo == null || !userInfo.read_dates_private) && !isInScheduleMode() && message.isOutOwner() && message.isSent() && !message.isEditing() && !message.isSending() && !message.isSendError() && !message.isContentUnread() && !message.isUnread() && (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - message.messageOwner.date < getMessagesController().pmReadDateExpirePeriod) && !(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.sponsoredBotApp != null); + if (chatMode == MODE_SAVED) { + showMessageSeen = false; + } + final boolean isReactionsAvailableFinal = isReactionsAvailable; int flags = 0; if (isReactionsViewAvailable || showMessageSeen || showSponsorInfo) { @@ -25435,6 +25876,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not popupLayout.addView(messageSeenLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 44)); addGap = true; + } else if (showPrivateMessageSeen) { + MessagePrivateSeenView messagePrivateSeenView = new MessagePrivateSeenView(getContext(), message, () -> { + if (scrimPopupWindow != null) { + scrimPopupWindow.dismiss(false); + scrimPopupWindow = null; + } + }, themeDelegate); + popupLayout.addView(messagePrivateSeenView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36)); + addGap = true; } boolean showRateTranscription = selectedObject != null && selectedObject.isVoice() && selectedObject.messageOwner != null && getUserConfig().isPremium() && !TextUtils.isEmpty(selectedObject.messageOwner.voiceTranscription) && selectedObject.messageOwner != null && !selectedObject.messageOwner.voiceTranscriptionRated && selectedObject.messageOwner.voiceTranscriptionId != 0 && selectedObject.messageOwner.voiceTranscriptionOpen; @@ -25940,7 +26390,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED; + boolean showNoForwards = noforwards && message.messageOwner.action == null && message.isSent() && !message.isEditing() && chatMode != MODE_SCHEDULED && chatMode != MODE_SAVED; scrimPopupContainerLayout.addView(popupLayout, LayoutHelper.createLinearRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, isReactionsAvailable ? 16 : 0, 0, isReactionsAvailable ? 36 : 0, 0)); scrimPopupContainerLayout.setPopupWindowLayout(popupLayout); if (showNoForwards) { @@ -26113,7 +26563,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } scrimPopupWindow.showAtLocation(chatListView, Gravity.LEFT | Gravity.TOP, finalPopupX, finalPopupY); - if (isReactionsAvailable && finalReactionsLayout != null) { + if (isReactionsAvailableFinal && finalReactionsLayout != null) { finalReactionsLayout.startEnterAnimation(true); } AndroidUtilities.runOnUIThread(() -> { @@ -26227,14 +26677,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.addView(emptyViewContainer, 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); int distance = getArguments().getInt("nearby_distance", -1); - if ((distance >= 0 || preloadedGreetingsSticker != null) && currentUser != null && !userBlocked) { + if ((distance >= 0 || preloadedGreetingsSticker != null) && currentUser != null && !userBlocked || userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium()) { greetingsViewContainer = new ChatGreetingsView(getContext(), currentUser, distance, currentAccount, preloadedGreetingsSticker, themeDelegate); + greetingsViewContainer.setPremiumLock(userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium(), dialog_id); greetingsViewContainer.setListener((sticker) -> { animatingDocuments.put(sticker, 0); SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null); }); greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(10), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); - emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 68, 0, 68, 0)); + emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else if (currentEncryptedChat == null) { if (isTopic && chatMode == 0) { CreateTopicEmptyView createTopicEmptyView = new CreateTopicEmptyView(getContext(), contentView, themeDelegate); @@ -26262,12 +26713,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (emptyMessage == null) { greetingsViewContainer = new ChatGreetingsView(getContext(), currentUser, distance, currentAccount, preloadedGreetingsSticker, themeDelegate); + greetingsViewContainer.setPremiumLock(userInfo != null && userInfo.contact_require_premium && !getUserConfig().isPremium(), dialog_id); greetingsViewContainer.setListener((sticker) -> { animatingDocuments.put(sticker, 0); SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, null, dialog_id, null, null, null, replyingQuote, null, true, 0, false, null); }); - greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(10), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); - emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 68, 0, 68, 0)); + greetingsViewContainer.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(16), greetingsViewContainer, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); + emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else { emptyView = new TextView(getContext()); emptyView.setText(emptyMessage); @@ -27283,7 +27735,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } case OPTION_VIEW_IN_TOPIC: { - int topicId = MessageObject.getTopicId(selectedObject.messageOwner, true); + long topicId = MessageObject.getTopicId(currentAccount, selectedObject.messageOwner, true); if (topicId != 0) { TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); if (topic != null) { @@ -27314,7 +27766,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (error == null) { TLRPC.Updates updates = (TLRPC.Updates) response; getMessagesController().processUpdates(updates, false); - AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, req.id, -dialog_id, true, dialog_id)); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messagesDeleted, req.id, getUserConfig().getClientUserId() == dialog_id ? 0 : -dialog_id, true, true)); } else if (error.text != null) { AndroidUtilities.runOnUIThread(() -> { if (error.text.startsWith("SLOWMODE_WAIT_")) { @@ -27599,6 +28051,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not parentLayout.addFragmentToStack(backToPreviousFragment, parentLayout.getFragmentStack().size() - 1); backToPreviousFragment = null; } + if (instantCameraView != null) { + instantCameraView.cancel(false); + } return true; } @@ -27624,6 +28079,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragmentView.invalidate(); } } + + public void setSavedDialog(long savedDialogId) { + threadMessageId = savedDialogId; + } public void setThreadMessages(ArrayList messageObjects, TLRPC.Chat originalChat, int originalMessage, int maxInboxReadId, int maxOutboxReadId, TLRPC.TL_forumTopic forumTopic) { this.forumTopic = forumTopic; @@ -27835,7 +28294,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (editTextItem != null) { editTextItem.setVisibility(View.GONE); } - if (threadMessageId == 0 && searchItem != null) { + if ((threadMessageId == 0 || chatMode == MODE_SAVED) && searchItem != null) { searchItem.setVisibility(View.VISIBLE); } if (searchIconItem != null && showSearchAsIcon) { @@ -27848,7 +28307,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateSearchButtons(0, 0, -1); updateBottomOverlay(); } - if ((threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser)) { + if ((threadMessageId == 0 || isTopic || chatMode == MODE_SAVED) && !UserObject.isReplyUser(currentUser)) { openSearchKeyboard = text == null; if (searchItem != null) { searchItem.openSearch(openSearchKeyboard); @@ -27858,7 +28317,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (searchItem != null) { searchItem.setSearchFieldText(text, false); } - getMediaDataController().searchMessagesInChat(text, dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); + getMediaDataController().searchMessagesInChat(text, dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); } updatePinnedMessageView(true); } @@ -27916,7 +28375,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return replyingQuote; } - public int getThreadId() { + public long getThreadId() { return threadMessageId; } @@ -29059,6 +29518,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public boolean isFrozen; public ArrayList frozenMessages = new ArrayList<>(); + public boolean isFiltered; + public boolean filteredEndReached; + public ArrayList filteredMessages = new ArrayList<>(); + public ChatActivityAdapter(Context context) { mContext = context; isBot = currentUser != null && currentUser.bot; @@ -29082,9 +29545,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void updateRowsInternal() { rowCount = 0; - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } if (!messages.isEmpty()) { - if ((!forwardEndReached[0] || mergeDialogId != 0 && !forwardEndReached[1]) && !hideForwardEndReached) { + if (!isFiltered && (!forwardEndReached[0] || mergeDialogId != 0 && !forwardEndReached[1]) && !hideForwardEndReached) { loadingDownRow = rowCount++; } else { loadingDownRow = -5; @@ -29099,7 +29569,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not botInfoRow = -5; } - if ((!endReached[0] || mergeDialogId != 0 && !endReached[1]) && !(DISABLE_PROGRESS_VIEW && !AndroidUtilities.isTablet() && !isComments && currentUser == null)) { + if (isFiltered ? !filteredEndReached : (!endReached[0] || mergeDialogId != 0 && !endReached[1]) && !(DISABLE_PROGRESS_VIEW && !AndroidUtilities.isTablet() && !isComments && currentUser == null)) { loadingUpRow = rowCount++; } else { loadingUpRow = -5; @@ -29128,7 +29598,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return 0; } - return clearingHistory ? 0 : rowCount; + return rowCount; } @Override @@ -29138,7 +29608,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 1; } } - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } if (position >= messagesStartRow && position < messagesEndRow) { return messages.get(position - messagesStartRow).stableId; @@ -29385,7 +29862,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public int getTopicId() { + public long getTopicId() { return ChatActivity.this.getTopicId(); } @@ -29467,7 +29944,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ChatLoadingCell loadingCell = (ChatLoadingCell) holder.itemView; loadingCell.setProgressVisible(loadsCount > 1); } else if (position >= messagesStartRow && position < messagesEndRow) { - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } MessageObject message = messages.get(position - messagesStartRow); View view = holder.itemView; @@ -29476,6 +29960,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final ChatMessageCell messageCell = (ChatMessageCell) view; MessageObject.GroupedMessages groupedMessages = getValidGroupedMessage(message); messageCell.isChat = currentChat != null || UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser); + messageCell.isSavedChat = chatMode == MODE_SAVED; + messageCell.isSavedPreviewChat = chatMode == MODE_SAVED && isInsideContainer; messageCell.isBot = currentUser != null && currentUser.bot; messageCell.isMegagroup = ChatObject.isChannel(currentChat) && currentChat.megagroup; messageCell.isForum = ChatObject.isForum(currentChat); @@ -29501,14 +29987,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not nextPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); } else { if ((pos.flags & MessageObject.POSITION_FLAG_TOP) != 0) { - prevPosition = position + groupedMessages.posArray.indexOf(pos) + 1; + if (groupedMessages.reversed) { + prevPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); + } else { + prevPosition = position + groupedMessages.posArray.indexOf(pos) + 1; + } } else { pinnedTop = true; pinnedTopByGroup = true; prevPosition = -100; } if ((pos.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { - nextPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); + if (groupedMessages.reversed) { + nextPosition = position + groupedMessages.posArray.indexOf(pos) + 1; + } else { + nextPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); + } } else { pinnedBottom = true; pinnedBottomByGroup = true; @@ -29588,8 +30082,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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; + long topicId = message.replyToForumTopic == null ? MessageObject.getTopicId(currentAccount, message.messageOwner, true) : message.replyToForumTopic.id; + long prevTopicId = prevMessage.replyToForumTopic == null ? MessageObject.getTopicId(currentAccount, prevMessage.messageOwner, true) : prevMessage.replyToForumTopic.id; if (topicId != prevTopicId) { pinnedTop = false; } @@ -29618,6 +30112,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not groupedMessages.messages.get(i).updateTranslation(false); } } + if (reversed) { + if (groupedMessages != null) { + pinnedTop = false; + pinnedBottom = false; + } else { + boolean wasPinnedTop = pinnedTop; + pinnedTop = pinnedBottom; + pinnedBottom = wasPinnedTop; + } + } messageCell.setMessageObject(message, groupedMessages, pinnedBottom, pinnedTop); messageCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); @@ -29680,8 +30184,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not o.setInterpolator(CubicBezierInterpolator.DEFAULT); allAnimators.playTogether(o, animatorSet); - allAnimators.setStartDelay(120); - allAnimators.setDuration(180); +// allAnimators.setStartDelay(120); + allAnimators.setDuration(300); if (instantCameraView != null) { instantCameraView.setIsMessageTransition(true); @@ -29855,6 +30359,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListItemAnimator.onGreetingStickerTransition(holder, greetingsViewContainer); } } + if (messageCell.makeVisibleAfterChange) { + messageCell.makeVisibleAfterChange = false; + messageCell.setVisibility(View.VISIBLE); + } } else if (view instanceof ChatActionCell) { ChatActionCell actionCell = (ChatActionCell) view; actionCell.setMessageObject(message); @@ -29878,7 +30386,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (position >= messagesStartRow && position < messagesEndRow) { - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } return messages.get(position - messagesStartRow).contentType; } else if (position == botInfoRow) { return 3; @@ -29961,7 +30476,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int position = holder.getAdapterPosition(); if (position >= messagesStartRow && position < messagesEndRow) { - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } MessageObject message = messages.get(position - messagesStartRow); View view = holder.itemView; @@ -29993,7 +30515,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public void updateRowAtPosition(int index) { - if (chatLayoutManager == null || isFrozen) { + if (chatLayoutManager == null || isFrozen || isFiltered) { return; } int lastVisibleItem = RecyclerView.NO_POSITION; @@ -30047,7 +30569,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - ArrayList messages = isFrozen ? frozenMessages : ChatActivity.this.messages; + final ArrayList messages; + if (isFrozen) { + messages = frozenMessages; + } else if (isFiltered) { + messages = filteredMessages; + } else { + messages = ChatActivity.this.messages; + } int index = messages.indexOf(messageObject); if (index == -1) { @@ -30260,6 +30789,43 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private float actionBarTagsT; + private ValueAnimator actionBarTagsAnimator; + private void showActionBarSearchTags(boolean show) { + if (actionBarSearchTags == null) return; + if (actionBarTagsAnimator != null) { + actionBarTagsAnimator.cancel(); + } + actionBarSearchTags.setVisibility(View.VISIBLE); + actionBarTagsAnimator = ValueAnimator.ofFloat(actionBarTagsT, show ? 1f : 0f); + actionBarTagsAnimator.addUpdateListener(valueAnimator1 -> { + actionBarTagsT = (float) valueAnimator1.getAnimatedValue(); + if (actionBarSearchTags != null) { + actionBarSearchTags.setBackgroundColor(actionBar.getBackgroundColor()); + actionBarSearchTags.setShown(actionBarTagsT); + } + }); + actionBarTagsAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + actionBarTagsAnimator.setDuration(320); + actionBarTagsAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + actionBarTagsT = show ? 1f : 0f; + if (actionBarSearchTags != null) { + actionBarSearchTags.setBackgroundColor(actionBar.getBackgroundColor()); + actionBarSearchTags.setShown(actionBarTagsT); + if (!show) { + actionBarSearchTags.setVisibility(View.GONE); + } + } + + invalidateChatListViewTopPadding = true; + updateChatListViewTopPadding(); + } + }); + actionBarTagsAnimator.start(); + } + private class SearchItemListener extends ActionBarMenuItem.ActionBarMenuItemSearchListener { boolean searchWas; @@ -30273,6 +30839,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } + @Override + public void onSearchFilterCleared(FiltersView.MediaFilterData filterData) { + super.onSearchFilterCleared(filterData); + if (actionBarSearchTags != null) { + actionBarSearchTags.clear(); + } + searchingReaction = null; + showSearchShowOther(false); + setFilterMessages(false); + } + @Override public void onSearchCollapse() { if (searchCalendarButton != null) { @@ -30342,7 +30919,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not attachItem.setVisibility(View.GONE); } } - if (threadMessageId == 0 && !UserObject.isReplyUser(currentUser) || threadMessageObject != null && threadMessageObject.getRepliesCount() < 10) { + if (chatMode == MODE_SAVED || threadMessageId == 0 && !UserObject.isReplyUser(currentUser) || threadMessageObject != null && threadMessageObject.getRepliesCount() < 10) { searchItem.setVisibility(View.GONE); } searchItemVisible = false; @@ -30354,6 +30931,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateBottomOverlay(); updatePinnedMessageView(true); updateVisibleRows(); + + whiteActionBar = getDialogId() == getUserConfig().getClientUserId(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(searchAnimationProgress, 0f); + valueAnimator.addUpdateListener(valueAnimator1 -> setSearchAnimationProgress((float) valueAnimator1.getAnimatedValue())); + valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + valueAnimator.setDuration(320); + valueAnimator.start(); + + searchingReaction = null; + showSearchShowOther(false); + if (actionBarSearchTags != null) { + actionBarSearchTags.clear(); + } + showActionBarSearchTags(false); + setFilterMessages(false); } @Override @@ -30373,13 +30965,46 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not removeKeyboardPositionBeforeTransition(); }, 500); hideSendButtonHints(); + + whiteActionBar = getDialogId() == getUserConfig().getClientUserId(); + ValueAnimator valueAnimator = ValueAnimator.ofFloat(searchAnimationProgress, 1f); + valueAnimator.addUpdateListener(valueAnimator1 -> setSearchAnimationProgress((float) valueAnimator1.getAnimatedValue())); + valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + valueAnimator.setDuration(320); + valueAnimator.start(); +// showActionBarSearchTags(actionBarSearchTags != null && actionBarSearchTags.hasFilters()); + } + + private float searchAnimationProgress; + private boolean whiteActionBar; + + public void setSearchAnimationProgress(float progress) { + searchAnimationProgress = progress; + if (whiteActionBar) { + int color1 = getThemedColor(Theme.key_actionBarDefaultIcon); + actionBar.setItemsColor(ColorUtils.blendARGB(color1, getThemedColor(Theme.key_actionBarActionModeDefaultIcon), searchAnimationProgress), false); + actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarActionModeDefaultIcon), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), searchAnimationProgress), true); + + color1 = getThemedColor(Theme.key_actionBarDefaultSelector); + int color2 = getThemedColor(Theme.key_actionBarActionModeDefaultSelector); + actionBar.setItemsBackgroundColor(ColorUtils.blendARGB(color1, color2, searchAnimationProgress), false); + + actionBar.setBackgroundColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefault), getThemedColor(Theme.key_actionBarActionModeDefault), searchAnimationProgress)); + actionBar.setSearchTextColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultSearch), getThemedColor(Theme.key_windowBackgroundWhiteBlackText), searchAnimationProgress), false); + actionBar.setSearchTextColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultSearchPlaceholder), getThemedColor(Theme.key_windowBackgroundWhiteGrayText), searchAnimationProgress), true); + actionBar.setSearchCursorColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultSearch), getThemedColor(Theme.key_windowBackgroundWhiteBlueText), searchAnimationProgress)); + AndroidUtilities.setLightStatusBar(fragmentView, isLightStatusBar()); + } + if (fragmentView != null) { + fragmentView.invalidate(); + } } @Override public void onSearchPressed(EditText editText) { searchWas = true; updateSearchButtons(0, 0, -1); - getMediaDataController().searchMessagesInChat(editText.getText().toString(), dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); + getMediaDataController().searchMessagesInChat(editText.getText().toString(), dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages, searchingReaction); } @Override @@ -30510,7 +31135,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatMode == MODE_PINNED) { chatActivityDelegate.openReplyMessage(messageObject.getId()); finishFragment(); - } else if ((UserObject.isReplyUser(currentUser) || UserObject.isUserSelf(currentUser)) && messageObject.messageOwner.fwd_from.saved_from_peer != null) { + } else if (chatMode == MODE_SAVED || (UserObject.isReplyUser(currentUser) || UserObject.isUserSelf(currentUser)) && messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.saved_from_peer != null) { if (UserObject.isReplyUser(currentUser) && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_to_top_id != 0) { openDiscussionMessageChat(messageObject.messageOwner.reply_to.reply_to_peer_id.channel_id, null, messageObject.messageOwner.reply_to.reply_to_top_id, 0, -1, messageObject.messageOwner.fwd_from.saved_from_msg_id, messageObject); } else { @@ -30604,7 +31229,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { - if (messageObject.isVoiceOnce()) { + if (messageObject.isVoiceOnce() || messageObject.isRoundOnce()) { if (secretVoicePlayer != null && secretVoicePlayer.isShown()) return false; try { AudioManager audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE); @@ -31353,7 +31978,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void didPressTopicButton(ChatMessageCell cell) { MessageObject message = cell.getMessageObject(); if (message != null) { - int topicId = MessageObject.getTopicId(message.messageOwner, true); + long topicId = MessageObject.getTopicId(message.currentAccount, message.messageOwner, true); if (topicId != 0) { TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); if (topic != null) { @@ -31758,13 +32383,47 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArticleViewer.getInstance().setParentActivity(getParentActivity(), ChatActivity.this); ArticleViewer.getInstance().open(messageObject); } - } else if (type == 5) { + } else if (type == ChatMessageCell.INSTANT_BUTTON_TYPE_CONTACT_VIEW) { long uid = messageObject.messageOwner.media.user_id; TLRPC.User user = null; if (uid != 0) { user = MessagesController.getInstance(currentAccount).getUser(uid); } openVCard(user, messageObject.messageOwner.media.phone_number, messageObject.messageOwner.media.vcard, messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name); + } else if (type == ChatMessageCell.INSTANT_BUTTON_TYPE_CONTACT_SEND_MESSAGE) { + long uid = messageObject.messageOwner.media.user_id; + Bundle args = new Bundle(); + args.putLong("user_id", uid); + presentFragment(new ChatActivity(args)); + } else if (type == ChatMessageCell.INSTANT_BUTTON_TYPE_CONTACT_ADD) { + long uid = messageObject.messageOwner.media.user_id; + TLRPC.User user = null; + if (uid != 0) { + user = MessagesController.getInstance(currentAccount).getUser(uid); + } + if (user != null) { + String phone; + if (!TextUtils.isEmpty(messageObject.vCardData)) { + phone = messageObject.vCardData.toString(); + } else { + if (!TextUtils.isEmpty(user.phone)) { + phone = PhoneFormat.getInstance().format("+" + user.phone); + } else { + phone = MessageObject.getMedia(messageObject.messageOwner).phone_number; + if (!TextUtils.isEmpty(phone)) { + phone = PhoneFormat.getInstance().format((String) phone); + } else { + phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); + } + } + } + + Bundle args = new Bundle(); + args.putLong("user_id", user.id); + args.putString("phone", phone); + args.putBoolean("addContact", true); + presentFragment(new ContactAddActivity(args)); + } } else { if (messageObject.isSponsored()) { logSponsoredClicked(messageObject); @@ -33999,7 +34658,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return ColorUtils.calculateLuminance(color) > 0.7f; } - return super.isLightStatusBar(); + return AndroidUtilities.computePerceivedBrightness(actionBar.getBackgroundColor()) > 0.721f; } public MessageObject.GroupedMessages getGroup(long id) { @@ -34056,7 +34715,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void checkLeaveChannelButton() { - if (headerItem == null) return; + if (headerItem == null || chatMode == MODE_SAVED) return; if (!headerItem.hasSubItem(delete_chat)) { if (!isTopic) { if (ChatObject.isChannel(currentChat) && !currentChat.creator) { @@ -34081,6 +34740,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public boolean supportsThanosEffect() { + if (chatListThanosEffect != null && chatListThanosEffect.destroyed) { + return false; + } return ThanosEffect.supports() && LiteMode.isEnabled(LiteMode.FLAG_CHAT_THANOS); } @@ -34093,6 +34755,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return null; } chatListThanosEffect = new ThanosEffect(getContext(), () -> { + if (removingFromParent) { + return; + } ThanosEffect thisThanosEffect = chatListThanosEffect; if (thisThanosEffect != null) { chatListThanosEffect = null; @@ -34103,4 +34768,47 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return chatListThanosEffect; } + + private void checkGroupMessagesOrder() { + if (!reversed) return; + int groupStart = -1; + long thisGroupId = 0; + for (int i = 0; i < messages.size(); ++i) { + MessageObject msg = messages.get(i); + long msgGroupId = msg.getGroupIdForUse(); + if (thisGroupId != msgGroupId) { + if (groupStart >= 0 && thisGroupId != 0 && i - groupStart > 1) { + // thisGroup from groupStart to (i - 1) + int count = i - groupStart; + ArrayList groupMessages = new ArrayList<>(); + for (int a = 0; a < count; ++a) { + groupMessages.add(messages.remove(groupStart)); + } + Collections.sort(groupMessages, (a, b) -> b.getId() - a.getId()); + messages.addAll(groupStart, groupMessages); + } + groupStart = i; + thisGroupId = msgGroupId; + } + } + if (groupStart >= 0 && thisGroupId != 0 && messages.size() - groupStart > 1) { + // thisGroup from groupStart to (messages.size() - 1) + int count = messages.size() - groupStart; + ArrayList groupMessages = new ArrayList<>(); + for (int a = 0; a < count; ++a) { + groupMessages.add(messages.remove(groupStart)); + } + messages.addAll(groupStart, groupMessages); + } + } + + private void invalidatePremiumBlocked() { + if (getUserConfig().isPremium()) + return; + if (currentUser == null || !currentUser.contact_require_premium) + return; + if (messages.isEmpty() == getMessagesController().isUserPremiumBlocked(getDialogId())) + return; + getMessagesController().invalidateUserPremiumBlocked(getDialogId(), classGuid); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java new file mode 100644 index 000000000..531cecad6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivityContainer.java @@ -0,0 +1,85 @@ +package org.telegram.ui; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.Menu; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.FrameLayout; + +import com.google.android.exoplayer2.util.Log; + +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; +import org.telegram.ui.ActionBar.INavigationLayout; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BackButtonMenu; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.List; + +public class ChatActivityContainer extends FrameLayout { + + public final ChatActivity chatActivity; + private final INavigationLayout parentLayout; + private View fragmentView; + + public ChatActivityContainer(Context context, INavigationLayout parentLayout, Bundle args) { + super(context); + this.parentLayout = parentLayout; + + chatActivity = new ChatActivity(args); + chatActivity.isInsideContainer = true; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (!chatActivity.onFragmentCreate()) { + return; + } + + fragmentView = chatActivity.fragmentView; + chatActivity.setParentLayout(parentLayout); + if (fragmentView == null) { + fragmentView = chatActivity.createView(getContext()); + } else { + ViewGroup parent = (ViewGroup) fragmentView.getParent(); + if (parent != null) { + chatActivity.onRemoveFromParent(); + parent.removeView(fragmentView); + } + } + addView(fragmentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + if (isActive) { + chatActivity.onResume(); + } + } + + private boolean isActive = true; + public void onPause() { + isActive = false; + if (fragmentView != null) { + chatActivity.onPause(); + } + } + + public void onResume() { + isActive = true; + if (fragmentView != null) { + chatActivity.onResume(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CodeNumberField.java b/TMessagesProj/src/main/java/org/telegram/ui/CodeNumberField.java index c2755a9df..3bbd07ba0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CodeNumberField.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CodeNumberField.java @@ -318,8 +318,13 @@ public class CodeNumberField extends EditTextBoldCursor { if (clipboard == null) { return; } - clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN); - ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); +// ClipDescription clipDescription = clipboard.getPrimaryClipDescription(); +// clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN); + ClipData clipData = clipboard.getPrimaryClip(); + if (clipData == null) { + return; + } + ClipData.Item item = clipData.getItemAt(0); int i = -1; String text = item.getText().toString(); try { 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 5b7d35667..ef3b2e35e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -240,7 +240,24 @@ public class AlertsCreator { if (error == null || error.code == 406 || error.text == null) { return null; } - if (request instanceof TLRPC.TL_messages_initHistoryImport || request instanceof TLRPC.TL_messages_checkHistoryImportPeer || request instanceof TLRPC.TL_messages_checkHistoryImport || request instanceof TLRPC.TL_messages_startHistoryImport) { + if (request instanceof TLRPC.TL_messages_sendMessage && error.text.contains("PRIVACY_PREMIUM_REQUIRED")) { + TLRPC.TL_messages_sendMessage req = (TLRPC.TL_messages_sendMessage) request; + long dialogId = DialogObject.getPeerDialogId(req.peer); + String username = ""; + if (dialogId >= 0) { + username = UserObject.getFirstName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat != null) { + username = chat.title; + } + } + if (fragment == null) { + fragment = LaunchActivity.getLastFragment(); + } + showSimpleAlert(fragment, LocaleController.getString(R.string.MessagePremiumErrorTitle), LocaleController.formatString(R.string.MessagePremiumErrorMessage, username)); + MessagesController.getInstance(currentAccount).invalidateUserPremiumBlocked(dialogId, 0); + } else if (request instanceof TLRPC.TL_messages_initHistoryImport || request instanceof TLRPC.TL_messages_checkHistoryImportPeer || request instanceof TLRPC.TL_messages_checkHistoryImport || request instanceof TLRPC.TL_messages_startHistoryImport) { TLRPC.InputPeer peer; if (request instanceof TLRPC.TL_messages_initHistoryImport) { peer = ((TLRPC.TL_messages_initHistoryImport) request).peer; @@ -4094,7 +4111,7 @@ public class AlertsCreator { return builder; } - public static BottomSheet createMuteAlert(BaseFragment fragment, final long dialog_id, int topicId, Theme.ResourcesProvider resourcesProvider) { + public static BottomSheet createMuteAlert(BaseFragment fragment, final long dialog_id, long topicId, Theme.ResourcesProvider resourcesProvider) { if (fragment == null || fragment.getParentActivity() == null) { return null; } @@ -4615,7 +4632,7 @@ public class AlertsCreator { return createColorSelectDialog(parentActivity, dialog_id, topicId, globalType, onSelect, null); } - public static Dialog createColorSelectDialog(Activity parentActivity, final long dialog_id, final int topicId, final int globalType, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { + public static Dialog createColorSelectDialog(Activity parentActivity, final long dialog_id, final long topicId, final int globalType, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { int currentColor; SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); String key = NotificationsController.getSharedPrefKey(dialog_id, topicId); @@ -4725,11 +4742,11 @@ public class AlertsCreator { return builder.create(); } - public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, int topicId, final boolean globalGroup, final boolean globalAll, final Runnable onSelect) { + public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, long topicId, final boolean globalGroup, final boolean globalAll, final Runnable onSelect) { return createVibrationSelectDialog(parentActivity, dialogId, topicId, globalGroup, globalAll, onSelect, null); } - public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, int topicId, final boolean globalGroup, final boolean globalAll, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { + public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, long topicId, final boolean globalGroup, final boolean globalAll, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { String prefix; if (dialogId != 0) { prefix = "vibrate_" + dialogId; @@ -4739,11 +4756,11 @@ public class AlertsCreator { return createVibrationSelectDialog(parentActivity, dialogId, topicId, prefix, onSelect, resourcesProvider); } - public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, int topicId, final String prefKeyPrefix, final Runnable onSelect) { + public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, long topicId, final String prefKeyPrefix, final Runnable onSelect) { return createVibrationSelectDialog(parentActivity, dialogId, topicId, prefKeyPrefix, onSelect, null); } - public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, int topicId, final String prefKeyPrefix, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { + public static Dialog createVibrationSelectDialog(Activity parentActivity, final long dialogId, long topicId, final String prefKeyPrefix, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); final int[] selected = new int[1]; String[] descriptions; @@ -5092,7 +5109,7 @@ public class AlertsCreator { return createPrioritySelectDialog(parentActivity, dialog_id, topicId, globalType, onSelect, null); } - public static Dialog createPrioritySelectDialog(Activity parentActivity, final long dialog_id, int topicId, final int globalType, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { + public static Dialog createPrioritySelectDialog(Activity parentActivity, final long dialog_id, long topicId, final int globalType, final Runnable onSelect, Theme.ResourcesProvider resourcesProvider) { SharedPreferences preferences = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); final int[] selected = new int[1]; String[] descriptions; @@ -5398,7 +5415,7 @@ public class AlertsCreator { void didPressedNewCard(); } - public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User user, TLRPC.Chat chat, TLRPC.EncryptedChat encryptedChat, TLRPC.ChatFull chatInfo, long mergeDialogId, MessageObject selectedMessage, SparseArray[] selectedMessages, MessageObject.GroupedMessages selectedGroup, boolean scheduled, int loadParticipant, Runnable onDelete, Runnable hideDim, Theme.ResourcesProvider resourcesProvider) { + public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User user, TLRPC.Chat chat, TLRPC.EncryptedChat encryptedChat, TLRPC.ChatFull chatInfo, long mergeDialogId, MessageObject selectedMessage, SparseArray[] selectedMessages, MessageObject.GroupedMessages selectedGroup, boolean scheduled, boolean isSavedMessages, int loadParticipant, Runnable onDelete, Runnable hideDim, Theme.ResourcesProvider resourcesProvider) { if (fragment == null || user == null && chat == null && encryptedChat == null) { return; } @@ -5459,7 +5476,7 @@ public class AlertsCreator { boolean hasNotOut = false; int myMessagesCount = 0; boolean canDeleteInbox = encryptedChat == null && user != null && canRevokeInbox && revokeTimeLimit == 0x7fffffff; - if (chat != null && chat.megagroup && !scheduled) { + if (chat != null && chat.megagroup && !scheduled && !isSavedMessages) { boolean canBan = ChatObject.canBlockUsers(chat); if (selectedMessage != null) { if (selectedMessage.messageOwner.action == null || selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionEmpty || @@ -5535,7 +5552,7 @@ public class AlertsCreator { } else if (error != null && "USER_NOT_PARTICIPANT".equals(error.text)) { loadType = 0; } - createDeleteMessagesAlert(fragment, user, chat, encryptedChat, chatInfo, mergeDialogId, selectedMessage, selectedMessages, selectedGroup, scheduled, loadType, onDelete, hideDim, resourcesProvider); + createDeleteMessagesAlert(fragment, user, chat, encryptedChat, chatInfo, mergeDialogId, selectedMessage, selectedMessages, selectedGroup, scheduled, isSavedMessages, loadType, onDelete, hideDim, resourcesProvider); })); AndroidUtilities.runOnUIThread(() -> { if (progressDialog[0] == null) { @@ -5599,7 +5616,7 @@ public class AlertsCreator { } else { actionUser = null; } - } else if (!scheduled && !ChatObject.isChannel(chat) && encryptedChat == null) { + } else if (!scheduled && !isSavedMessages && !ChatObject.isChannel(chat) && encryptedChat == null) { if (user != null && user.id != UserConfig.getInstance(currentAccount).getClientUserId() && (!user.bot || user.support) || chat != null) { if (selectedMessage != null) { boolean hasOutgoing = !selectedMessage.isSendError() && ( @@ -5664,6 +5681,10 @@ public class AlertsCreator { DialogInterface.OnClickListener deleteAction = (dialogInterface, i) -> { ArrayList ids = null; + long thisDialogId = dialogId; + if (isSavedMessages) { + thisDialogId = UserConfig.getInstance(currentAccount).getClientUserId(); + } if (selectedMessage != null) { ids = new ArrayList<>(); ArrayList random_ids = null; @@ -5685,7 +5706,7 @@ public class AlertsCreator { random_ids.add(selectedMessage.messageOwner.random_id); } } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, dialogId, deleteForAll[0], scheduled); + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, deleteForAll[0], scheduled); } else { for (int a = 1; a >= 0; a--) { ids = new ArrayList<>(); @@ -5702,7 +5723,7 @@ public class AlertsCreator { } } } - MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, dialogId, deleteForAll[0], scheduled); + MessagesController.getInstance(currentAccount).deleteMessages(ids, random_ids, encryptedChat, thisDialogId, deleteForAll[0], scheduled); selectedMessages[a].clear(); } } @@ -5732,19 +5753,33 @@ public class AlertsCreator { } }; - if (count == 1) { - builder.setTitle(LocaleController.getString("DeleteSingleMessagesTitle", R.string.DeleteSingleMessagesTitle)); + if (isSavedMessages) { + if (count == 1) { + builder.setTitle(LocaleController.getString(R.string.UnsaveSingleMessagesTitle)); + } else { + builder.setTitle(LocaleController.formatString(R.string.UnsaveMessagesTitle, LocaleController.formatPluralString("messages", count))); + } } else { - builder.setTitle(LocaleController.formatString("DeleteMessagesTitle", R.string.DeleteMessagesTitle, LocaleController.formatPluralString("messages", count))); + if (count == 1) { + builder.setTitle(LocaleController.getString(R.string.DeleteSingleMessagesTitle)); + } else { + builder.setTitle(LocaleController.formatString(R.string.DeleteMessagesTitle, LocaleController.formatPluralString("messages", count))); + } } - if (chat != null && hasNotOut) { - if (hasDeleteForAllCheck && myMessagesCount != count) { - builder.setMessage(LocaleController.formatString("DeleteMessagesTextGroupPart", R.string.DeleteMessagesTextGroupPart, LocaleController.formatPluralString("messages", myMessagesCount))); - } else if (count == 1) { - builder.setMessage(LocaleController.getString("AreYouSureDeleteSingleMessage", R.string.AreYouSureDeleteSingleMessage)); + if (isSavedMessages) { + if (count == 1) { + builder.setMessage(LocaleController.getString(R.string.AreYouSureUnsaveSingleMessage)); } else { - builder.setMessage(LocaleController.getString("AreYouSureDeleteFewMessages", R.string.AreYouSureDeleteFewMessages)); + builder.setMessage(LocaleController.getString(R.string.AreYouSureUnsaveFewMessages)); + } + } else if (chat != null && hasNotOut) { + if (hasDeleteForAllCheck && myMessagesCount != count) { + builder.setMessage(LocaleController.formatString(R.string.DeleteMessagesTextGroupPart, LocaleController.formatPluralString("messages", myMessagesCount))); + } else if (count == 1) { + builder.setMessage(LocaleController.getString(R.string.AreYouSureDeleteSingleMessage)); + } else { + builder.setMessage(LocaleController.getString(R.string.AreYouSureDeleteFewMessages)); } } else if (hasDeleteForAllCheck && !canDeleteInbox && myMessagesCount != count) { if (chat != null) { @@ -5793,12 +5828,12 @@ public class AlertsCreator { } } - if (isActiveGiveawayAndOwner) { + if (isActiveGiveawayAndOwner && !isSavedMessages) { builder.setTitle(LocaleController.getString("BoostingGiveawayDeleteMsgTitle", R.string.BoostingGiveawayDeleteMsgTitle)); builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BoostingGiveawayDeleteMsgText", R.string.BoostingGiveawayDeleteMsgText, giveawayEndDate))); builder.setNeutralButton(LocaleController.getString("Delete", R.string.Delete), deleteAction); } else { - builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), deleteAction); + builder.setPositiveButton(LocaleController.getString(isSavedMessages ? R.string.Remove : R.string.Delete), deleteAction); } builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setOnPreDismissListener(di -> { 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 bf959b9cf..ac5d2f099 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -72,6 +72,7 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB = 16; public static final int CACHE_TYPE_EMOJI_CALL = 17; + public static final int CACHE_TYPE_SAVED_REACTION = 18; public int rawDrawIndex; @@ -625,7 +626,7 @@ public class AnimatedEmojiDrawable extends Drawable { private void updateAutoRepeat(ImageReceiver imageReceiver) { if (cacheType == CACHE_TYPE_EMOJI_STATUS || cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || cacheType == CACHE_TYPE_FORUM_TOPIC) { imageReceiver.setAutoRepeatCount(2); - } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP) { + } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE || cacheType == CACHE_TYPE_SAVED_REACTION || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP) { imageReceiver.setAutoRepeatCount(1); } else if (cacheType == CACHE_TYPE_EMOJI_CALL){ imageReceiver.setAutoRepeatCount(0); 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 d8acbd1ca..15a350f4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -483,6 +483,10 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, } public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, int streamLoadingPriority, TLRPC.Document document, ImageLocation location, Object parentObject, long seekTo, int account, boolean preview, int w, int h, BitmapsCache.CacheOptions cacheOptions) { + this(file, createDecoder, streamSize, streamLoadingPriority, document, location, parentObject, seekTo, account, preview, w, h, cacheOptions, document != null ? 1 : 0); + } + + public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, int streamLoadingPriority, TLRPC.Document document, ImageLocation location, Object parentObject, long seekTo, int account, boolean preview, int w, int h, BitmapsCache.CacheOptions cacheOptions, int cacheType) { path = file; PRERENDER_FRAME = SharedConfig.deviceIsAboveAverage(); streamFileSize = streamSize; @@ -494,7 +498,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, this.document = document; getPaint().setFlags(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); if (streamSize != 0 && (document != null || location != null)) { - stream = new AnimatedFileDrawableStream(document, location, parentObject, account, preview, streamLoadingPriority); + stream = new AnimatedFileDrawableStream(document, location, parentObject, account, preview, streamLoadingPriority, cacheType); } if (createDecoder && !this.precache) { nativePtr = createDecoder(file.getAbsolutePath(), metaData, currentAccount, streamFileSize, stream, preview); 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 c32374e04..693f86173 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java @@ -124,6 +124,7 @@ public class AnimatedFloat { // set() must be called inside onDraw/dispatchDraw // the main purpose of AnimatedFloat is to interpolate between abrupt changing states + public float set(float mustBe) { return this.set(mustBe, false); } @@ -132,6 +133,8 @@ public class AnimatedFloat { return this.set(mustBe ? 1 : 0, false); } + // do set(value, true) when it's needed to skip animation + public float set(boolean mustBe, boolean force) { return this.set(mustBe ? 1 : 0, force); } 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 9481d99ec..668988021 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -46,7 +46,9 @@ public class AvatarDrawable extends Drawable { private TextPaint namePaint; private boolean hasGradient; + private boolean hasAdvancedGradient; private int color, color2; + private GradientTools advancedGradient; private boolean needApplyColorAccent; private StaticLayout textLayout; private float textWidth; @@ -75,7 +77,6 @@ public class AvatarDrawable extends Drawable { 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; @@ -92,6 +93,9 @@ public class AvatarDrawable extends Drawable { public static final int AVATAR_TYPE_COUNTRY = 17; public static final int AVATAR_TYPE_UNCLAIMED = 18; public static final int AVATAR_TYPE_TO_BE_DISTRIBUTED = 19; + public static final int AVATAR_TYPE_STORY = 20; + public static final int AVATAR_TYPE_ANONYMOUS = 21; + public static final int AVATAR_TYPE_MY_NOTES = 22; private int alpha = 255; private Theme.ResourcesProvider resourcesProvider; @@ -231,11 +235,11 @@ public class AvatarDrawable extends Drawable { public void setAvatarType(int value) { avatarType = value; rotate45Background = false; + hasAdvancedGradient = false; + hasGradient = false; if (avatarType == AVATAR_TYPE_REGISTER) { - hasGradient = false; color = color2 = Theme.getColor(Theme.key_chats_actionBackground); } else if (avatarType == AVATAR_TYPE_ARCHIVED) { - hasGradient = false; color = color2 = getThemedColor(Theme.key_avatar_backgroundArchivedHidden); } else if (avatarType == AVATAR_TYPE_REPLIES || avatarType == AVATAR_TYPE_SAVED || avatarType == AVATAR_TYPE_OTHER_CHATS) { hasGradient = true; @@ -282,12 +286,24 @@ public class AvatarDrawable extends Drawable { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(5)]); + } else if (avatarType == AVATAR_TYPE_ANONYMOUS) { + hasAdvancedGradient = true; + if (advancedGradient == null) { + advancedGradient = new GradientTools(); + } + advancedGradient.setColors(0xFF837CFF, 0xFFB063FF, 0xFFFF72A9, 0xFFE269FF); + } else if (avatarType == AVATAR_TYPE_MY_NOTES) { + hasAdvancedGradient = true; + if (advancedGradient == null) { + advancedGradient = new GradientTools(); + } + advancedGradient.setColors(0xFF4D8DFF, 0xFF2BBFFF, 0xFF20E2CD, 0xFF0EE1F1); } else { hasGradient = true; 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_STORY && 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_ANONYMOUS && avatarType != AVATAR_TYPE_REPLIES && avatarType != AVATAR_TYPE_OTHER_CHATS; } public void setArchivedAvatarHiddenProgress(float progress) { @@ -318,12 +334,14 @@ public class AvatarDrawable extends Drawable { public void setColor(int value) { hasGradient = false; + hasAdvancedGradient = false; color = color2 = value; needApplyColorAccent = false; } public void setColor(int value, int value2) { hasGradient = true; + hasAdvancedGradient = false; color = value; color2 = value2; needApplyColorAccent = false; @@ -359,6 +377,7 @@ public class AvatarDrawable extends Drawable { public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor, MessagesController.PeerColor profileColor) { hasGradient = true; + hasAdvancedGradient = false; invalidateTextLayout = true; if (profileColor != null) { color = profileColor.getAvatarColor1(); @@ -438,16 +457,20 @@ public class AvatarDrawable extends Drawable { } int size = bounds.width(); namePaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_avatar_text), alpha)); - if (hasGradient) { + Paint backgroundPaint = Theme.avatar_backgroundPaint; + if (hasAdvancedGradient && advancedGradient != null) { + advancedGradient.setBounds(bounds.left, bounds.top, bounds.left + size, bounds.top + size); + backgroundPaint = advancedGradient.paint; + } else if (hasGradient) { int color = ColorUtils.setAlphaComponent(getColor(), alpha); int color2 = ColorUtils.setAlphaComponent(getColor2(), alpha); if (gradient == null || gradientBottom != bounds.height() || gradientColor1 != color || gradientColor2 != color2) { gradient = new LinearGradient(0, 0, 0, gradientBottom = bounds.height(), gradientColor1 = color, gradientColor2 = color2, Shader.TileMode.CLAMP); } - Theme.avatar_backgroundPaint.setShader(gradient); + backgroundPaint.setShader(gradient); } else { - Theme.avatar_backgroundPaint.setShader(null); - Theme.avatar_backgroundPaint.setColor(ColorUtils.setAlphaComponent(getColor(), alpha)); + backgroundPaint.setShader(null); + backgroundPaint.setColor(ColorUtils.setAlphaComponent(getColor(), alpha)); } canvas.save(); canvas.translate(bounds.left, bounds.top); @@ -459,9 +482,9 @@ public class AvatarDrawable extends Drawable { } if (roundRadius > 0) { AndroidUtilities.rectTmp.set(0, 0, size, size); - canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, Theme.avatar_backgroundPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, backgroundPaint); } else { - canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f, Theme.avatar_backgroundPaint); + canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f, backgroundPaint); } if (rotate45Background) { canvas.restore(); @@ -470,8 +493,8 @@ public class AvatarDrawable extends Drawable { if (avatarType == AVATAR_TYPE_ARCHIVED) { if (archivedAvatarProgress != 0) { - Theme.avatar_backgroundPaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_avatar_backgroundArchived), alpha)); - canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f * archivedAvatarProgress, Theme.avatar_backgroundPaint); + backgroundPaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_avatar_backgroundArchived), alpha)); + canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f * archivedAvatarProgress, backgroundPaint); if (Theme.dialogs_archiveAvatarDrawableRecolored) { Theme.dialogs_archiveAvatarDrawable.beginApplyLayerColors(); Theme.dialogs_archiveAvatarDrawable.setLayerColor("Arrow1.**", Theme.getNonAnimatedColor(Theme.key_avatar_backgroundArchived)); @@ -531,6 +554,10 @@ public class AvatarDrawable extends Drawable { drawable = Theme.avatarDrawables[16]; } else if (avatarType == AVATAR_TYPE_STORY) { drawable = Theme.avatarDrawables[17]; + } else if (avatarType == AVATAR_TYPE_ANONYMOUS) { + drawable = Theme.avatarDrawables[18]; + } else if (avatarType == AVATAR_TYPE_MY_NOTES) { + drawable = Theme.avatarDrawables[19]; } else { drawable = Theme.avatarDrawables[9]; } 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 fcef07bf4..378a8d110 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java @@ -209,6 +209,9 @@ public class AvatarsDrawable { } public void animateFromState(AvatarsDrawable avatarsDrawable, int currentAccount, boolean createAnimator) { + if (avatarsDrawable == null) { + return; + } if (avatarsDrawable.transitionProgressAnimator != null) { avatarsDrawable.transitionProgressAnimator.cancel(); if (transitionInProgress) { 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 d223db3f5..76dd519c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java @@ -48,7 +48,7 @@ public class BackButtonMenu { int filterId; } - public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButton, long currentDialogId, int topicId, Theme.ResourcesProvider resourcesProvider) { + public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButton, long currentDialogId, long topicId, Theme.ResourcesProvider resourcesProvider) { if (thisFragment == null) { return null; } @@ -219,7 +219,7 @@ public class BackButtonMenu { return scrimPopupWindow; } - private static ArrayList getStackedHistoryForTopic(BaseFragment thisFragment, long currentDialogId, int topicId) { + private static ArrayList getStackedHistoryForTopic(BaseFragment thisFragment, long currentDialogId, long topicId) { ArrayList dialogs = new ArrayList<>(); if (thisFragment.getParentLayout().getFragmentStack().size() > 1 && thisFragment.getParentLayout().getFragmentStack().get(thisFragment.getParentLayout().getFragmentStack().size() - 2) instanceof TopicsFragment) { PulledDialog pulledDialog = new PulledDialog(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurBehindDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurBehindDrawable.java index 21f1c2b47..6f6686964 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurBehindDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurBehindDrawable.java @@ -123,6 +123,7 @@ public class BlurBehindDrawable { canvas.drawBitmap(bitmap[0], 0, 0, emptyPaint); canvas.restore(); wasDraw = true; + canvas.drawColor(0x1a000000); } canvas.restore(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java index 9737c1699..9dec20029 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java @@ -43,10 +43,13 @@ public abstract class BottomSheetWithRecyclerListView extends BottomSheet { } public BottomSheetWithRecyclerListView(BaseFragment fragment, boolean needFocus, boolean hasFixedSize, boolean useNested, Theme.ResourcesProvider resourcesProvider) { - super(fragment.getParentActivity(), needFocus, resourcesProvider); + this(fragment.getParentActivity(), fragment, needFocus, hasFixedSize, useNested, resourcesProvider); + } + + public BottomSheetWithRecyclerListView(Context context, BaseFragment fragment, boolean needFocus, boolean hasFixedSize, boolean useNested, Theme.ResourcesProvider resourcesProvider) { + super(context, needFocus, resourcesProvider); this.baseFragment = fragment; this.hasFixedSize = hasFixedSize; - Context context = fragment.getParentActivity(); headerShadowDrawable = ContextCompat.getDrawable(context, R.drawable.header_shadow).mutate(); FrameLayout containerView; if (useNested) { 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 59673d5de..d2fca34fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -32,6 +32,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; +import org.telegram.messenger.SavedMessagesController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -66,20 +67,16 @@ public final class BulletinFactory { public static BulletinFactory global() { BaseFragment baseFragment = LaunchActivity.getLastFragment(); if (baseFragment == null) { - return null; + return BulletinFactory.of(Bulletin.BulletinWindow.make(ApplicationLoader.applicationContext), null); } return BulletinFactory.of(baseFragment); } - public static void showForError(TLRPC.TL_error error) { - BulletinFactory bulletinFactory = BulletinFactory.global(); - if (bulletinFactory == null) { - return; - } + public void showForError(TLRPC.TL_error error) { if (BuildVars.DEBUG_VERSION) { - bulletinFactory.createErrorBulletin(error.code + " " + error.text).show(); + createErrorBulletin(error.code + " " + error.text).show(); } else { - bulletinFactory.createErrorBulletin(LocaleController.getString("UnknownError", R.string.UnknownError)).show(); + createErrorBulletin(LocaleController.getString("UnknownError", R.string.UnknownError)).show(); } } @@ -1039,9 +1036,9 @@ public final class BulletinFactory { if (dialogsCount <= 1) { if (did == UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { if (messagesCount <= 1) { - text = AndroidUtilities.replaceTags(LocaleController.getString("FwdMessageToSavedMessages", R.string.FwdMessageToSavedMessages)); + text = AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.FwdMessageToSavedMessages), SavedMessagesController::openSavedMessages); } else { - text = AndroidUtilities.replaceTags(LocaleController.getString("FwdMessagesToSavedMessages", R.string.FwdMessagesToSavedMessages)); + text = AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.FwdMessagesToSavedMessages), SavedMessagesController::openSavedMessages); } layout.setAnimation(R.raw.saved_messages, 30, 30); } else { 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 5c4a8bf6e..0080eeb3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -8,6 +8,9 @@ package org.telegram.ui.Components; +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.LaunchActivity.getLastFragment; import android.Manifest; @@ -60,6 +63,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; +import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.ActionMode; @@ -244,6 +248,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl); + void toggleVideoRecordingPause(); + void needChangeVideoPreviewState(int state, float seekProgress); void onSwitchRecordMode(boolean video); @@ -392,7 +398,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private HashMap animationParamsX = new HashMap<>(); - private class SeekBarWaveformView extends View { + protected class SeekBarWaveformView extends View { public SeekBarWaveformView(Context context) { super(context); @@ -486,15 +492,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Nullable protected FrameLayout recordedAudioPanel; @Nullable - private VideoTimelineView videoTimelineView; + protected VideoTimelineView videoTimelineView; @SuppressWarnings("FieldCanBeLocal") private RLottieImageView recordDeleteImageView; @Nullable - private SeekBarWaveformView recordedAudioSeekBar; + protected SeekBarWaveformView recordedAudioSeekBar; @Nullable private View recordedAudioBackground; @Nullable private ImageView recordedAudioPlayButton; + private long millisecondsRecorded; @Nullable private TextView recordedAudioTimeTextView; @Nullable @@ -531,7 +538,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private AnimatorSet scheduledButtonAnimation; @Nullable private RecordCircle recordCircle; - private OnceButton onceButton; + public ControlsView controlsView; private CloseProgressDrawable2 progressDrawable; private Paint dotPaint; private MediaActionDrawable playPauseDrawable; @@ -588,7 +595,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private boolean sendByEnter; private long lastTypingTimeSend; private float startedDraggingX = -1; - private float distCanMove = AndroidUtilities.dp(80); + private float distCanMove = dp(80); private boolean recordingAudioVideo; public int recordingGuid; private boolean forceShowSendButton; @@ -714,6 +721,18 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }; + private Property recordControlsCircleScale = new Property(Float.class, "controlsScale") { + @Override + public Float get(RecordCircle object) { + return object.getControlsScale(); + } + + @Override + public void set(RecordCircle object, Float value) { + object.setControlsScale(value); + } + }; + private Paint redDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private boolean stickersTabOpen; @@ -801,7 +820,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordingAudioVideo = true; updateRecordInterface(RECORD_STATE_ENTER); if (recordTimerView != null) { - recordTimerView.start(); + recordTimerView.start(0); } if (recordDot != null) { recordDot.enterAnimation = false; @@ -847,7 +866,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public RecordDot(Context context) { super(context); int resId = R.raw.chat_audio_record_delete_2; - drawable = new RLottieDrawable(resId, "" + resId, AndroidUtilities.dp(28), AndroidUtilities.dp(28), false, null); + drawable = new RLottieDrawable(resId, "" + resId, dp(28), dp(28), false, null); drawable.setCurrentParentView(this); drawable.setInvalidateOnProgressSet(true); updateColors(); @@ -855,7 +874,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void updateColors() { int dotColor = getThemedColor(Theme.key_chat_recordedVoiceDot); - int background = ColorUtils.blendARGB(dotColor, getThemedColor(Theme.key_chat_messagePanelBackground), 0.5f); + int background = getThemedColor(Theme.key_chat_messagePanelBackground); redDotPaint.setColor(dotColor); drawable.beginApplyLayerColors(); drawable.setLayerColor("Cup Red.**", dotColor); @@ -914,7 +933,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific drawable.draw(canvas); } if (!playing || !drawable.hasBitmap()) { - canvas.drawCircle(this.getMeasuredWidth() >> 1, this.getMeasuredHeight() >> 1, AndroidUtilities.dp(5), redDotPaint); + canvas.drawCircle(this.getMeasuredWidth() >> 1, this.getMeasuredHeight() >> 1, dp(5), redDotPaint); } invalidate(); } @@ -1017,30 +1036,93 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }; - public class OnceButton extends FrameLayout { + private boolean showTooltip; + private long showTooltipStartTime; + private float tooltipAlpha; + + public class ControlsView extends FrameLayout { private HintView2 hintView; - private CaptionContainerView.PeriodDrawable periodDrawable; - private Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Drawable tooltipBackground; + private Drawable tooltipBackgroundArrow; + private String tooltipMessage; + private StaticLayout tooltipLayout; + private float tooltipWidth; + private TextPaint tooltipPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + Paint lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + Paint lockOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - public OnceButton(Context context) { + Path path = new Path(); + private Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); + + private CaptionContainerView.PeriodDrawable periodDrawable; + + private Drawable micDrawable; + private Drawable vidDrawable; + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + } + + @Override + protected boolean onSetAlpha(int alpha) { + return super.onSetAlpha(alpha); + } + + public ControlsView(Context context) { super(context); periodDrawable = new CaptionContainerView.PeriodDrawable(); periodDrawable.setCallback(this); periodDrawable.setValue(1, voiceOnce, false); + lockOutlinePaint.setStyle(Paint.Style.STROKE); + lockOutlinePaint.setStrokeCap(Paint.Cap.ROUND); + lockOutlinePaint.setStrokeWidth(dpf2(1.7f)); + + lockShadowDrawable = getResources().getDrawable(R.drawable.lock_round_shadow); + lockShadowDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelVoiceLockShadow), PorterDuff.Mode.MULTIPLY)); + tooltipBackground = Theme.createRoundRectDrawable(dp(5), getThemedColor(Theme.key_chat_gifSaveHintBackground)); + + tooltipPaint.setTextSize(dp(14)); + tooltipBackgroundArrow = ContextCompat.getDrawable(context, R.drawable.tooltip_arrow); + tooltipMessage = LocaleController.getString("SlideUpToLock", R.string.SlideUpToLock); + + radiiLeft[0] = radiiLeft[1] = radiiLeft[6] = radiiLeft[7] = dp(3); + radiiLeft[2] = radiiLeft[3] = radiiLeft[4] = radiiLeft[5] = 0; + + radiiRight[0] = radiiRight[1] = radiiRight[6] = radiiRight[7] = 0; + radiiRight[2] = radiiRight[3] = radiiRight[4] = radiiRight[5] = dp(3); + + micDrawable = getResources().getDrawable(R.drawable.input_mic).mutate(); + vidDrawable = getResources().getDrawable(R.drawable.input_video).mutate(); + setWillNotDraw(false); updateColors(); } + public void showTooltipIfNeed() { + if (SharedConfig.lockRecordAudioVideoHint < 3) { + showTooltip = true; + showTooltipStartTime = System.currentTimeMillis(); + } + } + public void showHintView() { hideHintView(); hintView = new HintView2(getContext(), HintView2.DIRECTION_RIGHT); hintView.setJoint(1, 0); hintView.setMultilineText(true); - hintView.setText(AndroidUtilities.replaceTags(LocaleController.getString(voiceOnce ? R.string.VoiceSetOnceHintEnabled : R.string.VoiceSetOnceHint))); + int text; + if (isInVideoMode) { + text = voiceOnce ? R.string.VideoSetOnceHintEnabled : R.string.VideoSetOnceHint; + } else { + text = voiceOnce ? R.string.VoiceSetOnceHintEnabled : R.string.VoiceSetOnceHint; + } + hintView.setText(AndroidUtilities.replaceTags(LocaleController.getString(text))); hintView.setMaxWidthPx(HintView2.cutInFancyHalf(hintView.getText(), hintView.getTextPaint())); if (voiceOnce) { hintView.setIcon(R.raw.fire_on); @@ -1067,31 +1149,334 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + private int lastSize; + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int currentSize = MeasureSpec.getSize(widthMeasureSpec); + int h = dp(194 + 48 + 12); + if (lastSize != currentSize) { + lastSize = currentSize; + tooltipLayout = new StaticLayout(tooltipMessage, tooltipPaint, dp(220), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); + int n = tooltipLayout.getLineCount(); + tooltipWidth = 0; + for (int i = 0; i < n; i++) { + float w = tooltipLayout.getLineWidth(i); + if (w > tooltipWidth) { + tooltipWidth = w; + } + } + } +// if (tooltipLayout != null && tooltipLayout.getLineCount() > 1) { +// h += tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0); +// } super.onMeasure( widthMeasureSpec, - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(194 + 48 + 12), MeasureSpec.EXACTLY) + MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY) ); } private final RectF rectF = new RectF(); public final RectF onceRect = new RectF(); + private long lastUpdateTime; + + private final Path path2 = new Path(); + private final float[] radiiLeft = new float[8], radiiRight = new float[8]; + + private AnimatedFloat hidePauseT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + @Override protected void onDraw(Canvas canvas) { - if (recordCircle == null) return; + float sc; + if (scale <= 0.5f) { + sc = scale / 0.5f; + } else if (scale <= 0.75f) { + sc = 1.0f - (scale - 0.5f) / 0.25f * 0.1f; + } else { + sc = 0.9f + (scale - 0.75f) / 0.25f * 0.1f; + } + long dt = System.currentTimeMillis() - lastUpdateTime; + lastUpdateTime = System.currentTimeMillis(); - int cx = getMeasuredWidth() - AndroidUtilities.dp2(26); + float yAdd = 0; + if (lockAnimatedTranslation != 10000) { + yAdd = Math.max(0, (int) (startTranslation - lockAnimatedTranslation)); + if (yAdd > dp(57)) { + yAdd = dp(57); + } + } - final float cy = AndroidUtilities.lerp(recordCircle.lockY + recordCircle.translationDy, getMeasuredHeight() - AndroidUtilities.dp(70 + 36), Math.max(recordCircle.exitTransition, Math.min(recordCircle.progressToSeekbarStep1, recordCircle.slideToCancelLockProgress))); - rectF.set(cx - AndroidUtilities.dpf2(18), cy, cx + AndroidUtilities.dpf2(18), cy + recordCircle.lockSize); - rectF.offset(0, getMeasuredHeight() - recordCircle.getMeasuredHeight()); - onceVisible = delegate != null && delegate.onceVoiceAvailable() && !isInVideoMode; + final int cx = getMeasuredWidth() - AndroidUtilities.dp2(26); + float moveProgress = 1.0f - yAdd / dp(57); + final float multilinTooltipOffset = getMeasuredHeight() - dp(194); + + float lockSize; + float lockY; + float lockTopY; + float lockMiddleY; + + float lockRotation; + float transformToPauseProgress = 0; + if (sendButtonVisible) { + lockSize = dp(36); + lockY = dp(60) + multilinTooltipOffset + dpf2(30) * (1.0f - sc) - yAdd + dpf2(14f) * moveProgress; + + lockMiddleY = lockY + lockSize / 2f - dpf2(8) + dpf2(2); + lockTopY = lockY + lockSize / 2f - dpf2(16) + dpf2(2); + float snapRotateBackProgress = moveProgress > 0.4f ? 1f : moveProgress / 0.4f; + + lockRotation = 9 * (1f - moveProgress) * (1f - snapAnimationProgress) - 15 * snapAnimationProgress * (1f - snapRotateBackProgress); + + transformToPauseProgress = moveProgress; + } else { + lockSize = dp(36) + (int) (dp(14) * moveProgress); + lockY = dp(60) + multilinTooltipOffset + (int) (dp(30) * (1.0f - sc)) - (int) yAdd + (moveProgress) * idleProgress * -dp(8); + lockMiddleY = lockY + lockSize / 2f - dpf2(8) + dpf2(2) + dpf2(2) * moveProgress; + lockTopY = lockY + lockSize / 2f - dpf2(16) + dpf2(2) + dpf2(2) * moveProgress; + lockRotation = 9 * (1f - moveProgress); + snapAnimationProgress = 0; + } + + if ((showTooltip && System.currentTimeMillis() - showTooltipStartTime > 200) || tooltipAlpha != 0f) { + if (moveProgress < 0.8f || sendButtonVisible || exitTransition != 0 || transformToSeekbar != 0) { + showTooltip = false; + } + if (showTooltip) { + if (tooltipAlpha != 1f) { + tooltipAlpha += dt / 150f; + if (tooltipAlpha >= 1f) { + tooltipAlpha = 1f; + SharedConfig.increaseLockRecordAudioVideoHintShowed(); + } + } + } else { + tooltipAlpha -= dt / 150f; + if (tooltipAlpha < 0) { + tooltipAlpha = 0f; + } + } + + + int alphaInt = (int) (tooltipAlpha * 255); + + tooltipBackground.setAlpha(alphaInt); + tooltipBackgroundArrow.setAlpha(alphaInt); + tooltipPaint.setAlpha(alphaInt); + + if (tooltipLayout != null) { + canvas.save(); + rectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.translate(getMeasuredWidth() - tooltipWidth - dp(44), multilinTooltipOffset + dpf2(16)); + tooltipBackground.setBounds( + -dp(8), -dp(2), + (int) (tooltipWidth + dp(36)), (int) (tooltipLayout.getHeight() + dpf2(4)) + ); + tooltipBackground.draw(canvas); + tooltipLayout.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.translate(getMeasuredWidth() - dp(26), multilinTooltipOffset + dpf2(16 + 1) + tooltipLayout.getHeight() / 2f - idleProgress * dpf2(3f)); + path.reset(); + path.setLastPoint(-dpf2(5), dpf2(4)); + path.lineTo(0, 0); + path.lineTo(dpf2(5), dpf2(4)); + + p.setColor(Color.WHITE); + p.setAlpha(alphaInt); + p.setStyle(Paint.Style.STROKE); + p.setStrokeCap(Paint.Cap.ROUND); + p.setStrokeJoin(Paint.Join.ROUND); + p.setStrokeWidth(dpf2(1.5f)); + canvas.drawPath(path, p); + canvas.restore(); + + canvas.save(); + tooltipBackgroundArrow.setBounds( + cx - tooltipBackgroundArrow.getIntrinsicWidth() / 2, (int) (tooltipLayout.getHeight() + multilinTooltipOffset + dpf2(20)), + cx + tooltipBackgroundArrow.getIntrinsicWidth() / 2, (int) (tooltipLayout.getHeight() + multilinTooltipOffset + dpf2(20)) + tooltipBackgroundArrow.getIntrinsicHeight() + ); + tooltipBackgroundArrow.draw(canvas); + canvas.restore(); + } + } + + float progressToSeekbarStep1 = 0f; + float progressToSeekbarStep2 = 0; + float exitProgress2 = 0f; + float hidePause = hidePauseT.set(isInVideoMode && millisecondsRecorded >= 59_000); + + if (transformToSeekbar != 0 && recordedAudioBackground != null) { + float step1Time = 0.38f; + float step2Time = 0.25f; +// float step3Time = 1f - step1Time - step2Time; + + progressToSeekbarStep1 = transformToSeekbar > step1Time ? 1f : transformToSeekbar / step1Time; + progressToSeekbarStep2 = transformToSeekbar > step1Time + step2Time ? 1f : Math.max(0, (transformToSeekbar - step1Time) / step2Time); +// progressToSeekbarStep3 = Math.max(0, (transformToSeekbar - step1Time - step2Time) / step3Time); + + progressToSeekbarStep1 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep1); + progressToSeekbarStep2 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep2); +// progressToSeekbarStep3 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep3); +// +// radius = radius + AndroidUtilities.dp(16) * progressToSeekbarStep1; +// +// float toRadius = recordedAudioBackground.getMeasuredHeight() / 2f; +// radius = toRadius + (radius - toRadius) * (1f - progressToSeekbarStep2); + } else if (exitTransition != 0) { + float step1Time = 0.6f; + float step2Time = 0.4f; + + progressToSeekbarStep1 = exitTransition > step1Time ? 1f : exitTransition / step1Time; + exitProgress2 = messageTransitionIsRunning ? exitTransition : Math.max(0, (exitTransition - step1Time) / step2Time); + + progressToSeekbarStep1 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep1); + exitProgress2 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(exitProgress2); +// +// radius = radius + AndroidUtilities.dp(16) * progressToSeekbarStep1; +// radius *= (1f - exitProgress2); +// +// if (LiteMode.isEnabled(LiteMode.FLAGS_CHAT) && exitTransition > 0.6f) { +// circleAlpha = Math.max(0, 1f - (exitTransition - 0.6f) / 0.4f); +// } + } + + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - textFieldContainer.getMeasuredHeight()); + float translation = 0; + if (1f - controlsScale != 0) { + translation = 1f - controlsScale; +// } else if (progressToSeekbarStep2 != 0) { +// translation = progressToSeekbarStep2; + } else if (exitProgress2 != 0) { + translation = exitProgress2; + } + if (slideToCancelProgress < 0.7f || canceledByGesture) { + showTooltip = false; + if (slideToCancelLockProgress != 0) { + slideToCancelLockProgress -= 0.12f; + if (slideToCancelLockProgress < 0) { + slideToCancelLockProgress = 0; + } + } + } else { + if (slideToCancelLockProgress != 1f) { + slideToCancelLockProgress += 0.12f; + if (slideToCancelLockProgress > 1f) { + slideToCancelLockProgress = 1f; + } + } + } + + float maxTranslationDy = dpf2(72); + float dy = ( + maxTranslationDy * translation + + dpf2(24) * (progressToSeekbarStep1) * (1f - translation) + + maxTranslationDy * (1f - slideToCancelLockProgress) + ); + if (dy > maxTranslationDy) { + dy = maxTranslationDy; + } +// canvas.translate(0, dy); + float s = (1f - hidePause) * controlsScale * (1f - exitProgress2) * slideToCancelLockProgress; + canvas.scale(s, s, cx, lockMiddleY + dy); + + rectF.set(cx - dpf2(18), lockY + dy, cx + dpf2(18), lockY + dy + lockSize); + lockShadowDrawable.setBounds( + (int) (rectF.left - dpf2(3)), (int) (rectF.top - dpf2(3)), + (int) (rectF.right + dpf2(3)), (int) (rectF.bottom + dpf2(3)) + ); + lockShadowDrawable.draw(canvas); + canvas.drawRoundRect(rectF, dpf2(18), dpf2(18), lockBackgroundPaint); + pauseRect.set(rectF); + scale(pauseRect, s); + + rectF.set( + cx - dpf2(6) - dpf2(2) * (1f - transformToPauseProgress), + lockMiddleY + dy - dpf2(2) * (1f - transformToPauseProgress), + cx + dp(6) + dpf2(2) * (1f - transformToPauseProgress), + lockMiddleY + dy + dp(12) + dpf2(2) * (1f - transformToPauseProgress) + ); + float lockBottom = rectF.bottom; + float locCx = rectF.centerX(); + float locCy = rectF.centerY(); + canvas.save(); + canvas.translate(0, dpf2(2) * (1f - moveProgress)); + canvas.rotate(lockRotation, locCx, locCy); + + if (transformToPauseProgress != 1f) { + AndroidUtilities.rectTmp.set(0, 0, dpf2(8), dpf2(8)); + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), dy + lockBottom + dpf2(2) * (1f - moveProgress)); + canvas.translate(cx - dpf2(4), rectF.top - dp(6) - lerp(dpf2(2), dpf2(1.5f) * (1f - idleProgress), moveProgress) + dpf2(12) * transformToPauseProgress + dpf2(2) * snapAnimationProgress); + if (lockRotation > 0) { + canvas.rotate(lockRotation, dp(8), dp(8)); + } + canvas.drawLine(dpf2(8), dpf2(4), dpf2(8), dpf2(6) + dpf2(4) * (1f - transformToPauseProgress), lockOutlinePaint); + canvas.drawArc(AndroidUtilities.rectTmp, 0, -180, false, lockOutlinePaint); + canvas.drawLine( + 0, dpf2(4), + 0, dpf2(4) + dpf2(4) * idleProgress * (moveProgress) * (sendButtonVisible ? 0 : 1) + dpf2(4) * snapAnimationProgress * (1f - moveProgress), + lockOutlinePaint + ); + canvas.restore(); + } + + Drawable resumeDrawable = null; + float transformToResume = Utilities.clamp(transformToSeekbar * 2f, 1, 0); + if (transformToResume > 0) { + resumeDrawable = isInVideoMode ? vidDrawable : micDrawable; + } + + int wasAlpha = lockPaint.getAlpha(); + lockPaint.setAlpha((int) (wasAlpha * (1f - transformToResume))); + if (transformToPauseProgress > 0) { + canvas.drawRoundRect(rectF, dpf2(3), dpf2(3), lockBackgroundPaint); + + path2.rewind(); + AndroidUtilities.rectTmp.set(rectF); + AndroidUtilities.rectTmp.right = rectF.centerX() - dp(1.66f) * transformToPauseProgress; + radiiLeft[0] = radiiLeft[1] = radiiLeft[6] = radiiLeft[7] = lerp(dp(3), dp(1.5f), transformToPauseProgress); + radiiLeft[2] = radiiLeft[3] = radiiLeft[4] = radiiLeft[5] = dp(1.5f) * transformToPauseProgress; + path2.addRoundRect(AndroidUtilities.rectTmp, radiiLeft, Path.Direction.CW); + AndroidUtilities.rectTmp.set(rectF); + AndroidUtilities.rectTmp.left = rectF.centerX() + dp(1.66f) * transformToPauseProgress; + radiiRight[2] = radiiRight[3] = radiiRight[4] = radiiRight[5] = lerp(dp(3), dp(1.5f), transformToPauseProgress); + radiiRight[0] = radiiRight[1] = radiiRight[6] = radiiRight[7] = dp(1.5f) * transformToPauseProgress; + path2.addRoundRect(AndroidUtilities.rectTmp, radiiRight, Path.Direction.CW); + canvas.drawPath(path2, lockPaint); + } else { + canvas.drawRoundRect(rectF, dpf2(3), dpf2(3), lockPaint); + } + lockPaint.setAlpha(wasAlpha); + + if (resumeDrawable != null) { + final float _s = 0.9285f; + AndroidUtilities.rectTmp2.set( + (int) (rectF.centerX() - resumeDrawable.getIntrinsicWidth() / 2 * _s), + (int) (rectF.centerY() - resumeDrawable.getIntrinsicHeight() / 2 * _s), + (int) (rectF.centerX() + resumeDrawable.getIntrinsicWidth() / 2 * _s), + (int) (rectF.centerY() + resumeDrawable.getIntrinsicHeight() / 2 * _s) + ); + resumeDrawable.setBounds(AndroidUtilities.rectTmp2); + resumeDrawable.setAlpha((int) (0xFF * transformToResume)); + resumeDrawable.draw(canvas); + } + + if (transformToPauseProgress != 1) { + canvas.drawCircle(locCx, locCy, dpf2(2) * (1f - transformToPauseProgress), lockBackgroundPaint); + } + canvas.restore(); + canvas.restore(); + + final float cy = lerp(lockY, getMeasuredHeight() - dp(118), Math.max(exitTransition, Math.min(progressToSeekbarStep1, slideToCancelLockProgress))) + dy + dp(38) * hidePause; + rectF.set(cx - dpf2(18), cy, cx + dpf2(18), cy + lockSize); + onceVisible = delegate != null && delegate.onceVoiceAvailable(); if (onceVisible) { - final float onceOffset = AndroidUtilities.dpf2(AndroidUtilities.lerp(4, 12, recordCircle.moveProgress)); + final float onceOffset = dpf2(12); rectF.set( - rectF.left, rectF.top - AndroidUtilities.dpf2(36) - onceOffset, rectF.right, rectF.top - onceOffset + rectF.left, rectF.top - dpf2(36) - onceOffset, rectF.right, rectF.top - onceOffset ); if (hintView != null) { hintView.setJointPx(0, rectF.centerY()); @@ -1099,14 +1484,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } onceRect.set(rectF); canvas.save(); - final float s = recordCircle.scale * (1f - recordCircle.exitTransition) * recordCircle.slideToCancelLockProgress * recordCircle.snapAnimationProgress; - canvas.scale(s, s, rectF.centerX(), rectF.centerY()); + final float s2 = controlsScale * (1f - exitTransition) * slideToCancelLockProgress * snapAnimationProgress; + canvas.scale(s2, s2, rectF.centerX(), rectF.centerY()); lockShadowDrawable.setBounds( - (int) (rectF.left - AndroidUtilities.dpf2(3)), (int) (rectF.top - AndroidUtilities.dpf2(3)), - (int) (rectF.right + AndroidUtilities.dpf2(3)), (int) (rectF.bottom + AndroidUtilities.dpf2(3)) + (int) (rectF.left - dpf2(3)), (int) (rectF.top - dpf2(3)), + (int) (rectF.right + dpf2(3)), (int) (rectF.bottom + dpf2(3)) ); lockShadowDrawable.draw(canvas); - canvas.drawRoundRect(rectF, AndroidUtilities.dpf2(18), AndroidUtilities.dpf2(18), lockBackgroundPaint); + canvas.drawRoundRect(rectF, dpf2(18), dpf2(18), lockBackgroundPaint); periodDrawable.setBounds((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom); periodDrawable.draw(canvas); canvas.restore(); @@ -1120,33 +1505,75 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 0xFFFFFFFF ); lockBackgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLockBackground)); + + tooltipPaint.setColor(getThemedColor(Theme.key_chat_gifSaveHintText)); + tooltipBackground = Theme.createRoundRectDrawable(dp(5), getThemedColor(Theme.key_chat_gifSaveHintBackground)); + tooltipBackgroundArrow.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_gifSaveHintBackground), PorterDuff.Mode.SRC_IN)); + + lockBackgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLockBackground)); + lockPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLock)); + lockOutlinePaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLock)); + + micDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelVoiceLock), PorterDuff.Mode.SRC_IN)); + vidDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelVoiceLock), PorterDuff.Mode.SRC_IN)); } - private boolean pressed; + private void scale(RectF rect, float s) { + final float cx = rect.centerX(), cy = rect.centerY(); + rect.left = lerp(cx, rect.left, s); + rect.right = lerp(cx, rect.right, s); + rect.top = lerp(cy, rect.top, s); + rect.bottom = lerp(cy, rect.bottom, s); + } + + private boolean oncePressed; + private boolean pausePressed; + @Override public boolean onTouchEvent(MotionEvent event) { - if (onceVisible && (recordCircle != null && recordCircle.snapAnimationProgress > .1f)) { - int x = (int) event.getX(); - int y = (int) event.getY(); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - return pressed = onceRect.contains(x, y); - } else if (pressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - if (onceRect.contains(x, y)) { - voiceOnce = !voiceOnce; - periodDrawable.setValue(1, voiceOnce, true); - if (voiceOnce) { - showHintView(); - } else { - hideHintView(); - } - invalidate(); + final int x = (int) event.getX(); + final int y = (int) event.getY(); + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (sendButtonVisible) { + pausePressed = pauseRect.contains(x, y); + } + if (onceVisible && (recordCircle != null && snapAnimationProgress > .1f)) { + oncePressed = onceRect.contains(x, y); + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + if (pausePressed && pauseRect.contains(x, y)) { + if (isInVideoMode()) { + if (slideText != null) { + slideText.setEnabled(false); + } + delegate.toggleVideoRecordingPause(); + } else { + MediaController.getInstance().toggleRecordingPause(); + delegate.needStartRecordAudio(0); + if (slideText != null) { + slideText.setEnabled(false); } } + pausePressed = oncePressed = false; + return true; + } else if (oncePressed && onceRect.contains(x, y)) { + voiceOnce = !voiceOnce; + periodDrawable.setValue(1, voiceOnce, true); + if (voiceOnce) { + showHintView(); + } else { + hideHintView(); + } + invalidate(); + pausePressed = oncePressed = false; return true; } + pausePressed = oncePressed = false; + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + pausePressed = oncePressed = false; } - return false; + return pausePressed || oncePressed; } @Override @@ -1155,20 +1582,81 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + private float scale; + private float controlsScale; + private float slideToCancelProgress; + private float startTranslation; + private float lockAnimatedTranslation; + private float exitTransition; + private float snapAnimationProgress; + float idleProgress; + private float transformToSeekbar; + private float progressToSeekbarStep1, progressToSeekbarStep2; + private float slideToCancelLockProgress; + private boolean canceledByGesture; + private boolean sendButtonVisible; + private int slideDelta; + + @Keep + public float getExitTransition() { + return exitTransition; + } + + @Keep + public void setExitTransition(float value) { + exitTransition = value; + if (recordCircle != null) { + recordCircle.invalidate(); + } + } + + @Keep + public float getSlideToCancelProgress() { + return slideToCancelProgress; + } + + @Keep + public void setSlideToCancelProgress(float value) { + slideToCancelProgress = value; + float distance = getMeasuredWidth() * 0.35f; + if (distance > dp(140)) { + distance = dp(140); + } + slideDelta = (int) (-distance * (1f - slideToCancelProgress)); + if (recordCircle != null) { + recordCircle.invalidate(); + } + } + + @Keep + public float getLockAnimatedTranslation() { + return lockAnimatedTranslation; + } + @Keep + public void setLockAnimatedTranslation(float value) { + lockAnimatedTranslation = value; + if (recordCircle != null) { + recordCircle.invalidate(); + } + } + + @Keep + public void setSnapAnimationProgress(float value) { + snapAnimationProgress = value; + invalidate(); + } + + public boolean seekbarVisible() { + return !recordIsCanceled && transformToSeekbar > 0; + } + public class RecordCircle extends View { - public float scale; private float amplitude; private float animateToAmplitude; private float animateAmplitudeDiff; private long lastUpdateTime; - private float lockAnimatedTranslation; - private float snapAnimationProgress; - private float startTranslation; - private boolean sendButtonVisible; private boolean pressed; - private float transformToSeekbar; - private float exitTransition; public float progressToSeekbarStep3; private float progressToSendButton; @@ -1177,37 +1665,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific BlobDrawable tinyWaveDrawable = new BlobDrawable(11, LiteMode.FLAGS_CHAT); BlobDrawable bigWaveDrawable = new BlobDrawable(12, LiteMode.FLAGS_CHAT); - private Drawable tooltipBackground; - private Drawable tooltipBackgroundArrow; - private String tooltipMessage; - private StaticLayout tooltipLayout; - private float tooltipWidth; - private TextPaint tooltipPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private float tooltipAlpha; - private boolean showTooltip; - private long showTooltipStartTime; - - private float circleRadius = AndroidUtilities.dpf2(41); - private float circleRadiusAmplitude = AndroidUtilities.dp(30); - - Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - Paint lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - Paint lockOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float circleRadius = dpf2(41); + private float circleRadiusAmplitude = dp(30); RectF rectF = new RectF(); - Path path = new Path(); - float idleProgress; boolean incIdle; private VirtualViewHelper virtualViewHelper; private int paintAlpha; private float touchSlop; - public float slideToCancelProgress; - public float slideToCancelLockProgress; - private float progressToSeekbarStep1, progressToSeekbarStep2; - private int slideDelta; - private boolean canceledByGesture; private float lastMovingX; private float lastMovingY; @@ -1215,39 +1682,30 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private float wavesEnterAnimation = 0f; private boolean showWaves = true; - private Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); - public float drawingCx, drawingCy, drawingCircleRadius; public boolean voiceEnterTransitionInProgress; public boolean skipDraw; private int lastSize; + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + } + public RecordCircle(Context context) { super(context); virtualViewHelper = new VirtualViewHelper(this); ViewCompat.setAccessibilityDelegate(this, virtualViewHelper); - tinyWaveDrawable.minRadius = AndroidUtilities.dp(47); - tinyWaveDrawable.maxRadius = AndroidUtilities.dp(55); + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(55); tinyWaveDrawable.generateBlob(); - bigWaveDrawable.minRadius = AndroidUtilities.dp(47); - bigWaveDrawable.maxRadius = AndroidUtilities.dp(55); + bigWaveDrawable.minRadius = dp(47); + bigWaveDrawable.maxRadius = dp(55); bigWaveDrawable.generateBlob(); - - lockOutlinePaint.setStyle(Paint.Style.STROKE); - lockOutlinePaint.setStrokeCap(Paint.Cap.ROUND); - lockOutlinePaint.setStrokeWidth(AndroidUtilities.dpf2(1.7f)); - - lockShadowDrawable = getResources().getDrawable(R.drawable.lock_round_shadow); - lockShadowDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelVoiceLockShadow), PorterDuff.Mode.MULTIPLY)); - tooltipBackground = Theme.createRoundRectDrawable(AndroidUtilities.dp(5), getThemedColor(Theme.key_chat_gifSaveHintBackground)); - - tooltipPaint.setTextSize(AndroidUtilities.dp(14)); - tooltipBackgroundArrow = ContextCompat.getDrawable(context, R.drawable.tooltip_arrow); - tooltipMessage = LocaleController.getString("SlideUpToLock", R.string.SlideUpToLock); iconScale = 1f; final ViewConfiguration vc = ViewConfiguration.get(context); @@ -1297,21 +1755,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific invalidate(); } - @Keep - public void setLockAnimatedTranslation(float value) { - lockAnimatedTranslation = value; - invalidate(); + public float getControlsScale() { + return controlsScale; } @Keep - public void setSnapAnimationProgress(float snapAnimationProgress) { - this.snapAnimationProgress = snapAnimationProgress; - invalidate(); - } - - @Keep - public float getLockAnimatedTranslation() { - return lockAnimatedTranslation; + public void setControlsScale(float value) { + controlsScale = value; + if (controlsView != null) { + controlsView.invalidate(); + } } public boolean isSendButtonVisible() { @@ -1321,129 +1774,91 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void setSendButtonInvisible() { sendButtonVisible = false; invalidate(); + if (controlsView != null) { + controlsView.invalidate(); + } } - public int setLockTranslation(float value) { - if (value == 10000) { + public void resetLockTranslation(boolean toLock) { + if (!toLock) { sendButtonVisible = false; lockAnimatedTranslation = -1; startTranslation = -1; - invalidate(); - snapAnimationProgress = 0; - transformToSeekbar = 0; - exitTransition = 0; - iconScale = 1f; - scale = 0f; - tooltipAlpha = 0f; - showTooltip = false; - progressToSendButton = 0f; slideToCancelProgress = 1f; slideToCancelLockProgress = 1f; - canceledByGesture = false; - return 0; - } else { - if (sendButtonVisible) { - return 2; - } - if (lockAnimatedTranslation == -1) { - startTranslation = value; - } - lockAnimatedTranslation = value; - invalidate(); - if (canceledByGesture || slideToCancelProgress < 0.7f) { - return 1; - } - if (startTranslation - lockAnimatedTranslation >= AndroidUtilities.dp(57)) { - sendButtonVisible = true; - return 2; - } + snapAnimationProgress = 0; + controlsScale = 0f; + } + invalidate(); + transformToSeekbar = 0; + isRecordingStateChanged(); + exitTransition = 0; + iconScale = 1f; + scale = 0f; + tooltipAlpha = 0f; + showTooltip = false; + progressToSendButton = 0f; + canceledByGesture = false; + if (controlsView != null) { + controlsView.invalidate(); } - return 1; } - @Override - public boolean onTouchEvent(MotionEvent event) { + public int setLockTranslation(float value) { if (sendButtonVisible) { - int x = (int) event.getX(); - int y = (int) event.getY(); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - return pressed = pauseRect.contains(x, y); - } else if (pressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - if (pauseRect.contains(x, y)) { - if (isInVideoMode()) { - delegate.needStartRecordVideo(3, true, 0, voiceOnce ? 0x7FFFFFFF : 0); - } else { - MediaController.getInstance().stopRecording(2, true, 0, voiceOnce); - delegate.needStartRecordAudio(0); - } - if (slideText != null) { - slideText.setEnabled(false); - } - } - } - return true; - } + return 2; } - return false; + if (lockAnimatedTranslation == -1) { + startTranslation = value; + } + lockAnimatedTranslation = value; + invalidate(); + if (canceledByGesture || slideToCancelProgress < 0.7f) { + return 1; + } + if (startTranslation - lockAnimatedTranslation >= dp(57)) { + sendButtonVisible = true; + return 2; + } + return 1; } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int currentSize = MeasureSpec.getSize(widthMeasureSpec); - int h = AndroidUtilities.dp(194); - if (lastSize != currentSize) { - lastSize = currentSize; - tooltipLayout = new StaticLayout(tooltipMessage, tooltipPaint, AndroidUtilities.dp(220), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); - int n = tooltipLayout.getLineCount(); - tooltipWidth = 0; - for (int i = 0; i < n; i++) { - float w = tooltipLayout.getLineWidth(i); - if (w > tooltipWidth) { - tooltipWidth = w; - } - } - } - if (tooltipLayout != null && tooltipLayout.getLineCount() > 1) { - h += tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0); - } + int h = dp(194); super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); float distance = getMeasuredWidth() * 0.35f; - if (distance > AndroidUtilities.dp(140)) { - distance = AndroidUtilities.dp(140); + if (distance > dp(140)) { + distance = dp(140); } slideDelta = (int) (-distance * (1f - slideToCancelProgress)); } - public float moveProgress; - public float lockY, lockSize; - public float translationDy; - @Override protected void onDraw(Canvas canvas) { if (skipDraw) { return; } float multilinTooltipOffset = 0; - if (tooltipLayout != null && tooltipLayout.getLineCount() > 1) { - multilinTooltipOffset = tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0); - } +// if (tooltipLayout != null && tooltipLayout.getLineCount() > 1) { +// multilinTooltipOffset = tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0); +// } int cx = getMeasuredWidth() - AndroidUtilities.dp2(26); - int cy = (int) (AndroidUtilities.dp(170) + multilinTooltipOffset); - float yAdd = 0; + int cy = (int) (dp(170) + multilinTooltipOffset); +// float yAdd = 0; +// if (lockAnimatedTranslation != 10000) { +// yAdd = Math.max(0, (int) (startTranslation - lockAnimatedTranslation)); +// if (yAdd > AndroidUtilities.dp(57)) { +// yAdd = AndroidUtilities.dp(57); +// } +// } drawingCx = cx + slideDelta; drawingCy = cy; - if (lockAnimatedTranslation != 10000) { - yAdd = Math.max(0, (int) (startTranslation - lockAnimatedTranslation)); - if (yAdd > AndroidUtilities.dp(57)) { - yAdd = AndroidUtilities.dp(57); - } - } - float sc; float circleAlpha = 1f; if (scale <= 0.5f) { @@ -1494,7 +1909,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific progressToSeekbarStep2 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep2); progressToSeekbarStep3 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep3); - radius = radius + AndroidUtilities.dp(16) * progressToSeekbarStep1; + radius = radius + dp(16) * progressToSeekbarStep1; float toRadius = recordedAudioBackground.getMeasuredHeight() / 2f; radius = toRadius + (radius - toRadius) * (1f - progressToSeekbarStep2); @@ -1508,15 +1923,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific progressToSeekbarStep1 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(progressToSeekbarStep1); exitProgress2 = CubicBezierInterpolator.EASE_BOTH.getInterpolation(exitProgress2); - radius = radius + AndroidUtilities.dp(16) * progressToSeekbarStep1; + radius = radius + dp(16) * progressToSeekbarStep1; radius *= (1f - exitProgress2); if (LiteMode.isEnabled(LiteMode.FLAGS_CHAT) && exitTransition > 0.6f) { circleAlpha = Math.max(0, 1f - (exitTransition - 0.6f) / 0.4f); } } - this.progressToSeekbarStep1 = progressToSeekbarStep1; - this.progressToSeekbarStep2 = progressToSeekbarStep2; if (canceledByGesture && slideToCancelProgress > 0.7f) { circleAlpha *= (1f - (slideToCancelProgress - 0.7f) / 0.3f); @@ -1549,16 +1962,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific replaceDrawable.setBounds(cx - replaceDrawable.getIntrinsicWidth() / 2, cy - replaceDrawable.getIntrinsicHeight() / 2, cx + replaceDrawable.getIntrinsicWidth() / 2, cy + replaceDrawable.getIntrinsicHeight() / 2); } - float moveProgress = this.moveProgress = 1.0f - yAdd / AndroidUtilities.dp(57); - - float lockSize; - float lockY; - float lockTopY; - float lockMiddleY; - - float lockRotation; - float transformToPauseProgress = 0; - if (incIdle) { idleProgress += 0.01f; if (idleProgress > 1f) { @@ -1574,11 +1977,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (LiteMode.isEnabled(LiteMode.FLAGS_CHAT)) { - tinyWaveDrawable.minRadius = AndroidUtilities.dp(47); - tinyWaveDrawable.maxRadius = AndroidUtilities.dp(47) + AndroidUtilities.dp(15) * BlobDrawable.FORM_SMALL_MAX; + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(47) + dp(15) * BlobDrawable.FORM_SMALL_MAX; - bigWaveDrawable.minRadius = AndroidUtilities.dp(50); - bigWaveDrawable.maxRadius = AndroidUtilities.dp(50) + AndroidUtilities.dp(12) * BlobDrawable.FORM_BIG_MAX; + bigWaveDrawable.minRadius = dp(50); + bigWaveDrawable.maxRadius = dp(50) + dp(12) * BlobDrawable.FORM_BIG_MAX; bigWaveDrawable.updateAmplitude(dt); bigWaveDrawable.update(bigWaveDrawable.amplitude, 1.01f); @@ -1613,12 +2016,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } - if (!voiceEnterTransitionInProgress) { paint.setAlpha((int) (paintAlpha * circleAlpha)); - if (this.scale == 1f) { + if (scale == 1f) { if (transformToSeekbar != 0) { - if (progressToSeekbarStep3 > 0 && recordedAudioBackground != null) { + if (!isInVideoMode && progressToSeekbarStep3 > 0 && recordedAudioBackground != null) { float circleB = cy + radius; float circleT = cy - radius; float circleR = cx + slideDelta + radius; @@ -1650,7 +2052,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific rectF.set(left, top, right, bottom); canvas.drawRoundRect(rectF, transformRadius, transformRadius, paint); } else { - canvas.drawCircle(cx + slideDelta, cy, radius, paint); + canvas.drawCircle(cx + slideDelta, cy, radius * (1f - progressToSeekbarStep3), paint); } } else { canvas.drawCircle(cx + slideDelta, cy, radius, paint); @@ -1663,178 +2065,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } - if (isSendButtonVisible()) { - lockSize = this.lockSize = AndroidUtilities.dp(36); - lockY = this.lockY = AndroidUtilities.dp(60) + multilinTooltipOffset + AndroidUtilities.dpf2(30) * (1.0f - sc) - yAdd + AndroidUtilities.dpf2(14f) * moveProgress; - - lockMiddleY = lockY + lockSize / 2f - AndroidUtilities.dpf2(8) + AndroidUtilities.dpf2(2); - lockTopY = lockY + lockSize / 2f - AndroidUtilities.dpf2(16) + AndroidUtilities.dpf2(2); - float snapRotateBackProgress = moveProgress > 0.4f ? 1f : moveProgress / 0.4f; - - lockRotation = 9 * (1f - moveProgress) * (1f - snapAnimationProgress) - 15 * snapAnimationProgress * (1f - snapRotateBackProgress); - - transformToPauseProgress = moveProgress; - } else { - lockSize = this.lockSize = AndroidUtilities.dp(36) + (int) (AndroidUtilities.dp(14) * moveProgress); - lockY = this.lockY = AndroidUtilities.dp(60) + multilinTooltipOffset + (int) (AndroidUtilities.dp(30) * (1.0f - sc)) - (int) yAdd + (moveProgress) * idleProgress * -AndroidUtilities.dp(8); - lockMiddleY = lockY + lockSize / 2f - AndroidUtilities.dpf2(8) + AndroidUtilities.dpf2(2) + AndroidUtilities.dpf2(2) * moveProgress; - lockTopY = lockY + lockSize / 2f - AndroidUtilities.dpf2(16) + AndroidUtilities.dpf2(2) + AndroidUtilities.dpf2(2) * moveProgress; - lockRotation = 9 * (1f - moveProgress); - snapAnimationProgress = 0; - } - - if ((showTooltip && System.currentTimeMillis() - showTooltipStartTime > 200) || tooltipAlpha != 0f) { - if (moveProgress < 0.8f || isSendButtonVisible() || exitTransition != 0 || transformToSeekbar != 0) { - showTooltip = false; - } - if (showTooltip) { - if (tooltipAlpha != 1f) { - tooltipAlpha += dt / 150f; - if (tooltipAlpha >= 1f) { - tooltipAlpha = 1f; - SharedConfig.increaseLockRecordAudioVideoHintShowed(); - } - } - } else { - tooltipAlpha -= dt / 150f; - if (tooltipAlpha < 0) { - tooltipAlpha = 0f; - } - } - - - int alphaInt = (int) (tooltipAlpha * 255); - - tooltipBackground.setAlpha(alphaInt); - tooltipBackgroundArrow.setAlpha(alphaInt); - tooltipPaint.setAlpha(alphaInt); - - if (tooltipLayout != null) { - canvas.save(); - rectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - canvas.translate(getMeasuredWidth() - tooltipWidth - AndroidUtilities.dp(44), AndroidUtilities.dpf2(16)); - tooltipBackground.setBounds( - -AndroidUtilities.dp(8), -AndroidUtilities.dp(2), - (int) (tooltipWidth + AndroidUtilities.dp(36)), (int) (tooltipLayout.getHeight() + AndroidUtilities.dpf2(4)) - ); - tooltipBackground.draw(canvas); - tooltipLayout.draw(canvas); - canvas.restore(); - - canvas.save(); - canvas.translate(cx, AndroidUtilities.dpf2(17) + tooltipLayout.getHeight() / 2f - idleProgress * AndroidUtilities.dpf2(3f)); - path.reset(); - path.setLastPoint(-AndroidUtilities.dpf2(5), AndroidUtilities.dpf2(4)); - path.lineTo(0, 0); - path.lineTo(AndroidUtilities.dpf2(5), AndroidUtilities.dpf2(4)); - - p.setColor(Color.WHITE); - p.setAlpha(alphaInt); - p.setStyle(Paint.Style.STROKE); - p.setStrokeCap(Paint.Cap.ROUND); - p.setStrokeJoin(Paint.Join.ROUND); - p.setStrokeWidth(AndroidUtilities.dpf2(1.5f)); - canvas.drawPath(path, p); - canvas.restore(); - - canvas.save(); - tooltipBackgroundArrow.setBounds( - cx - tooltipBackgroundArrow.getIntrinsicWidth() / 2, (int) (tooltipLayout.getHeight() + AndroidUtilities.dpf2(20)), - cx + tooltipBackgroundArrow.getIntrinsicWidth() / 2, (int) (tooltipLayout.getHeight() + AndroidUtilities.dpf2(20)) + tooltipBackgroundArrow.getIntrinsicHeight() - ); - tooltipBackgroundArrow.draw(canvas); - canvas.restore(); - } - } - - canvas.save(); - canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - textFieldContainer.getMeasuredHeight()); - float translation = 0; - if (1f - scale != 0) { - translation = 1f - scale; - } else if (progressToSeekbarStep2 != 0) { - translation = progressToSeekbarStep2; - } else if (exitProgress2 != 0) { - translation = exitProgress2; - } - if (slideToCancelProgress < 0.7f || canceledByGesture) { - showTooltip = false; - if (slideToCancelLockProgress != 0) { - slideToCancelLockProgress -= 0.12f; - if (slideToCancelLockProgress < 0) { - slideToCancelLockProgress = 0; - } - } - } else { - if (slideToCancelLockProgress != 1f) { - slideToCancelLockProgress += 0.12f; - if (slideToCancelLockProgress > 1f) { - slideToCancelLockProgress = 1f; - } - } - } - - float maxTranslationDy = AndroidUtilities.dpf2(72); - float dy = ( - maxTranslationDy * translation - - AndroidUtilities.dpf2(20) * (progressToSeekbarStep1) * (1f - translation) - + maxTranslationDy * (1f - slideToCancelLockProgress) - ); - if (dy > maxTranslationDy) { - dy = maxTranslationDy; - } - this.translationDy = dy; - canvas.translate(0, dy); - float s = scale * (1f - progressToSeekbarStep2) * (1f - exitProgress2) * slideToCancelLockProgress; - canvas.scale(s, s, cx, lockMiddleY); - - rectF.set(cx - AndroidUtilities.dpf2(18), lockY, cx + AndroidUtilities.dpf2(18), lockY + lockSize); - lockShadowDrawable.setBounds( - (int) (rectF.left - AndroidUtilities.dpf2(3)), (int) (rectF.top - AndroidUtilities.dpf2(3)), - (int) (rectF.right + AndroidUtilities.dpf2(3)), (int) (rectF.bottom + AndroidUtilities.dpf2(3)) - ); - lockShadowDrawable.draw(canvas); - canvas.drawRoundRect(rectF, AndroidUtilities.dpf2(18), AndroidUtilities.dpf2(18), lockBackgroundPaint); - pauseRect.set(rectF); - - rectF.set( - cx - AndroidUtilities.dpf2(6) - AndroidUtilities.dpf2(2) * (1f - transformToPauseProgress), - lockMiddleY - AndroidUtilities.dpf2(2) * (1f - transformToPauseProgress), - cx + AndroidUtilities.dp(6) + AndroidUtilities.dpf2(2) * (1f - transformToPauseProgress), - lockMiddleY + AndroidUtilities.dp(12) + AndroidUtilities.dpf2(2) * (1f - transformToPauseProgress) - ); - float lockBottom = rectF.bottom; - float locCx = rectF.centerX(); - float locCy = rectF.centerY(); - canvas.save(); - canvas.translate(0, AndroidUtilities.dpf2(2) * (1f - moveProgress)); - canvas.rotate(lockRotation, locCx, locCy); - canvas.drawRoundRect(rectF, AndroidUtilities.dpf2(3), AndroidUtilities.dpf2(3), lockPaint); - - if (transformToPauseProgress != 1) { - canvas.drawCircle(locCx, locCy, AndroidUtilities.dpf2(2) * (1f - transformToPauseProgress), lockBackgroundPaint); - } - - if (transformToPauseProgress != 1f) { - rectF.set(0, 0, AndroidUtilities.dpf2(8), AndroidUtilities.dpf2(8)); - canvas.save(); - canvas.clipRect(0, 0, getMeasuredWidth(), dy + lockBottom + AndroidUtilities.dpf2(2) * (1f - moveProgress)); - canvas.translate(cx - AndroidUtilities.dpf2(4), lockTopY - AndroidUtilities.dpf2(1.5f) * (1f - idleProgress) * (moveProgress) - AndroidUtilities.dpf2(2) * (1f - moveProgress) + AndroidUtilities.dpf2(12) * transformToPauseProgress + AndroidUtilities.dpf2(2) * snapAnimationProgress); - if (lockRotation > 0) { - canvas.rotate(lockRotation, AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - } - canvas.drawLine(AndroidUtilities.dpf2(8), AndroidUtilities.dpf2(4), AndroidUtilities.dpf2(8), AndroidUtilities.dpf2(6) + AndroidUtilities.dpf2(4) * (1f - transformToPauseProgress), lockOutlinePaint); - canvas.drawArc(rectF, 0, -180, false, lockOutlinePaint); - canvas.drawLine( - 0, AndroidUtilities.dpf2(4), - 0, AndroidUtilities.dpf2(4) + AndroidUtilities.dpf2(4) * idleProgress * (moveProgress) * (isSendButtonVisible() ? 0 : 1) + AndroidUtilities.dpf2(4) * snapAnimationProgress * (1f - moveProgress), - lockOutlinePaint - ); - canvas.restore(); - } - canvas.restore(); - canvas.restore(); - if (scale != 1f) { canvas.drawCircle(cx + slideDelta, cy, radius, paint); float a = (canceledByGesture ? (1f - slideToCancelProgress) : 1); @@ -1849,8 +2079,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Override public void invalidate() { super.invalidate(); - if (onceButton != null) { - onceButton.invalidate(); + if (controlsView != null) { + controlsView.invalidate(); } } @@ -1927,55 +2157,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return progressToSeekbarStep3; } - @Keep - public float getExitTransition() { - return exitTransition; - } - - @Keep - public void setExitTransition(float exitTransition) { - this.exitTransition = exitTransition; - invalidate(); - } - public void updateColors() { paint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceBackground)); tinyWaveDrawable.paint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messagePanelVoiceBackground), (int) (255 * WaveDrawable.CIRCLE_ALPHA_2))); bigWaveDrawable.paint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_messagePanelVoiceBackground), (int) (255 * WaveDrawable.CIRCLE_ALPHA_1))); - tooltipPaint.setColor(getThemedColor(Theme.key_chat_gifSaveHintText)); - tooltipBackground = Theme.createRoundRectDrawable(AndroidUtilities.dp(5), getThemedColor(Theme.key_chat_gifSaveHintBackground)); - tooltipBackgroundArrow.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_gifSaveHintBackground), PorterDuff.Mode.SRC_IN)); - - lockBackgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLockBackground)); - lockPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLock)); - lockOutlinePaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLock)); paintAlpha = paint.getAlpha(); } - public void showTooltipIfNeed() { - if (SharedConfig.lockRecordAudioVideoHint < 3) { - showTooltip = true; - showTooltipStartTime = System.currentTimeMillis(); - } - } - - @Keep - public float getSlideToCancelProgress() { - return slideToCancelProgress; - } - - @Keep - public void setSlideToCancelProgress(float slideToCancelProgress) { - this.slideToCancelProgress = slideToCancelProgress; - float distance = getMeasuredWidth() * 0.35f; - if (distance > AndroidUtilities.dp(140)) { - distance = AndroidUtilities.dp(140); - } - slideDelta = (int) (-distance * (1f - slideToCancelProgress)); - invalidate(); - } - public void canceledByGesture() { canceledByGesture = true; } @@ -2044,7 +2233,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected void getVisibleVirtualViews(List list) { if (isSendButtonVisible()) { list.add(1); - list.add(2); +// list.add(2); list.add(3); } } @@ -2057,7 +2246,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (id == 2) { rect.set((int) pauseRect.left, (int) pauseRect.top, (int) pauseRect.right, (int) pauseRect.bottom); info.setBoundsInParent(rect); - info.setText(LocaleController.getString("Stop", R.string.Stop)); + info.setText(LocaleController.getString(R.string.Stop)); } else if (id == 3 && recordCircle != null) { if (slideText != null && slideText.cancelRect != null) { AndroidUtilities.rectTmp2.set(slideText.cancelRect); @@ -2099,6 +2288,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific setClipChildren(false); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStarted); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordPaused); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordResumed); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStartError); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStopped); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordProgressChanged); @@ -2136,7 +2327,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific }; textFieldContainer.setClipChildren(false); textFieldContainer.setClipToPadding(false); - textFieldContainer.setPadding(0, AndroidUtilities.dp(1), 0, 0); + textFieldContainer.setPadding(0, dp(1), 0, 0); addView(textFieldContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 0, 1, 0, 0)); FrameLayout frameLayout = messageEditTextContainer = new FrameLayout(context) { @@ -2144,7 +2335,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (scheduledButton != null) { - int x = getMeasuredWidth() - AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(48); + int x = getMeasuredWidth() - dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(48); scheduledButton.layout(x, scheduledButton.getTop(), x + scheduledButton.getMeasuredWidth(), scheduledButton.getBottom()); } if (!animationParamsX.isEmpty()) { @@ -2178,16 +2369,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (topAlpha <= 0 && bottomAlpha <= 0) { return super.drawChild(canvas, child, drawingTime); } - canvas.saveLayerAlpha(0, 0, messageEditText.getX() + messageEditText.getMeasuredWidth() + AndroidUtilities.dp(5), messageEditText.getY() + messageEditText.getMeasuredHeight() + AndroidUtilities.dp(2), 0xFF, Canvas.ALL_SAVE_FLAG); + canvas.saveLayerAlpha(0, 0, messageEditText.getX() + messageEditText.getMeasuredWidth() + dp(5), messageEditText.getY() + messageEditText.getMeasuredHeight() + dp(2), 0xFF, Canvas.ALL_SAVE_FLAG); final boolean result = super.drawChild(canvas, child, drawingTime); canvas.save(); if (topAlpha > 0) { AndroidUtilities.rectTmp.set( - messageEditText.getX() - AndroidUtilities.dp(5), + messageEditText.getX() - dp(5), messageEditText.getY() + animatedTop, - messageEditText.getX() + messageEditText.getMeasuredWidth() + AndroidUtilities.dp(5), - messageEditText.getY() + animatedTop + AndroidUtilities.dp(13) + messageEditText.getX() + messageEditText.getMeasuredWidth() + dp(5), + messageEditText.getY() + animatedTop + dp(13) ); clipMatrix.reset(); clipMatrix.postScale(1f, AndroidUtilities.rectTmp.height() / 16f); @@ -2199,10 +2390,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (bottomAlpha > 0) { AndroidUtilities.rectTmp.set( - messageEditText.getX() - AndroidUtilities.dp(5), - messageEditText.getY() + messageEditText.getMeasuredHeight() - AndroidUtilities.dp(13 + 2), - messageEditText.getX() + messageEditText.getMeasuredWidth() + AndroidUtilities.dp(5), - messageEditText.getY() + messageEditText.getMeasuredHeight() + AndroidUtilities.dp(2) + messageEditText.getX() - dp(5), + messageEditText.getY() + messageEditText.getMeasuredHeight() - dp(13 + 2), + messageEditText.getX() + messageEditText.getMeasuredWidth() + dp(5), + messageEditText.getY() + messageEditText.getMeasuredHeight() + dp(2) ); clipMatrix.reset(); clipMatrix.postScale(1f, AndroidUtilities.rectTmp.height() / 16f); @@ -2222,6 +2413,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } return super.drawChild(canvas, child, drawingTime); } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return super.dispatchTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } }; frameLayout.setClipChildren(false); textFieldContainer.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 48, 0)); @@ -2231,15 +2432,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (getTag() != null && attachLayout != null && !emojiViewVisible && !MediaDataController.getInstance(currentAccount).getUnreadStickerSets().isEmpty() && dotPaint != null) { - int x = getWidth() / 2 + AndroidUtilities.dp(4 + 5); - int y = getHeight() / 2 - AndroidUtilities.dp(13 - 5); - canvas.drawCircle(x, y, AndroidUtilities.dp(5), dotPaint); + int x = getWidth() / 2 + dp(4 + 5); + int y = getHeight() / 2 - dp(13 - 5); + canvas.drawCircle(x, y, dp(5), dotPaint); } } }; emojiButton.setContentDescription(LocaleController.getString(R.string.AccDescrEmojiButton)); emojiButton.setFocusable(true); - int padding = AndroidUtilities.dp(9.5f); + int padding = dp(9.5f); emojiButton.setPadding(padding, padding, padding, padding); emojiButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelIcons), PorterDuff.Mode.SRC_IN)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -2292,7 +2493,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific attachLayout = new LinearLayout(context); attachLayout.setOrientation(LinearLayout.HORIZONTAL); attachLayout.setEnabled(false); - attachLayout.setPivotX(AndroidUtilities.dp(48)); + attachLayout.setPivotX(dp(48)); attachLayout.setClipChildren(false); messageEditTextContainer.addView(attachLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48, Gravity.BOTTOM | Gravity.RIGHT)); @@ -2318,7 +2519,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific notifySilentDrawable.setCrossOut(silent, true); notifyButton.setImageDrawable(notifySilentDrawable); MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("silent_" + dialog_id, silent).commit(); - NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(dialog_id, fragment == null ? 0 :fragment.getTopicId()); + NotificationsController.getInstance(currentAccount).updateServerNotificationsSettings(dialog_id, fragment == null ? 0 : fragment.getTopicId()); UndoView undoView = fragment.getUndoView(); if (undoView != null) { undoView.showWithAction(0, !silent ? UndoView.ACTION_NOTIFY_ON : UndoView.ACTION_NOTIFY_OFF, null); @@ -2380,6 +2581,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific audioVideoButtonContainer = new FrameLayout(context) { + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; @@ -2429,7 +2635,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return true; } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL && recordingAudioVideo) { - if (recordCircle.slideToCancelProgress < 0.7f) { + if (slideToCancelProgress < 0.7f) { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); delegate.needStartRecordVideo(2, true, 0, voiceOnce ? 0x7FFFFFFF : 0); @@ -2437,10 +2643,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.needStartRecordAudio(0); MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } + millisecondsRecorded = 0; recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); } else { - recordCircle.sendButtonVisible = true; + sendButtonVisible = true; startLockTransition(); } return false; @@ -2463,6 +2670,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.needStartRecordAudio(0); MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } + millisecondsRecorded = 0; recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); } else { @@ -2515,8 +2723,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (startedDraggingX == -1) { startedDraggingX = x; distCanMove = (float) (sizeNotifierLayout.getMeasuredWidth() * 0.35); - if (distCanMove > AndroidUtilities.dp(140)) { - distCanMove = AndroidUtilities.dp(140); + if (distCanMove > dp(140)) { + distCanMove = dp(140); } } @@ -2532,9 +2740,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (slideText != null) { slideText.setSlideX(alpha); } - if (recordCircle != null) { - recordCircle.setSlideToCancelProgress(alpha); - } + setSlideToCancelProgress(alpha); } if (alpha == 0) { @@ -2729,7 +2935,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific audioVideoSendButton.setFocusable(true); audioVideoSendButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); audioVideoSendButton.setAccessibilityDelegate(mediaMessageButtonsDelegate); - padding = AndroidUtilities.dp(9.5f); + padding = dp(9.5f); audioVideoSendButton.setPadding(padding, padding, padding, padding); audioVideoSendButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelIcons), PorterDuff.Mode.SRC_IN)); audioVideoButtonContainer.addView(audioVideoSendButton, LayoutHelper.createFrame(48, 48)); @@ -2774,6 +2980,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sendButton = new View(context) { + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + } + private int drawableColor; private float animationProgress; private float animateBounce; @@ -2784,14 +2995,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Override protected void onDraw(Canvas canvas) { - int rad = AndroidUtilities.dp(20); + int rad = dp(20); int center = getMeasuredWidth() >> 1; int x = (getMeasuredWidth() - sendButtonDrawable.getIntrinsicWidth()) / 2; int y = (getMeasuredHeight() - sendButtonDrawable.getIntrinsicHeight()) / 2; if (isInScheduleMode()) { - y -= AndroidUtilities.dp(1); + y -= dp(1); } else { - x += AndroidUtilities.dp(2); + x += dp(2); } int color; @@ -2853,16 +3064,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific float p = animationProgress; if (p <= 0.25f) { float progress = p / 0.25f; - rad += AndroidUtilities.dp(2) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + rad += dp(2) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); } else { p -= 0.25f; if (p <= 0.5f) { float progress = p / 0.5f; - rad += AndroidUtilities.dp(2) - AndroidUtilities.dp(3) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + rad += dp(2) - dp(3) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); } else { p -= 0.5f; float progress = p / 0.25f; - rad += -AndroidUtilities.dp(1) + AndroidUtilities.dp(1) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); + rad += -dp(1) + dp(1) * CubicBezierInterpolator.EASE_IN.getInterpolation(progress); } } } else { @@ -2910,7 +3121,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific slowModeButton.setScaleX(0.1f); slowModeButton.setScaleY(0.1f); slowModeButton.setAlpha(0.0f); - slowModeButton.setPadding(0, 0, AndroidUtilities.dp(13), 0); + slowModeButton.setPadding(0, 0, dp(13), 0); slowModeButton.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); slowModeButton.setTextColor(getThemedColor(Theme.key_chat_messagePanelIcons)); sendButtonContainer.addView(slowModeButton, LayoutHelper.createFrame(64, 48, Gravity.RIGHT | Gravity.TOP)); @@ -2927,8 +3138,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific }); SharedPreferences sharedPreferences = MessagesController.getGlobalEmojiSettings(); - keyboardHeight = sharedPreferences.getInt("kbd_height", AndroidUtilities.dp(200)); - keyboardHeightLand = sharedPreferences.getInt("kbd_height_land3", AndroidUtilities.dp(200)); + keyboardHeight = sharedPreferences.getInt("kbd_height", dp(200)); + keyboardHeightLand = sharedPreferences.getInt("kbd_height_land3", dp(200)); setRecordVideoButtonVisible(false, false); checkSendButton(false); @@ -3056,11 +3267,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific textFieldContainer.addView(doneButtonContainer, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | Gravity.RIGHT)); doneButtonContainer.setOnClickListener(view -> doneEditingMessage()); - Drawable doneCircleDrawable = Theme.createCircleDrawable(AndroidUtilities.dp(16), getThemedColor(Theme.key_chat_messagePanelSend)); + Drawable doneCircleDrawable = Theme.createCircleDrawable(dp(16), getThemedColor(Theme.key_chat_messagePanelSend)); doneCheckDrawable = getContext().getResources().getDrawable(R.drawable.input_done).mutate(); doneCheckDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelVoicePressed), PorterDuff.Mode.MULTIPLY)); - CombinedDrawable combinedDrawable = new CombinedDrawable(doneCircleDrawable, doneCheckDrawable, 0, AndroidUtilities.dp(1)); - combinedDrawable.setCustomSize(AndroidUtilities.dp(32), AndroidUtilities.dp(32)); + CombinedDrawable combinedDrawable = new CombinedDrawable(doneCircleDrawable, doneCheckDrawable, 0, dp(1)); + combinedDrawable.setCustomSize(dp(32), dp(32)); doneButtonImage = new ImageView(getContext()); doneButtonImage.setScaleType(ImageView.ScaleType.CENTER); @@ -3150,6 +3361,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific super.setVisibility(visibility); updateSendAsButton(); } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return super.dispatchTouchEvent(ev); + } }; recordedAudioPanel.setVisibility(audioToSend == null ? GONE : VISIBLE); recordedAudioPanel.setFocusable(true); @@ -3175,6 +3391,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific }); videoTimelineView = new VideoTimelineView(getContext()); + videoTimelineView.setVisibility(INVISIBLE); videoTimelineView.useClip = !shouldDrawBackground; videoTimelineView.setRoundFrames(true); videoTimelineView.setDelegate(new VideoTimelineView.VideoTimelineViewDelegate() { @@ -3219,7 +3436,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific getBackground().draw(canvas); } }; - recordedAudioBackground.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(18), getThemedColor(Theme.key_chat_recordedVoiceBackground))); + recordedAudioBackground.setBackgroundDrawable(Theme.createRoundRectDrawable(dp(18), getThemedColor(Theme.key_chat_recordedVoiceBackground))); recordedAudioPanel.addView(recordedAudioBackground, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_VERTICAL | Gravity.LEFT, 48, 0, 0, 0)); LinearLayout waveFormTimerLayout = new LinearLayout(getContext()); @@ -3228,7 +3445,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordedAudioPlayButton = new ImageView(getContext()); Matrix matrix = new Matrix(); - matrix.postScale(0.8f, 0.8f, AndroidUtilities.dpf2(24), AndroidUtilities.dpf2(24)); + matrix.postScale(0.8f, 0.8f, dpf2(24), dpf2(24)); recordedAudioPlayButton.setImageMatrix(matrix); recordedAudioPlayButton.setImageDrawable(playPauseDrawable = new MediaActionDrawable()); recordedAudioPlayButton.setScaleType(ImageView.ScaleType.MATRIX); @@ -3250,6 +3467,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific }); recordedAudioSeekBar = new SeekBarWaveformView(getContext()); + recordedAudioSeekBar.setVisibility(View.INVISIBLE); waveFormTimerLayout.addView(recordedAudioSeekBar, LayoutHelper.createLinear(0, 32, 1f, Gravity.CENTER_VERTICAL, 0, 0, 4, 0)); recordedAudioTimeTextView = new TextView(getContext()); @@ -3274,6 +3492,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } new File(audioToSendPath).delete(); } + MediaController.getInstance().stopRecording(0, false, 0, false); + millisecondsRecorded = 0; hideRecordedAudioPanel(false); checkSendButton(true); } @@ -3289,17 +3509,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific hidePopup(true, true); return; } - if (delegate.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + if (delegate.measureKeyboardHeight() > dp(20)) { int totalHeight = delegate.getContentViewHeight(); int keyboard = delegate.measureKeyboardHeight(); - if (keyboard <= AndroidUtilities.dp(20)) { + if (keyboard <= dp(20)) { totalHeight += keyboard; } if (emojiViewVisible) { totalHeight -= getEmojiPadding(); } - if (totalHeight < AndroidUtilities.dp(200)) { + if (totalHeight < dp(200)) { onKeyboardClosed = () -> senderSelectView.callOnClick(); closeKeyboard(); return; @@ -3396,12 +3616,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific senderSelectView.getLocationInWindow(location); float endX = location[0], endY = location[1]; - float off = AndroidUtilities.dp(5); - float startX = loc[0] + popupX + off + AndroidUtilities.dp(4) + offX, startY = loc[1] + popupY + off + offY; + float off = dp(5); + float startX = loc[0] + popupX + off + dp(4) + offX, startY = loc[1] + popupY + off + offY; avatar.setTranslationX(startX); avatar.setTranslationY(startY); - float startScale = (float) (SenderSelectPopup.AVATAR_SIZE_DP - 10) / SenderSelectPopup.AVATAR_SIZE_DP, endScale = senderSelectView.getLayoutParams().width / (float) AndroidUtilities.dp(SenderSelectPopup.AVATAR_SIZE_DP); + float startScale = (float) (SenderSelectPopup.AVATAR_SIZE_DP - 10) / SenderSelectPopup.AVATAR_SIZE_DP, endScale = senderSelectView.getLayoutParams().width / (float) dp(SenderSelectPopup.AVATAR_SIZE_DP); avatar.setPivotX(0); avatar.setPivotY(0); avatar.setScaleX(startScale); @@ -3457,17 +3677,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }), new SpringAnimation(avatar, DynamicAnimation.TRANSLATION_X) - .setStartValue(MathUtils.clamp(startX, endX - AndroidUtilities.dp(6), startX)) + .setStartValue(MathUtils.clamp(startX, endX - dp(6), startX)) .setSpring(new SpringForce(endX) .setStiffness(translationStiffness) .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)) - .setMinValue(endX - AndroidUtilities.dp(6)), + .setMinValue(endX - dp(6)), new SpringAnimation(avatar, DynamicAnimation.TRANSLATION_Y) - .setStartValue(MathUtils.clamp(startY, startY, endY + AndroidUtilities.dp(6))) + .setStartValue(MathUtils.clamp(startY, startY, endY + dp(6))) .setSpring(new SpringForce(endY) .setStiffness(translationStiffness) .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)) - .setMaxValue(endY + AndroidUtilities.dp(6)) + .setMaxValue(endY + dp(6)) .addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { boolean performedHapticFeedback = false; @@ -3539,13 +3759,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific senderSelectPopupWindow.setOutsideTouchable(true); senderSelectPopupWindow.setClippingEnabled(true); senderSelectPopupWindow.setFocusable(true); - senderSelectPopupWindow.getContentView().measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + senderSelectPopupWindow.getContentView().measure(View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(dp(1000), View.MeasureSpec.AT_MOST)); senderSelectPopupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); senderSelectPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); senderSelectPopupWindow.getContentView().setFocusableInTouchMode(true); senderSelectPopupWindow.setAnimationEnabled(false); - int pad = -AndroidUtilities.dp(4); + int pad = -dp(4); int[] location = new int[2]; int popupX = pad; if (AndroidUtilities.isTablet()) { @@ -3555,22 +3775,22 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific int totalHeight = delegate.getContentViewHeight(); int height = senderSelectPopupWindow.getContentView().getMeasuredHeight(); int keyboard = delegate.measureKeyboardHeight(); - if (keyboard <= AndroidUtilities.dp(20)) { + if (keyboard <= dp(20)) { totalHeight += keyboard; } if (emojiViewVisible) { totalHeight -= getEmojiPadding(); } - int shadowPad = AndroidUtilities.dp(1); + int shadowPad = dp(1); int popupY; if (height < totalHeight + pad * 2 - (parentFragment.isInBubbleMode() ? 0 : AndroidUtilities.statusBarHeight) - senderSelectPopupWindow.headerText.getMeasuredHeight()) { ChatActivityEnterView.this.getLocationInWindow(location); - popupY = location[1] - height - pad - AndroidUtilities.dp(2); - fl.addView(senderSelectPopupWindow.dimView, new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, popupY + pad + height + shadowPad + AndroidUtilities.dp(2))); + popupY = location[1] - height - pad - dp(2); + fl.addView(senderSelectPopupWindow.dimView, new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, popupY + pad + height + shadowPad + dp(2))); } else { popupY = parentFragment.isInBubbleMode() ? 0 : AndroidUtilities.statusBarHeight; - int off = AndroidUtilities.dp(14); + int off = dp(14); senderSelectPopupWindow.recyclerContainer.getLayoutParams().height = totalHeight - popupY - off - getHeightWithTopView(); fl.addView(senderSelectPopupWindow.dimView, new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, off + popupY + senderSelectPopupWindow.recyclerContainer.getLayoutParams().height + shadowPad)); } @@ -3636,7 +3856,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private void createRecordCircle() { - createOnceButton(); + createControlsView(); if (recordCircle != null) { return; } @@ -3645,16 +3865,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sizeNotifierLayout.addView(recordCircle, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); } - private void createOnceButton() { - if (onceButton != null) { + private void createControlsView() { + if (controlsView != null) { return; } - if (delegate == null || !delegate.onceVoiceAvailable()) { - return; - } - onceButton = new OnceButton(getContext()); - onceButton.setVisibility(GONE); - sizeNotifierLayout.addView(onceButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + controlsView = new ControlsView(getContext()); + controlsView.setVisibility(GONE); + sizeNotifierLayout.addView(controlsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); } private void showRestrictedHint() { @@ -3749,10 +3966,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AnimatorSet animatorSet = new AnimatorSet(); performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - ObjectAnimator translate = ObjectAnimator.ofFloat(recordCircle, "lockAnimatedTranslation", recordCircle.startTranslation); + ObjectAnimator translate = ObjectAnimator.ofFloat(this, "lockAnimatedTranslation", startTranslation); translate.setStartDelay(100); translate.setDuration(350); - ObjectAnimator snap = ObjectAnimator.ofFloat(recordCircle, "snapAnimationProgress", 1f); + ObjectAnimator snap = ObjectAnimator.ofFloat(this, "snapAnimationProgress", 1f); snap.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); snap.setDuration(250); @@ -3761,7 +3978,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific animatorSet.playTogether( snap, translate, - ObjectAnimator.ofFloat(recordCircle, "slideToCancelProgress", 1f).setDuration(200), + ObjectAnimator.ofFloat(this, "slideToCancelProgress", 1f).setDuration(200), ObjectAnimator.ofFloat(slideText, "cancelToProgress", 1f) ); @@ -3782,13 +3999,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (clip) { canvas.save(); if (child == textFieldContainer) { - int top = (int) (animatedTop + AndroidUtilities.dp(2) + chatSearchExpandOffset); + int top = (int) (animatedTop + dp(2) + chatSearchExpandOffset); if (topView != null && topView.getVisibility() == View.VISIBLE) { top += topView.getHeight(); } canvas.clipRect(0, top, getMeasuredWidth(), getMeasuredHeight()); } else { - canvas.clipRect(0, animatedTop, getMeasuredWidth(), animatedTop + child.getLayoutParams().height + AndroidUtilities.dp(2)); + canvas.clipRect(0, animatedTop, getMeasuredWidth(), animatedTop + child.getLayoutParams().height + dp(2)); } } boolean result = super.drawChild(canvas, child, drawingTime); @@ -3837,6 +4054,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return false; } + private ActionBarMenuSubItem actionScheduleButton; private boolean onSendLongClick(View view) { if (isInScheduleMode()) { return false; @@ -3874,14 +4092,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific boolean scheduleButtonValue = parentFragment != null && parentFragment.canScheduleMessage(); boolean sendWithoutSoundButtonValue = !(self || slowModeTimer > 0 && !isInScheduleMode()); if (scheduleButtonValue) { - ActionBarMenuSubItem scheduleButton = new ActionBarMenuSubItem(getContext(), true, !sendWithoutSoundButtonValue, resourcesProvider); + actionScheduleButton = new ActionBarMenuSubItem(getContext(), true, !sendWithoutSoundButtonValue, resourcesProvider); if (self) { - scheduleButton.setTextAndIcon(LocaleController.getString("SetReminder", R.string.SetReminder), R.drawable.msg_calendar2); + actionScheduleButton.setTextAndIcon(LocaleController.getString("SetReminder", R.string.SetReminder), R.drawable.msg_calendar2); } else { - scheduleButton.setTextAndIcon(LocaleController.getString("ScheduleMessage", R.string.ScheduleMessage), R.drawable.msg_calendar2); + actionScheduleButton.setTextAndIcon(LocaleController.getString("ScheduleMessage", R.string.ScheduleMessage), R.drawable.msg_calendar2); } - scheduleButton.setMinimumWidth(AndroidUtilities.dp(196)); - scheduleButton.setOnClickListener(v -> { + actionScheduleButton.setMinimumWidth(dp(196)); + actionScheduleButton.setOnClickListener(v -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } @@ -3892,12 +4110,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }, resourcesProvider); }); - sendPopupLayout.addView(scheduleButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + sendPopupLayout.addView(actionScheduleButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); SharedConfig.removeScheduledHint(); if (!self && dialog_id > 0) { sendWhenOnlineButton = new ActionBarMenuSubItem(getContext(), true, !sendWithoutSoundButtonValue, resourcesProvider); sendWhenOnlineButton.setTextAndIcon(LocaleController.getString("SendWhenOnline", R.string.SendWhenOnline), R.drawable.msg_online); - sendWhenOnlineButton.setMinimumWidth(AndroidUtilities.dp(196)); + sendWhenOnlineButton.setMinimumWidth(dp(196)); sendWhenOnlineButton.setOnClickListener(v -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); @@ -3910,7 +4128,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (sendWithoutSoundButtonValue) { ActionBarMenuSubItem sendWithoutSoundButton = new ActionBarMenuSubItem(getContext(), !scheduleButtonValue, true, resourcesProvider); sendWithoutSoundButton.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); - sendWithoutSoundButton.setMinimumWidth(AndroidUtilities.dp(196)); + sendWithoutSoundButton.setMinimumWidth(dp(196)); sendWithoutSoundButton.setOnClickListener(v -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); @@ -3941,6 +4159,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.onSendLongClick(); } } + if (actionScheduleButton != null) { + actionScheduleButton.setVisibility(voiceOnce ? View.GONE : View.VISIBLE); + } if (sendWhenOnlineButton != null) { TLRPC.User user = parentFragment.getCurrentUser(); @@ -3950,16 +4171,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific sendWhenOnlineButton.setVisibility(GONE); } } - sendPopupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); + sendPopupLayout.measure(MeasureSpec.makeMeasureSpec(dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(1000), MeasureSpec.AT_MOST)); sendPopupWindow.setFocusable(true); view.getLocationInWindow(location); int y; - if (keyboardVisible && ChatActivityEnterView.this.getMeasuredHeight() > AndroidUtilities.dp(topView != null && topView.getVisibility() == VISIBLE ? 48 + 58 : 58)) { + if (keyboardVisible && ChatActivityEnterView.this.getMeasuredHeight() > dp(topView != null && topView.getVisibility() == VISIBLE ? 48 + 58 : 58)) { y = location[1] + view.getMeasuredHeight(); } else { - y = location[1] - sendPopupLayout.getMeasuredHeight() - AndroidUtilities.dp(2); + y = location[1] - sendPopupLayout.getMeasuredHeight() - dp(2); } - sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + AndroidUtilities.dp(8), y); + sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + dp(8), y); sendPopupWindow.dimBehind(); sendButton.invalidate(); try { @@ -4058,12 +4279,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (measuredFourViewsHeight > 0) { - padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - measuredFourViewsHeight - AndroidUtilities.dp(8) - AndroidUtilities.dp(viewsCount > 4 ? 12 : 0)); + padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - measuredFourViewsHeight - dp(8) - dp(viewsCount > 4 ? 12 : 0)); } else { if (botCommandsAdapter.getItemCount() > 4) { - padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - AndroidUtilities.dp(8 + 36 * 4.3f)); + padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - dp(8 + 36 * 4.3f)); } else { - padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - AndroidUtilities.dp(8 + 36 * Math.max(1, Math.min(4, botCommandsAdapter.getItemCount())))); + padding = Math.max(0, sizeNotifierLayout.getMeasuredHeight() - dp(8 + 36 * Math.max(1, Math.min(4, botCommandsAdapter.getItemCount())))); } } @@ -4080,7 +4301,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } } - botCommandsMenuContainer.listView.setPadding(0, padding, 0, AndroidUtilities.dp(8)); + botCommandsMenuContainer.listView.setPadding(0, padding, 0, dp(8)); } } @@ -4257,7 +4478,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Override public boolean requestRectangleOnScreen(Rect rectangle) { - rectangle.bottom += AndroidUtilities.dp(1000); + rectangle.bottom += dp(1000); return super.requestRectangleOnScreen(rectangle); } @@ -4511,7 +4732,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditText.setMaxLines(6); messageEditText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); messageEditText.setGravity(Gravity.BOTTOM); - messageEditText.setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(12)); + messageEditText.setPadding(0, dp(11), 0, dp(12)); messageEditText.setBackgroundDrawable(null); messageEditText.setTextColor(getThemedColor(Theme.key_chat_messagePanelText)); messageEditText.setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkOut)); @@ -4809,7 +5030,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public boolean isRecordingAudioVideo() { - return recordingAudioVideo || (runningAnimationAudio != null && runningAnimationAudio.isRunning()); + return recordingAudioVideo || (runningAnimationAudio != null && runningAnimationAudio.isRunning()) && !recordIsCanceled; } public boolean isRecordLocked() { @@ -4822,7 +5043,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.needStartRecordVideo(5, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); + MediaController.getInstance().stopRecording(0, false, 0, false); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL); @@ -5214,7 +5435,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.onWindowSizeChanged(size); } if (topView != null) { - if (size < AndroidUtilities.dp(72) + ActionBar.getCurrentActionBarHeight()) { + if (size < dp(72) + ActionBar.getCurrentActionBarHeight()) { if (allowShowTopView) { allowShowTopView = false; if (needShowTopView) { @@ -5244,9 +5465,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private void resizeForTopView(boolean show) { LayoutParams layoutParams = (LayoutParams) textFieldContainer.getLayoutParams(); - layoutParams.topMargin = AndroidUtilities.dp(2) + (show ? topView.getLayoutParams().height : 0); + layoutParams.topMargin = dp(2) + (show ? topView.getLayoutParams().height : 0); textFieldContainer.setLayoutParams(layoutParams); - setMinimumHeight(AndroidUtilities.dp(51) + (show ? topView.getLayoutParams().height : 0)); + setMinimumHeight(dp(51) + (show ? topView.getLayoutParams().height : 0)); if (stickersExpanded) { if (searchingType == 0) { setStickersExpanded(false, true, false); @@ -5259,6 +5480,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void onDestroy() { destroyed = true; NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStarted); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordPaused); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordResumed); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStartError); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStopped); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordProgressChanged); @@ -5425,6 +5648,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (currentAccount != account) { notificationsLocker.unlock(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStarted); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordPaused); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordResumed); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStartError); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordStopped); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.recordProgressChanged); @@ -5439,6 +5664,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific currentAccount = account; accountInstance = AccountInstance.getInstance(currentAccount); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStarted); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordPaused); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordResumed); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStartError); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordStopped); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.recordProgressChanged); @@ -5583,8 +5810,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (DialogObject.isChatDialog(dialog_id)) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); TLRPC.ChatFull chatFull = accountInstance.getMessagesController().getChatFull(-dialog_id); - isChannel = ChatObject.isChannel(chat) && !chat.megagroup; - anonymously = ChatObject.getSendAsPeerId(chat, chatFull) == chat.id; + isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + anonymously = ChatObject.getSendAsPeerId(chat, chatFull) == -dialog_id; } if (anonymously) { messageEditText.setHintText(LocaleController.getString("SendAnonymously", R.string.SendAnonymously)); @@ -5689,9 +5916,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific animators.add(ObjectAnimator.ofFloat(attachButton, View.SCALE_Y, 1.0f)); animators.add(ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 1f)); animators.add(ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0)); - if (onceButton != null) { - animators.add(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); - onceButton.hideHintView(); + if (controlsView != null) { + animators.add(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0)); + controlsView.hideHintView(); } recordPannelAnimation.playTogether(animators); @@ -5729,11 +5956,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ArrayList animators = new ArrayList<>(); if (isInVideoMode()) { animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, 0.0f)); - animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.TRANSLATION_X, -AndroidUtilities.dp(20))); + animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.TRANSLATION_X, -dp(20))); animators.add(ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0)); - if (onceButton != null) { - animators.add(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0.0f)); - onceButton.hideHintView(); + if (controlsView != null) { + animators.add(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0.0f)); + controlsView.hideHintView(); } exitAnimation.playTogether(animators); if (emojiButtonPaddingAlpha == 1f) { @@ -5761,13 +5988,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific animators.add(ObjectAnimator.ofFloat(recordedAudioPlayButton, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(recordedAudioBackground, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.ALPHA, 0.0f)); - animators.add(ObjectAnimator.ofFloat(recordedAudioSeekBar, View.TRANSLATION_X, -AndroidUtilities.dp(20))); - animators.add(ObjectAnimator.ofFloat(recordedAudioPlayButton, View.TRANSLATION_X, -AndroidUtilities.dp(20))); - animators.add(ObjectAnimator.ofFloat(recordedAudioBackground, View.TRANSLATION_X, -AndroidUtilities.dp(20))); - animators.add(ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.TRANSLATION_X, -AndroidUtilities.dp(20))); - if (onceButton != null) { - animators.add(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); - onceButton.hideHintView(); + animators.add(ObjectAnimator.ofFloat(recordedAudioSeekBar, View.TRANSLATION_X, -dp(20))); + animators.add(ObjectAnimator.ofFloat(recordedAudioPlayButton, View.TRANSLATION_X, -dp(20))); + animators.add(ObjectAnimator.ofFloat(recordedAudioBackground, View.TRANSLATION_X, -dp(20))); + animators.add(ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.TRANSLATION_X, -dp(20))); + if (controlsView != null) { + animators.add(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0)); + controlsView.hideHintView(); } exitAnimation.playTogether(animators); } @@ -5837,15 +6064,35 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordPannelAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + if (videoTimelineView != null) { + videoTimelineView.setVisibility(GONE); + } + if (recordedAudioSeekBar != null) { + recordedAudioSeekBar.setVisibility(GONE); + } + if (recordedAudioPlayButton != null) { + recordedAudioPlayButton.setVisibility(GONE); + } + if (recordedAudioBackground != null) { + recordedAudioBackground.setVisibility(GONE); + } + if (recordedAudioTimeTextView != null) { + recordedAudioTimeTextView.setVisibility(GONE); + } + transformToSeekbar = 0; + isRecordingStateChanged(); hideRecordedAudioPanelInternal(); + if (recordCircle != null) { + recordCircle.setSendButtonInvisible(); + } } }); } if (recordPannelAnimation != null) { recordPannelAnimation.start(); } - if (onceButton != null) { - onceButton.invalidate(); + if (controlsView != null) { + controlsView.invalidate(); } } @@ -5933,6 +6180,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.needStartRecordVideo(4, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0); hideRecordedAudioPanel(true); checkSendButton(true); + AndroidUtilities.runOnUIThread(() -> { + if (recordCircle != null) { + recordCircle.setSendButtonInvisible(); + } + }, 100); return; } else if (audioToSend != null) { MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); @@ -5947,6 +6199,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } hideRecordedAudioPanel(true); checkSendButton(true); + AndroidUtilities.runOnUIThread(() -> { + if (recordCircle != null) { + recordCircle.setSendButtonInvisible(); + } + }, 100); return; } CharSequence message = messageEditText == null ? "" : messageEditText.getText(); @@ -6251,14 +6508,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (!delegate.hasForwardingMessages()) { sendAnimationData = new MessageObject.SendAnimationData(); - sendAnimationData.width = sendAnimationData.height = AndroidUtilities.dp(22); + sendAnimationData.width = sendAnimationData.height = dp(22); if (messageEditText != null) { messageEditText.getLocationInWindow(location); - sendAnimationData.x = location[0] + AndroidUtilities.dp(11); - sendAnimationData.y = location[1] + AndroidUtilities.dp(8 + 11); + sendAnimationData.x = location[0] + dp(11); + sendAnimationData.y = location[1] + dp(8 + 11); } else { - sendAnimationData.x = AndroidUtilities.dp(48 + 11); - sendAnimationData.y = AndroidUtilities.displaySize.y - AndroidUtilities.dp(8 + 11); + sendAnimationData.x = dp(48 + 11); + sendAnimationData.y = AndroidUtilities.displaySize.y - dp(8 + 11); } } @@ -6351,12 +6608,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (hasScheduled) { scheduledButton.setVisibility(VISIBLE); scheduledButton.setTag(1); - scheduledButton.setPivotX(AndroidUtilities.dp(48)); - animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0))); + scheduledButton.setPivotX(dp(48)); + animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0))); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, 1.0f)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.SCALE_X, 1.0f)); } else { - scheduledButton.setTranslationX(AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); + scheduledButton.setTranslationX(dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); scheduledButton.setAlpha(1.0f); scheduledButton.setScaleX(1.0f); } @@ -6483,7 +6740,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific scheduledButton.setVisibility(VISIBLE); scheduledButton.setTag(1); } - scheduledButton.setTranslationX(AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); + scheduledButton.setTranslationX(dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); scheduledButton.setAlpha(1.0f); scheduledButton.setScaleX(1.0f); scheduledButton.setScaleY(1.0f); @@ -6533,11 +6790,11 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific scheduledButton.setTag(null); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.SCALE_X, 0.0f)); - animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0))); + animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0))); } else { scheduledButton.setAlpha(0.0f); scheduledButton.setScaleX(0.0f); - scheduledButton.setTranslationX(AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); + scheduledButton.setTranslationX(dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); } } runningAnimation2.playTogether(animators); @@ -6692,7 +6949,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific scheduledButton.setAlpha(0.0f); scheduledButton.setScaleX(0.0f); scheduledButton.setScaleY(1.0f); - scheduledButton.setTranslationX(AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - AndroidUtilities.dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); + scheduledButton.setTranslationX(dp(botButton != null && botButton.getVisibility() == VISIBLE ? 96 : 48) - dp(giftButton != null && giftButton.getVisibility() == VISIBLE ? 48 : 0)); } } } @@ -6727,7 +6984,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (hasScheduled) { scheduledButton.setVisibility(VISIBLE); scheduledButton.setTag(1); - scheduledButton.setPivotX(AndroidUtilities.dp(48)); + scheduledButton.setPivotX(dp(48)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, 1.0f)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.SCALE_X, 1.0f)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, 0)); @@ -6857,7 +7114,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific scheduledButton.setTranslationX(0); } } - } else if (sendButton.getVisibility() == VISIBLE || cancelBotButton.getVisibility() == VISIBLE || expandStickersButton != null && expandStickersButton.getVisibility() == VISIBLE || slowModeButton.getVisibility() == VISIBLE) { + } else if ( + sendButton.getVisibility() == VISIBLE || + cancelBotButton.getVisibility() == VISIBLE || + expandStickersButton != null && expandStickersButton.getVisibility() == VISIBLE || + slowModeButton.getVisibility() == VISIBLE + ) { if (animated) { if (runningAnimationType == 2) { return; @@ -6892,10 +7154,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (hasScheduled) { scheduledButton.setVisibility(VISIBLE); scheduledButton.setTag(1); - scheduledButton.setPivotX(AndroidUtilities.dp(48)); + scheduledButton.setPivotX(dp(48)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, 1.0f)); animators.add(ObjectAnimator.ofFloat(scheduledButton, View.SCALE_X, 1.0f)); - animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, giftButton != null && giftButton.getVisibility() == VISIBLE ? -AndroidUtilities.dp(48) : 0)); + animators.add(ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, giftButton != null && giftButton.getVisibility() == VISIBLE ? -dp(48) : 0)); } else { scheduledButton.setAlpha(1.0f); scheduledButton.setScaleX(1.0f); @@ -7041,9 +7303,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private void setSlowModeButtonVisible(boolean visible) { slowModeButton.setVisibility(visible ? VISIBLE : GONE); - int padding = visible ? AndroidUtilities.dp(16) : 0; + int padding = visible ? dp(16) : 0; if (messageEditText != null && messageEditText.getPaddingRight() != padding) { - messageEditText.setPadding(0, AndroidUtilities.dp(11), padding, AndroidUtilities.dp(12)); + messageEditText.setPadding(0, dp(11), padding, dp(12)); } } @@ -7055,27 +7317,27 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific int oldRightMargin = layoutParams.rightMargin; if (attachVisible == 1) { if (botButton != null && botButton.getVisibility() == VISIBLE && scheduledButton != null && scheduledButton.getVisibility() == VISIBLE && attachLayout != null && attachLayout.getVisibility() == VISIBLE) { - layoutParams.rightMargin = AndroidUtilities.dp(146); + layoutParams.rightMargin = dp(146); } else if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE || scheduledButton != null && scheduledButton.getTag() != null) { - layoutParams.rightMargin = AndroidUtilities.dp(98); + layoutParams.rightMargin = dp(98); } else { - layoutParams.rightMargin = AndroidUtilities.dp(50); + layoutParams.rightMargin = dp(50); } } else if (attachVisible == 2) { - if (layoutParams.rightMargin != AndroidUtilities.dp(2)) { + if (layoutParams.rightMargin != dp(2)) { if (botButton != null && botButton.getVisibility() == VISIBLE && scheduledButton != null && scheduledButton.getVisibility() == VISIBLE && attachLayout != null && attachLayout.getVisibility() == VISIBLE) { - layoutParams.rightMargin = AndroidUtilities.dp(146); + layoutParams.rightMargin = dp(146); } else if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE || scheduledButton != null && scheduledButton.getTag() != null) { - layoutParams.rightMargin = AndroidUtilities.dp(98); + layoutParams.rightMargin = dp(98); } else { - layoutParams.rightMargin = AndroidUtilities.dp(50); + layoutParams.rightMargin = dp(50); } } } else { if (scheduledButton != null && scheduledButton.getTag() != null) { - layoutParams.rightMargin = AndroidUtilities.dp(50); + layoutParams.rightMargin = dp(50); } else { - layoutParams.rightMargin = AndroidUtilities.dp(2); + layoutParams.rightMargin = dp(2); } } if (oldRightMargin != layoutParams.rightMargin) { @@ -7096,6 +7358,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return moveToSendStateRunnable != null; } + private int lastRecordState; protected void updateRecordInterface(int recordState) { if (moveToSendStateRunnable != null) { AndroidUtilities.cancelRunOnUIThread(moveToSendStateRunnable); @@ -7106,12 +7369,19 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (recordingAudioVideo) { if (recordInterfaceState == 1) { + lastRecordState = recordState; return; } - voiceOnce = false; - if (onceButton != null) { - onceButton.periodDrawable.setValue(1, false, false); + final boolean fromPause = lastRecordState == RECORD_STATE_PREPARING; + + if (!fromPause) { + voiceOnce = false; + if (controlsView != null) { + controlsView.periodDrawable.setValue(1, false, false); + } + millisecondsRecorded = 0; } + createRecordAudioPanel(); recordInterfaceState = 1; if (emojiView != null) { @@ -7150,8 +7420,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordCircle.setVisibility(VISIBLE); recordCircle.setAmplitude(0); } - if (onceButton != null) { - onceButton.setVisibility(delegate != null && delegate.onceVoiceAvailable() ? VISIBLE : GONE); + if (controlsView != null) { + controlsView.setVisibility(VISIBLE); } if (recordDot != null) { recordDot.resetAlpha(); @@ -7163,16 +7433,24 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific runningAnimationAudio = new AnimatorSet(); - recordTimerView.setTranslationX(AndroidUtilities.dp(20)); + recordTimerView.setTranslationX(dp(20)); recordTimerView.setAlpha(0); - slideText.setTranslationX(AndroidUtilities.dp(20)); - slideText.setAlpha(0); - slideText.setCancelToProgress(0f); - slideText.setSlideX(1f); - recordCircle.setLockTranslation(10000); - slideText.setEnabled(true); + if (lastRecordState != RECORD_STATE_PREPARING) { + slideText.setTranslationX(dp(20)); + slideText.setAlpha(0); + slideText.setCancelToProgress(0f); + slideText.setSlideX(1f); + slideText.setEnabled(true); + } else { + slideText.setTranslationX(0); + slideText.setAlpha(0); + slideText.setCancelToProgress(1f); + slideText.setEnabled(true); + } + recordCircle.resetLockTranslation(lastRecordState == RECORD_STATE_PREPARING); recordIsCanceled = false; + isRecordingStateChanged(); //ENTER TRANSITION AnimatorSet iconChanges = new AnimatorSet(); @@ -7182,17 +7460,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 1), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 1), ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, 0), - ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 1), - ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, 0), - ObjectAnimator.ofFloat(slideText, View.ALPHA, 1) + ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 1) ); - if (onceButton != null) { - iconChanges.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 1)); + iconChanges.playTogether(ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, 0)); + iconChanges.playTogether(ObjectAnimator.ofFloat(slideText, View.ALPHA, 1)); + if (controlsView != null) { + iconChanges.playTogether(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 1)); } if (audioVideoSendButton != null) { iconChanges.playTogether(ObjectAnimator.ofFloat(audioVideoSendButton, View.ALPHA, 0)); } - if (botCommandsMenuButton != null) { iconChanges.playTogether( ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_Y, 0), @@ -7203,19 +7480,32 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AnimatorSet viewTransition = new AnimatorSet(); viewTransition.playTogether( - ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, AndroidUtilities.dp(20)), + ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, dp(20)), ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 0), ObjectAnimator.ofFloat(recordedAudioPanel, View.ALPHA, 1f) ); + if (fromPause) { + viewTransition.playTogether(ObjectAnimator.ofFloat(recordedAudioSeekBar, View.ALPHA, 0.0f)); + viewTransition.playTogether(ObjectAnimator.ofFloat(recordedAudioPlayButton, View.ALPHA, 0.0f)); + viewTransition.playTogether(ObjectAnimator.ofFloat(recordedAudioBackground, View.ALPHA, 0.0f)); + viewTransition.playTogether(ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.ALPHA, 0.0f)); + + viewTransition.playTogether(ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f)); + viewTransition.playTogether(ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_X, 0.0f)); + viewTransition.playTogether(ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 0.0f)); + + viewTransition.playTogether(ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, 0)); + } + if (scheduledButton != null) { viewTransition.playTogether( - ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, AndroidUtilities.dp(30)), + ObjectAnimator.ofFloat(scheduledButton, View.TRANSLATION_X, dp(30)), ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, 0f) ); } if (attachLayout != null) { viewTransition.playTogether( - ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, AndroidUtilities.dp(30)), + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, dp(30)), ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 0f) ); } @@ -7225,6 +7515,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific viewTransition.setDuration(150), ObjectAnimator.ofFloat(recordCircle, recordCircleScale, 1).setDuration(300) ); + if (!fromPause) { + runningAnimationAudio.playTogether(ObjectAnimator.ofFloat(recordCircle, recordControlsCircleScale, 1).setDuration(300)); + } runningAnimationAudio.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { @@ -7235,15 +7528,26 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific slideText.setAlpha(1f); slideText.setTranslationX(0); - recordCircle.showTooltipIfNeed(); + if (controlsView != null) { + controlsView.showTooltipIfNeed(); + } if (messageEditText != null) { messageEditText.setAlpha(0f); } + if (fromPause) { + if (recordedAudioSeekBar != null) { + recordedAudioSeekBar.setVisibility(View.GONE); + } + if (recordedAudioPanel != null) { + recordedAudioPanel.setVisibility(View.GONE); + } + isRecordingStateChanged(); + } } }); runningAnimationAudio.setInterpolator(new DecelerateInterpolator()); runningAnimationAudio.start(); - recordTimerView.start(); + recordTimerView.start(millisecondsRecorded); } else { if (recordIsCanceled && recordState == RECORD_STATE_PREPARING) { return; @@ -7259,6 +7563,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.unlockOrientation(parentActivity); wasSendTyping = false; if (recordInterfaceState == 0) { + lastRecordState = recordState; return; } accountInstance.getMessagesController().sendTyping(dialog_id, getThreadMessageId(), 2, 0); @@ -7297,17 +7602,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(recordCircle, recordCircleScale, 0.0f), + ObjectAnimator.ofFloat(recordCircle, recordControlsCircleScale, 0.0f), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordCircle, recordCircleScale, 0.0f), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 1), ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0), - ObjectAnimator.ofFloat(recordCircle, "slideToCancelProgress", 1f) + ObjectAnimator.ofFloat(this, "slideToCancelProgress", 1f) ); - if (onceButton != null) { - runningAnimationAudio.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); - onceButton.hideHintView(); + if (controlsView != null) { + runningAnimationAudio.playTogether(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0)); + controlsView.hideHintView(); } if (botCommandsMenuButton != null) { runningAnimationAudio.playTogether( @@ -7336,6 +7641,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } recordIsCanceled = true; + isRecordingStateChanged(); runningAnimationAudio.setDuration(150); } else if (recordState == RECORD_STATE_PREPARING) { if (slideText != null) { @@ -7354,6 +7660,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (recordedAudioSeekBar != null) { recordedAudioSeekBar.setVisibility(GONE); + isRecordingStateChanged(); } if (recordedAudioPanel != null) { recordedAudioPanel.setAlpha(1.0f); @@ -7366,6 +7673,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else { if (videoTimelineView != null) { videoTimelineView.setVisibility(GONE); + isRecordingStateChanged(); } if (recordedAudioTimeTextView != null) { recordedAudioTimeTextView.setVisibility(VISIBLE); @@ -7386,9 +7694,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (recordedAudioSeekBar != null) { recordedAudioSeekBar.setVisibility(VISIBLE); recordedAudioSeekBar.setAlpha(0f); + isRecordingStateChanged(); } } + sendButtonVisible = true; + snapAnimationProgress = 1f; + lockAnimatedTranslation = startTranslation; + slideToCancelProgress = 1f; + if (slideText != null) { + slideText.setCancelToProgress(1f); + } + if (controlsView != null) { + controlsView.invalidate(); + } + if (recordDeleteImageView != null) { recordDeleteImageView.setAlpha(0f); recordDeleteImageView.setScaleX(0f); @@ -7400,8 +7720,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ValueAnimator transformToSeekbar = ValueAnimator.ofFloat(0, 1f); transformToSeekbar.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); + recordCircle.setTransformToSeekbar(value); if (!isInVideoMode()) { - recordCircle.setTransformToSeekbar(value); seekBarWaveform.setWaveScaling(recordCircle.getTransformToSeekbarProgressStep3()); recordedAudioTimeTextView.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); recordedAudioPlayButton.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); @@ -7409,8 +7729,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordedAudioPlayButton.setScaleY(recordCircle.getTransformToSeekbarProgressStep3()); recordedAudioSeekBar.setAlpha(recordCircle.getTransformToSeekbarProgressStep3()); recordedAudioSeekBar.invalidate(); - } else { - recordCircle.setExitTransition(value); + } + isRecordingStateChanged(); + }); + transformToSeekbar.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + recordCircle.setTransformToSeekbar(1); + isRecordingStateChanged(); } }); @@ -7421,13 +7747,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific oldLayoutParams = recordedAudioPanel.getLayoutParams(); parent.removeView(recordedAudioPanel); - FrameLayout.LayoutParams newLayoutParams = new FrameLayout.LayoutParams(parent.getMeasuredWidth(), AndroidUtilities.dp(48)); + FrameLayout.LayoutParams newLayoutParams = new FrameLayout.LayoutParams(parent.getMeasuredWidth(), dp(48)); newLayoutParams.gravity = Gravity.BOTTOM; sizeNotifierLayout.addView(recordedAudioPanel, newLayoutParams); videoTimelineView.setVisibility(GONE); } else { videoTimelineView.setVisibility(VISIBLE); } + isRecordingStateChanged(); if (recordDeleteImageView != null) { recordDeleteImageView.setAlpha(0f); @@ -7441,7 +7768,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -AndroidUtilities.dp(20)), + ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -dp(20)), ObjectAnimator.ofFloat(slideText, View.ALPHA, 0), ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 1), ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 1f), @@ -7526,8 +7853,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific botCommandsMenuButton.setScaleY(0f); } - if (onceButton != null && onceVisible && MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3) { - onceButton.showHintView(); + if (controlsView != null && onceVisible && !voiceOnce && (MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3)) { + controlsView.showHintView(); } } }); @@ -7537,6 +7864,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific audioVideoSendButton.setVisibility(View.VISIBLE); } recordIsCanceled = true; + isRecordingStateChanged(); AnimatorSet iconsAnimator = new AnimatorSet(); iconsAnimator.playTogether( ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_SCALE, 1), @@ -7544,9 +7872,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0) ); - if (onceButton != null) { - iconsAnimator.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); - onceButton.hideHintView(); + if (controlsView != null) { + iconsAnimator.playTogether(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0)); + controlsView.hideHintView(); } if (botCommandsMenuButton != null) { @@ -7558,9 +7886,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AnimatorSet recordTimer = new AnimatorSet(); recordTimer.playTogether( ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -AndroidUtilities.dp(20)), + ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, -dp(20)), ObjectAnimator.ofFloat(slideText, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, -AndroidUtilities.dp(20)) + ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, -dp(20)) ); if (recordState != RECORD_STATE_CANCEL_BY_GESTURE) { @@ -7578,7 +7906,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } iconsAnimator.playTogether( - ObjectAnimator.ofFloat(recordCircle, "slideToCancelProgress", 1f), + ObjectAnimator.ofFloat(this, "slideToCancelProgress", 1f), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_X, 1f), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.SCALE_Y, 1f), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1f) @@ -7662,16 +7990,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific iconsAnimator, recordTimer, messageEditTextAniamtor, - ObjectAnimator.ofFloat(recordCircle, "lockAnimatedTranslation", recordCircle.startTranslation).setDuration(200) + ObjectAnimator.ofFloat(this, "lockAnimatedTranslation", startTranslation).setDuration(200) ); if (recordState == RECORD_STATE_CANCEL_BY_GESTURE) { recordCircle.canceledByGesture(); - ObjectAnimator cancel = ObjectAnimator.ofFloat(recordCircle, "slideToCancelProgress", 1f).setDuration(200); + ObjectAnimator cancel = ObjectAnimator.ofFloat(this, "slideToCancelProgress", 1f).setDuration(200); cancel.setInterpolator(CubicBezierInterpolator.EASE_BOTH); runningAnimationAudio.playTogether(cancel); } else { - Animator recordCircleAnimator = ObjectAnimator.ofFloat(recordCircle, "exitTransition", 1.0f); + Animator recordCircleAnimator = ObjectAnimator.ofFloat(this, "exitTransition", 1.0f); recordCircleAnimator.setDuration(360); recordCircleAnimator.setStartDelay(490); runningAnimationAudio.playTogether( @@ -7695,9 +8023,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1.0f) ); - if (onceButton != null) { - iconsAnimator.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); - onceButton.hideHintView(); + if (controlsView != null) { + iconsAnimator.playTogether(ObjectAnimator.ofFloat(controlsView, View.ALPHA, 0)); + controlsView.hideHintView(); } if (botCommandsMenuButton != null) { iconsAnimator.playTogether( @@ -7731,14 +8059,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AnimatorSet recordTimer = new AnimatorSet(); recordTimer.playTogether( ObjectAnimator.ofFloat(recordTimerView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, AndroidUtilities.dp(40)), + ObjectAnimator.ofFloat(recordTimerView, View.TRANSLATION_X, dp(40)), ObjectAnimator.ofFloat(slideText, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, AndroidUtilities.dp(40)) + ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, dp(40)) ); recordTimer.setDuration(150); - - Animator recordCircleAnimator = ObjectAnimator.ofFloat(recordCircle, "exitTransition", 1.0f); + Animator recordCircleAnimator = ObjectAnimator.ofFloat(this, "exitTransition", 1.0f); recordCircleAnimator.setDuration(messageTransitionIsRunning ? 220 : 360); messageTextTranslationX = 0; @@ -7762,7 +8089,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (recordState != RECORD_STATE_PREPARING && messageEditText != null) { messageEditText.requestFocus(); } - cancelRecordIntefraceInternal(); + cancelRecordInterfaceInternal(); + if (recordState != RECORD_STATE_PREPARING && recordCircle != null) { + recordCircle.setSendButtonInvisible(); + } } } }); @@ -7773,15 +8103,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } delegate.onAudioVideoInterfaceUpdated(); updateSendAsButton(); + lastRecordState = recordState; } - private void cancelRecordIntefraceInternal() { + private void cancelRecordInterfaceInternal() { if (recordPanel != null) { recordPanel.setVisibility(GONE); } if (recordCircle != null) { recordCircle.setVisibility(GONE); - recordCircle.setSendButtonInvisible(); } runningAnimationAudio = null; isRecordingStateChanged(); @@ -7809,7 +8139,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } - recordPanel = new FrameLayout(getContext()); + recordPanel = new FrameLayout(getContext()) { + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + }; recordPanel.setClipChildren(false); recordPanel.setVisibility(GONE); messageEditTextContainer.addView(recordPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); @@ -7818,7 +8153,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordTimeContainer = new LinearLayout(getContext()); recordTimeContainer.setOrientation(LinearLayout.HORIZONTAL); - recordTimeContainer.setPadding(AndroidUtilities.dp(13), 0, 0, 0); + recordTimeContainer.setPadding(dp(13), 0, 0, 0); recordTimeContainer.setFocusable(false); recordTimeContainer.addView(recordDot = new RecordDot(getContext()), LayoutHelper.createLinear(28, 28, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); @@ -7917,7 +8252,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (paint == null) { paint = new TextPaint(); - paint.setTextSize(AndroidUtilities.dp(18)); + paint.setTextSize(dp(18)); } fontMetricsInt = paint.getFontMetricsInt(); @@ -8035,7 +8370,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific openKeyboard(); if (messageEditText != null) { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) messageEditText.getLayoutParams(); - layoutParams.rightMargin = AndroidUtilities.dp(4); + layoutParams.rightMargin = dp(4); messageEditText.setLayoutParams(layoutParams); } sendButton.setVisibility(GONE); @@ -8225,7 +8560,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private void updateRecordedDeleteIconColors() { int dotColor = getThemedColor(Theme.key_chat_recordedVoiceDot); - int background = ColorUtils.blendARGB(dotColor, getThemedColor(Theme.key_chat_messagePanelBackground), 0.5f); + int background = getThemedColor(Theme.key_chat_messagePanelBackground); int greyColor = getThemedColor(Theme.key_chat_messagePanelVoiceDelete); if (recordDeleteImageView != null) { @@ -8233,6 +8568,10 @@ 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); } } @@ -8395,7 +8734,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific AndroidUtilities.updateViewVisibilityAnimated(giftButton, visible, 1f, animated); if (scheduledButton != null && scheduledButton.getVisibility() == View.VISIBLE) { - float tX = (visible ? -AndroidUtilities.dp(48) : 0) + AndroidUtilities.dp(botButton != null && botButton.getVisibility() == VISIBLE ? 48 : 0); + float tX = (visible ? -dp(48) : 0) + dp(botButton != null && botButton.getVisibility() == VISIBLE ? 48 : 0); if (animated) { scheduledButton.animate().translationX(tX).setDuration(150).start(); } else { @@ -8432,7 +8771,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (newVisibility != notifyButton.getVisibility()) { notifyButton.setVisibility(newVisibility); if (attachLayout != null) { - attachLayout.setPivotX(AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); + attachLayout.setPivotX(dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); } } } @@ -8454,14 +8793,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific notifyButton.setVisibility(notifyVisible && scheduledButton.getVisibility() != VISIBLE ? VISIBLE : GONE); } if (giftButton != null && giftButton.getVisibility() == VISIBLE) { - scheduledButton.setTranslationX(-AndroidUtilities.dp(48)); + scheduledButton.setTranslationX(-dp(48)); } } } else if (scheduledButton != null) { if (visible) { scheduledButton.setVisibility(VISIBLE); } - scheduledButton.setPivotX(AndroidUtilities.dp(24)); + scheduledButton.setPivotX(dp(24)); scheduledButtonAnimation = new AnimatorSet(); scheduledButtonAnimation.playTogether(ObjectAnimator.ofFloat(scheduledButton, View.ALPHA, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(scheduledButton, View.SCALE_X, visible ? 1.0f : 0.1f), @@ -8479,7 +8818,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific scheduledButtonAnimation.start(); } if (attachLayout != null) { - attachLayout.setPivotX(AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); + attachLayout.setPivotX(dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); } } @@ -8518,7 +8857,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } boolean wasVisible = senderSelectView != null && senderSelectView.getVisibility() == View.VISIBLE; - int pad = AndroidUtilities.dp(2); + int pad = dp(2); float startAlpha = isVisible ? 0 : 1; float endAlpha = isVisible ? 1 : 0; final float startX, endX; @@ -8707,7 +9046,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } updateFieldRight(2); - attachLayout.setPivotX(AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); + attachLayout.setPivotX(dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); } public boolean isRtlText() { @@ -8843,7 +9182,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific Runnable onRequestWebView = new Runnable() { @Override public void run() { - if (sizeNotifierLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { + if (sizeNotifierLayout.measureKeyboardHeight() > dp(20)) { AndroidUtilities.hideKeyboard(ChatActivityEnterView.this); AndroidUtilities.runOnUIThread(this, 150); return; @@ -9276,10 +9615,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity, resourcesProvider); - builder.setTitle(LocaleController.getString("ClearRecentEmojiTitle", R.string.ClearRecentEmojiTitle)); - builder.setMessage(LocaleController.getString("ClearRecentEmojiText", R.string.ClearRecentEmojiText)); - builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearForAll), (dialogInterface, i) -> emojiView.clearRecentEmoji()); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString(R.string.ClearRecentEmojiTitle)); + builder.setMessage(LocaleController.getString(R.string.ClearRecentEmojiText)); + builder.setPositiveButton(LocaleController.getString(R.string.ClearForAll), (dialogInterface, i) -> emojiView.clearRecentEmoji()); + builder.setNegativeButton(LocaleController.getString(R.string.Cancel), null); parentFragment.showDialog(builder.create()); } @@ -9422,7 +9761,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 1); stickersExpandedHeight = sizeNotifierLayout.getHeight() - (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? AndroidUtilities.statusBarHeight : 0) - ActionBar.getCurrentActionBarHeight() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight(); if (searchingType == 2) { - stickersExpandedHeight = Math.min(stickersExpandedHeight, AndroidUtilities.dp(120) + (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight)); + stickersExpandedHeight = Math.min(stickersExpandedHeight, dp(120) + (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight)); } emojiView.getLayoutParams().height = stickersExpandedHeight; emojiView.setLayerType(LAYER_TYPE_HARDWARE, null); @@ -9442,7 +9781,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } stickersDragging = false; - if ((wasExpanded && velocity >= AndroidUtilities.dp(200)) || (!wasExpanded && velocity <= AndroidUtilities.dp(-200)) || (wasExpanded && stickersExpansionProgress <= 0.6f) || (!wasExpanded && stickersExpansionProgress >= 0.4f)) { + if ((wasExpanded && velocity >= dp(200)) || (!wasExpanded && velocity <= dp(-200)) || (wasExpanded && stickersExpansionProgress <= 0.6f) || (!wasExpanded && stickersExpansionProgress >= 0.4f)) { setStickersExpanded(!wasExpanded, true, true); } else { setStickersExpanded(wasExpanded, true, true); @@ -9598,10 +9937,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific currentPopupContentType = contentType; if (keyboardHeight <= 0) { - keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", AndroidUtilities.dp(200)); + keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", dp(200)); } if (keyboardHeightLand <= 0) { - keyboardHeightLand = MessagesController.getGlobalEmojiSettings().getInt("kbd_height_land3", AndroidUtilities.dp(200)); + keyboardHeightLand = MessagesController.getGlobalEmojiSettings().getInt("kbd_height_land3", dp(200)); } int currentHeight = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight; /*if (!samePannelWasVisible && !anotherPanelWasVisible) { @@ -10037,7 +10376,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific checkBotMenu(); return; } - if (height > AndroidUtilities.dp(50) && keyboardVisible && !AndroidUtilities.isInMultiwindow) { + if (height > dp(50) && keyboardVisible && !AndroidUtilities.isInMultiwindow) { if (isWidthGreater) { keyboardHeightLand = height; MessagesController.getGlobalEmojiSettings().edit().putInt("kbd_height_land3", keyboardHeightLand).commit(); @@ -10223,9 +10562,6 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific updateRecordInterface(RECORD_STATE_CANCEL); } } - if (id == NotificationCenter.recordStopped) { - Integer reason = (Integer) args[1]; - } } else if (id == NotificationCenter.recordStarted) { int guid = (Integer) args[0]; if (guid != recordingGuid) { @@ -10243,28 +10579,41 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific recordCircle.showWaves(true, true); } if (recordTimerView != null) { - recordTimerView.start(); + recordTimerView.start(millisecondsRecorded); } if (recordDot != null) { recordDot.enterAnimation = false; } + } else if (id == NotificationCenter.recordPaused) { + recordingAudioVideo = false; + audioToSend = null; + videoToSendMessageObject = null; + } else if (id == NotificationCenter.recordResumed) { + audioToSend = null; + videoToSendMessageObject = null; + checkSendButton(true); + recordingAudioVideo = true; + updateRecordInterface(RECORD_STATE_ENTER); } else if (id == NotificationCenter.audioDidSent) { int guid = (Integer) args[0]; if (guid != recordingGuid) { return; } + millisecondsRecorded = 0; Object audio = args[1]; if (audio instanceof VideoEditedInfo) { videoToSendMessageObject = (VideoEditedInfo) audio; audioToSendPath = (String) args[2]; ArrayList keyframes = (ArrayList) args[3]; + millisecondsRecorded = videoToSendMessageObject.estimatedDuration; if (videoTimelineView != null) { videoTimelineView.setVideoPath(audioToSendPath); videoTimelineView.setKeyframes(keyframes); videoTimelineView.setVisibility(VISIBLE); videoTimelineView.setMinProgressDiff(1000.0f / videoToSendMessageObject.estimatedDuration); + isRecordingStateChanged(); } updateRecordInterface(RECORD_STATE_PREPARING); checkSendButton(false); @@ -10317,7 +10666,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific break; } } - recordedAudioTimeTextView.setText(AndroidUtilities.formatShortDuration((int) duration)); + millisecondsRecorded = (long) (duration * 1000L); + recordedAudioTimeTextView.setText(AndroidUtilities.formatShortDuration((int) (duration))); checkSendButton(false); updateRecordInterface(RECORD_STATE_PREPARING); } else { @@ -10376,6 +10726,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific updateSlowModeText(); } } else if (id == NotificationCenter.audioRecordTooShort) { + audioToSend = null; + videoToSendMessageObject = null; updateRecordInterface(RECORD_STATE_CANCEL_BY_TIME); } else if (id == NotificationCenter.updateBotMenuButton) { long botId = (long) args[0]; @@ -10419,7 +10771,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific final int origHeight = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight; int newHeight = originalViewHeight - (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? AndroidUtilities.statusBarHeight : 0) - ActionBar.getCurrentActionBarHeight() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight(); if (searchingType == 2) { - newHeight = Math.min(newHeight, AndroidUtilities.dp(120) + origHeight); + newHeight = Math.min(newHeight, dp(120) + origHeight); } int currentHeight = emojiView.getLayoutParams().height; if (currentHeight == newHeight) { @@ -10516,7 +10868,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific originalViewHeight = sizeNotifierLayout.getHeight(); stickersExpandedHeight = originalViewHeight - (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? AndroidUtilities.statusBarHeight : 0) - ActionBar.getCurrentActionBarHeight() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight(); if (searchingType == 2) { - stickersExpandedHeight = Math.min(stickersExpandedHeight, AndroidUtilities.dp(120) + origHeight); + stickersExpandedHeight = Math.min(stickersExpandedHeight, dp(120) + origHeight); } emojiView.getLayoutParams().height = stickersExpandedHeight; sizeNotifierLayout.requestLayout(); @@ -10788,8 +11140,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific delegate.needStartRecordAudio(0); MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } + audioToSend = null; + audioToSendMessageObject = null; + videoToSendMessageObject = null; + millisecondsRecorded = 0; recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL); + checkSendButton(true); } @@ -10797,18 +11154,18 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public SlideTextView(@NonNull Context context) { super(context); - smallSize = AndroidUtilities.displaySize.x <= AndroidUtilities.dp(320); + smallSize = AndroidUtilities.displaySize.x <= dp(320); grayPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - grayPaint.setTextSize(AndroidUtilities.dp(smallSize ? 13 : 15)); + grayPaint.setTextSize(dp(smallSize ? 13 : 15)); bluePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - bluePaint.setTextSize(AndroidUtilities.dp(15)); + bluePaint.setTextSize(dp(15)); bluePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); arrowPaint.setColor(getThemedColor(Theme.key_chat_messagePanelIcons)); arrowPaint.setStyle(Paint.Style.STROKE); - arrowPaint.setStrokeWidth(AndroidUtilities.dpf2(smallSize ? 1f : 1.6f)); + arrowPaint.setStrokeWidth(dpf2(smallSize ? 1f : 1.6f)); arrowPaint.setStrokeCap(Paint.Cap.ROUND); arrowPaint.setStrokeJoin(Paint.Join.ROUND); @@ -10826,7 +11183,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific bluePaint.setColor(getThemedColor(Theme.key_chat_recordVoiceCancel)); slideToAlpha = grayPaint.getAlpha(); cancelAlpha = bluePaint.getAlpha(); - selectableBackground = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(60), 0, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_recordVoiceCancel), 26)); + selectableBackground = Theme.createSimpleSelectorCircleDrawable(dp(60), 0, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_recordVoiceCancel), 26)); selectableBackground.setCallback(this); } @@ -10863,13 +11220,13 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific int heightHalf = getMeasuredHeight() >> 1; arrowPath.reset(); if (smallSize) { - arrowPath.setLastPoint(AndroidUtilities.dpf2(2.5f), heightHalf - AndroidUtilities.dpf2(3.12f)); + arrowPath.setLastPoint(dpf2(2.5f), heightHalf - dpf2(3.12f)); arrowPath.lineTo(0, heightHalf); - arrowPath.lineTo(AndroidUtilities.dpf2(2.5f), heightHalf + AndroidUtilities.dpf2(3.12f)); + arrowPath.lineTo(dpf2(2.5f), heightHalf + dpf2(3.12f)); } else { - arrowPath.setLastPoint(AndroidUtilities.dpf2(4f), heightHalf - AndroidUtilities.dpf2(5f)); + arrowPath.setLastPoint(dpf2(4f), heightHalf - dpf2(5f)); arrowPath.lineTo(0, heightHalf); - arrowPath.lineTo(AndroidUtilities.dpf2(4f), heightHalf + AndroidUtilities.dpf2(5f)); + arrowPath.lineTo(dpf2(4f), heightHalf + dpf2(5f)); } slideToLayout = new StaticLayout(slideToCancelString, grayPaint, (int) slideToCancelWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); @@ -10879,10 +11236,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Override protected void onDraw(Canvas canvas) { - if (slideToLayout == null || cancelLayout == null) { + if (slideToLayout == null || cancelLayout == null || recordCircle == null) { return; } - int w = cancelLayout.getWidth() + AndroidUtilities.dp(16); + int w = cancelLayout.getWidth() + dp(16); grayPaint.setColor(getThemedColor(Theme.key_chat_recordTime)); grayPaint.setAlpha((int) (slideToAlpha * (1f - cancelToProgress) * slideProgress)); @@ -10890,21 +11247,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific arrowPaint.setColor(grayPaint.getColor()); if (smallSize) { - xOffset = AndroidUtilities.dp(16); + xOffset = dp(16); } else { long dt = (System.currentTimeMillis() - lastUpdateTime); lastUpdateTime = System.currentTimeMillis(); if (cancelToProgress == 0 && slideProgress > 0.8f) { if (moveForward) { - xOffset += (AndroidUtilities.dp(3) / 250f) * dt; - if (xOffset > AndroidUtilities.dp(6)) { - xOffset = AndroidUtilities.dp(6); + xOffset += (dp(3) / 250f) * dt; + if (xOffset > dp(6)) { + xOffset = dp(6); moveForward = false; } } else { - xOffset -= (AndroidUtilities.dp(3) / 250f) * dt; - if (xOffset < -AndroidUtilities.dp(6)) { - xOffset = -AndroidUtilities.dp(6); + xOffset -= (dp(3) / 250f) * dt; + if (xOffset < -dp(6)) { + xOffset = -dp(6); moveForward = true; } } @@ -10913,20 +11270,20 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific boolean enableTransition = cancelCharOffset >= 0; - int slideX = (int) ((getMeasuredWidth() - slideToCancelWidth) / 2) + AndroidUtilities.dp(5); + int slideX = (int) ((getMeasuredWidth() - slideToCancelWidth) / 2) + dp(5); int cancelX = (int) ((getMeasuredWidth() - cancelWidth) / 2); float offset = enableTransition ? slideToLayout.getPrimaryHorizontal(cancelCharOffset) : 0; float cancelDiff = enableTransition ? slideX + offset - cancelX : 0; - float x = slideX + xOffset * (1f - cancelToProgress) * slideProgress - cancelDiff * cancelToProgress + AndroidUtilities.dp(16); + float x = slideX + xOffset * (1f - cancelToProgress) * slideProgress - cancelDiff * cancelToProgress + dp(16); - float offsetY = enableTransition ? 0 : cancelToProgress * AndroidUtilities.dp(12); + float offsetY = enableTransition ? 0 : cancelToProgress * dp(12); if (cancelToProgress != 1) { int slideDelta = (int) (-getMeasuredWidth() / 4 * (1f - slideProgress) + recordCircle.getTranslationX() * 0.3f); canvas.save(); - canvas.clipRect((recordTimerView == null ? 0 : recordTimerView.getLeftProperty()) + AndroidUtilities.dp(4), 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect((recordTimerView == null ? 0 : recordTimerView.getLeftProperty()) + dp(4), 0, getMeasuredWidth(), getMeasuredHeight()); canvas.save(); - canvas.translate((int) x - (smallSize ? AndroidUtilities.dp(7) : AndroidUtilities.dp(10)) + slideDelta, offsetY); + canvas.translate((int) x - (smallSize ? dp(7) : dp(10)) + slideDelta, offsetY); canvas.drawPath(arrowPath, arrowPaint); canvas.restore(); @@ -10940,7 +11297,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific float xi; float yi = (getMeasuredHeight() - cancelLayout.getHeight()) / 2f; if (!enableTransition) { - yi -= (AndroidUtilities.dp(12) - offsetY); + yi -= (dp(12) - offsetY); } if (enableTransition) { xi = x + offset; @@ -10948,7 +11305,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific xi = cancelX; } cancelRect.set((int) xi, (int) yi, (int) (xi + cancelLayout.getWidth()), (int) (yi + cancelLayout.getHeight())); - cancelRect.inset(-AndroidUtilities.dp(16), -AndroidUtilities.dp(16)); + cancelRect.inset(-dp(16), -dp(16)); if (cancelToProgress > 0) { selectableBackground.setBounds( getMeasuredWidth() / 2 - w, getMeasuredHeight() / 2 - w, @@ -11002,16 +11359,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific float replaceTransition; TextPaint textPaint; - final float replaceDistance = AndroidUtilities.dp(15); + final float replaceDistance = dp(15); float left; public TimerView(Context context) { super(context); } - public void start() { + public void start(long milliseconds) { isRunning = true; - startTime = System.currentTimeMillis(); + startTime = System.currentTimeMillis() - milliseconds; lastSendTypingTime = startTime; invalidate(); } @@ -11032,7 +11389,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected void onDraw(Canvas canvas) { if (textPaint == null) { textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - textPaint.setTextSize(AndroidUtilities.dp(15)); + textPaint.setTextSize(dp(15)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textPaint.setColor(getThemedColor(Theme.key_chat_recordTime)); } @@ -11208,21 +11565,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (botCommandsMenuButton != null && botCommandsMenuButton.getTag() != null) { botCommandsMenuButton.measure(widthMeasureSpec, heightMeasureSpec); - ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = AndroidUtilities.dp(10) + (botCommandsMenuButton == null ? 0 : botCommandsMenuButton.getMeasuredWidth()); + ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = dp(10) + (botCommandsMenuButton == null ? 0 : botCommandsMenuButton.getMeasuredWidth()); if (messageEditText != null) { - ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = AndroidUtilities.dp(57) + (botCommandsMenuButton == null ? 0 : botCommandsMenuButton.getMeasuredWidth()); + ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = dp(57) + (botCommandsMenuButton == null ? 0 : botCommandsMenuButton.getMeasuredWidth()); } } else if (senderSelectView != null && senderSelectView.getVisibility() == View.VISIBLE) { int width = senderSelectView.getLayoutParams().width, height = senderSelectView.getLayoutParams().height; senderSelectView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = AndroidUtilities.dp(16) + width; + ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = dp(16) + width; if (messageEditText != null) { - ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = AndroidUtilities.dp(63) + width; + ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = dp(63) + width; } } else { - ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = AndroidUtilities.dp(3); + ((MarginLayoutParams) emojiButton.getLayoutParams()).leftMargin = dp(3); if (messageEditText != null) { - ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = AndroidUtilities.dp(50); + ((MarginLayoutParams) messageEditText.getLayoutParams()).leftMargin = dp(50); } } updateBotCommandsMenuContainerTopPadding(); @@ -11232,7 +11589,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (botCommandsMenuButton != null) { botWebViewButton.setMeasuredButtonWidth(botCommandsMenuButton.getMeasuredWidth()); } - botWebViewButton.getLayoutParams().height = getMeasuredHeight() - AndroidUtilities.dp(2); + botWebViewButton.getLayoutParams().height = getMeasuredHeight() - dp(2); measureChild(botWebViewButton, widthMeasureSpec, heightMeasureSpec); } if (botWebViewMenuContainer != null) { @@ -11341,7 +11698,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific super.dispatchDraw(canvas); } else { canvas.save(); - canvas.clipRect(0, AndroidUtilities.dp(2), getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect(0, dp(2), getMeasuredWidth(), getMeasuredHeight()); canvas.translate(0, -emojiView.getStickersExpandOffset()); super.dispatchDraw(canvas); canvas.restore(); @@ -11367,19 +11724,22 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void setHorizontalPadding(float padding, float progress, boolean allowShare) { float leftPadding = -padding * (1f - progress); - float rightPadding = -(padding + AndroidUtilities.dp(40)) * (1f - progress); + float rightPadding = -(padding + dp(40)) * (1f - progress); float s = 0.5f + 0.5f * progress; emojiButtonPaddingScale = s; emojiButtonPaddingAlpha = progress; updateEmojiButtonParams(); emojiButton.setTranslationX(-leftPadding); - messageTextPaddingTranslationX = -leftPadding - AndroidUtilities.dp(31) * (1f - progress); + messageTextPaddingTranslationX = -leftPadding - dp(31) * (1f - progress); if (recordDeleteImageView != null) { recordDeleteImageView.setTranslationX(-leftPadding); } if (recordCircle != null) { recordCircle.setTranslationX(rightPadding); } + if (controlsView != null) { + controlsView.setTranslationX(rightPadding); + } if (recordTimeContainer != null) { recordTimeContainer.setTranslationX(-leftPadding); } @@ -11410,12 +11770,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } if (messageEditText != null) { - float scale = AndroidUtilities.lerp(0.88f, 1f, progress); + float scale = lerp(0.88f, 1f, progress); messageEditText.setPivotX(0); messageEditText.setPivotY(messageEditText.getMeasuredHeight() / 2f); messageEditText.setScaleX(scale); messageEditText.setScaleY(scale); - messageEditText.setHintRightOffset(AndroidUtilities.lerp(AndroidUtilities.dp(30), 0, progress)); + messageEditText.setHintRightOffset(lerp(dp(30), 0, progress)); } } @@ -11483,8 +11843,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific audioVideoSendButton.setVisibility(View.VISIBLE); } recordIsCanceled = true; - cancelRecordIntefraceInternal(); + isRecordingStateChanged(); + cancelRecordInterfaceInternal(); hideRecordedAudioPanelInternal(); + if (recordCircle != null) { + recordCircle.setSendButtonInvisible(); + } } public enum BotMenuButtonType { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java index 5d1ba021d..a8ce41686 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java @@ -37,7 +37,7 @@ public interface ChatActivityInterface { return 0; } - default int getTopicId() { + default long getTopicId() { return 0; } 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 4513c0c63..1ecdc91ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -3884,7 +3884,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N actionBarAnimation = null; } - boolean needsSearchItem = searchItem != null && (avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs() && ((ChatActivity) baseFragment).allowSendPhotos()); + boolean needsSearchItem = searchItem != null && (avatarSearch || false && currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs() && ((ChatActivity) baseFragment).allowSendPhotos()); boolean needMoreItem = !isPhotoPicker && (avatarPicker != 0 || !menuShowed) && currentAttachLayout == photoLayout && (photosEnabled || videosEnabled); if (currentAttachLayout == restrictedLayout) { needsSearchItem = false; @@ -4045,7 +4045,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N menuAnimator.cancel(); menuAnimator = null; } - boolean needsSearchItem = searchItem != null && actionBar.getTag() != null && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs(); + boolean needsSearchItem = avatarPicker != 0 && searchItem != null && actionBar.getTag() != null && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs(); if (menuShowed) { if (avatarPicker == 0) { selectedMenuItem.setVisibility(View.VISIBLE); 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 2232ad2f1..483a612c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -20,6 +20,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.text.TextPaint; import android.text.TextUtils; import android.view.Gravity; import android.view.MotionEvent; @@ -67,6 +68,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private SimpleTextView titleTextView; private AtomicReference titleTextLargerCopyView = new AtomicReference<>(); private SimpleTextView subtitleTextView; + private AnimatedTextView animatedSubtitleTextView; private AtomicReference subtitleTextLargerCopyView = new AtomicReference<>(); private ImageView timeItem; private TimerDrawable timerDrawable; @@ -104,8 +106,14 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emojiStatusDrawable; + protected boolean useAnimatedSubtitle() { + return false; + } + public void hideSubtitle() { - subtitleTextView.setVisibility(View.GONE); + if (getSubtitleTextView() != null) { + getSubtitleTextView().setVisibility(View.GONE); + } } public void setStoriesForceState(Integer storiesForceState) { @@ -241,14 +249,27 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleTextView.setPadding(0, AndroidUtilities.dp(6), 0, AndroidUtilities.dp(12)); addView(titleTextView); - subtitleTextView = new SimpleTextConnectedView(context, subtitleTextLargerCopyView); - subtitleTextView.setEllipsizeByGradient(true); - subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); - subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); - subtitleTextView.setTextSize(14); - subtitleTextView.setGravity(Gravity.LEFT); - subtitleTextView.setPadding(0, 0, AndroidUtilities.dp(10), 0); - addView(subtitleTextView); + if (useAnimatedSubtitle()) { + animatedSubtitleTextView = new AnimatedTextView(context, true, true, true); + animatedSubtitleTextView.setAnimationProperties(.3f, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); + animatedSubtitleTextView.setEllipsizeByGradient(true); + animatedSubtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + animatedSubtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + animatedSubtitleTextView.setTextSize(AndroidUtilities.dp(14)); + animatedSubtitleTextView.setGravity(Gravity.LEFT); + animatedSubtitleTextView.setPadding(0, 0, AndroidUtilities.dp(10), 0); + animatedSubtitleTextView.setTranslationY(-AndroidUtilities.dp(1)); + addView(animatedSubtitleTextView); + } else { + subtitleTextView = new SimpleTextConnectedView(context, subtitleTextLargerCopyView); + subtitleTextView.setEllipsizeByGradient(true); + subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + subtitleTextView.setTextSize(14); + subtitleTextView.setGravity(Gravity.LEFT); + subtitleTextView.setPadding(0, 0, AndroidUtilities.dp(10), 0); + addView(subtitleTextView); + } if (parentFragment != null) { timeItem = new ImageView(context); @@ -276,8 +297,8 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } } - if (parentFragment != null && parentFragment.getChatMode() == 0) { - if ((!parentFragment.isThreadChat() || parentFragment.isTopic) && !UserObject.isReplyUser(parentFragment.getCurrentUser())) { + if (parentFragment != null && (parentFragment.getChatMode() == 0 || parentFragment.getChatMode() == ChatActivity.MODE_SAVED)) { + if ((!parentFragment.isThreadChat() || parentFragment.isTopic) && !UserObject.isReplyUser(parentFragment.getCurrentUser()) && parentFragment.getChatMode() != ChatActivity.MODE_SAVED) { setOnClickListener(v -> openProfile(false)); } @@ -406,7 +427,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (user != null) { Bundle args = new Bundle(); - if (UserObject.isUserSelf(user)) { + if (UserObject.isUserSelf(user) && parentFragment.getChatMode() != ChatActivity.MODE_SAVED) { args.putLong("dialog_id", parentFragment.getDialogId()); int[] media = new int[MediaDataController.MEDIA_TYPES_COUNT]; System.arraycopy(sharedMediaPreloader.getLastMediaCount(), 0, media, 0, media.length); @@ -414,11 +435,21 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent fragment.setChatInfo(parentFragment.getCurrentChatInfo()); parentFragment.presentFragment(fragment); } else { - args.putLong("user_id", user.id); - args.putBoolean("reportSpam", parentFragment.hasReportSpam()); - if (timeItem != null) { - args.putLong("dialog_id", parentFragment.getDialogId()); + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + long dialogId = parentFragment.getSavedDialogId(); + args.putBoolean("saved", true); + if (dialogId >= 0) { + args.putLong("user_id", dialogId); + } else { + args.putLong("chat_id", -dialogId); + } + } else { + args.putLong("user_id", user.id); + if (timeItem != null) { + args.putLong("dialog_id", parentFragment.getDialogId()); + } } + args.putBoolean("reportSpam", parentFragment.hasReportSpam()); args.putInt("actionBarColor", getThemedColor(Theme.key_actionBarDefault)); ProfileActivity fragment = new ProfileActivity(args, sharedMediaPreloader); fragment.setUserInfo(parentFragment.getCurrentUserInfo()); @@ -430,8 +461,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } else if (chat != null) { Bundle args = new Bundle(); args.putLong("chat_id", chat.id); - if (parentFragment.isTopic) { - args.putInt("topic_id", parentFragment.getThreadMessage().getId()); + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + args.putLong("topic_id", parentFragment.getSavedDialogId()); + } else if (parentFragment.isTopic) { + args.putLong("topic_id", parentFragment.getThreadMessage().getId()); } ProfileActivity fragment = new ProfileActivity(args, sharedMediaPreloader); fragment.setChatInfo(parentFragment.getCurrentChatInfo()); @@ -458,7 +491,11 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent int availableWidth = width - AndroidUtilities.dp((avatarImageView.getVisibility() == VISIBLE ? 54 : 0) + 16); avatarImageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); titleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24 + 8) + titleTextView.getPaddingRight(), MeasureSpec.AT_MOST)); - subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + if (subtitleTextView != null) { + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + } else if (animatedSubtitleTextView != null) { + animatedSubtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + } if (timeItem != null) { timeItem.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(34), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(34), MeasureSpec.EXACTLY)); } @@ -511,7 +548,11 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent subtitleTextLargerCopyView.setTag(Theme.key_actionBarDefaultSubtitle); subtitleTextLargerCopyView.setTextSize(14); subtitleTextLargerCopyView.setGravity(Gravity.LEFT); - subtitleTextLargerCopyView.setText(subtitleTextView.getText()); + if (subtitleTextView != null) { + subtitleTextLargerCopyView.setText(subtitleTextView.getText()); + } else if (animatedSubtitleTextView != null) { + subtitleTextLargerCopyView.setText(animatedSubtitleTextView.getText()); + } subtitleTextLargerCopyView.animate().alpha(0).setDuration(350).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).withEndAction(() -> { SimpleTextView subtitleTextLargerCopyView2 = this.subtitleTextLargerCopyView.get(); if (subtitleTextLargerCopyView2 != null) { @@ -534,7 +575,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent avatarImageView.layout(leftPadding, viewTop + 1, leftPadding + AndroidUtilities.dp(42), viewTop + 1 + AndroidUtilities.dp(42)); int l = leftPadding + (avatarImageView.getVisibility() == VISIBLE ? AndroidUtilities.dp( 54) : 0) + rightAvatarPadding; SimpleTextView titleTextLargerCopyView = this.titleTextLargerCopyView.get(); - if (subtitleTextView.getVisibility() != GONE) { + if (getSubtitleTextView().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()); if (titleTextLargerCopyView != null) { titleTextLargerCopyView.layout(l, viewTop + AndroidUtilities.dp(1.3f), l + titleTextLargerCopyView.getMeasuredWidth(), viewTop + titleTextLargerCopyView.getTextHeight() + AndroidUtilities.dp(1.3f)); @@ -548,7 +589,11 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (timeItem != null) { timeItem.layout(leftPadding + AndroidUtilities.dp(16), viewTop + AndroidUtilities.dp(15), leftPadding + AndroidUtilities.dp(16 + 34), viewTop + AndroidUtilities.dp(15 + 34)); } - subtitleTextView.layout(l, viewTop + AndroidUtilities.dp(24), l + subtitleTextView.getMeasuredWidth(), viewTop + subtitleTextView.getTextHeight() + AndroidUtilities.dp(24)); + if (subtitleTextView != null) { + subtitleTextView.layout(l, viewTop + AndroidUtilities.dp(24), l + subtitleTextView.getMeasuredWidth(), viewTop + subtitleTextView.getTextHeight() + AndroidUtilities.dp(24)); + } else if (animatedSubtitleTextView != null) { + animatedSubtitleTextView.layout(l, viewTop + AndroidUtilities.dp(24), l + animatedSubtitleTextView.getMeasuredWidth(), viewTop + animatedSubtitleTextView.getTextHeight() + AndroidUtilities.dp(24)); + } SimpleTextView subtitleTextLargerCopyView = this.subtitleTextLargerCopyView.get(); if (subtitleTextLargerCopyView != null) { subtitleTextLargerCopyView.layout(l, viewTop + AndroidUtilities.dp(24), l + subtitleTextLargerCopyView.getMeasuredWidth(), viewTop + subtitleTextLargerCopyView.getTextHeight() + AndroidUtilities.dp(24)); @@ -692,7 +737,11 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent public void setSubtitle(CharSequence value) { if (lastSubtitle == null) { - subtitleTextView.setText(value); + if (subtitleTextView != null) { + subtitleTextView.setText(value); + } else if (animatedSubtitleTextView != null) { + animatedSubtitleTextView.setText(value); + } } else { lastSubtitle = value; } @@ -706,8 +755,18 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent return titleTextView; } - public SimpleTextView getSubtitleTextView() { - return subtitleTextView; + public View getSubtitleTextView() { + if (subtitleTextView != null) { + return subtitleTextView; + } + if (animatedSubtitleTextView != null) { + return animatedSubtitleTextView; + } + return null; + } + + public TextPaint getSubtitlePaint() { + return subtitleTextView != null ? subtitleTextView.getTextPaint() : animatedSubtitleTextView.getPaint(); } public void onDestroy() { @@ -717,6 +776,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } private void setTypingAnimation(boolean start) { + if (subtitleTextView == null) return; if (start) { try { int type = MessagesController.getInstance(currentAccount).getPrintingStringType(parentFragment.getDialogId(), parentFragment.getThreadId()); @@ -759,9 +819,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent return; } TLRPC.User user = parentFragment.getCurrentUser(); - if (UserObject.isUserSelf(user) || UserObject.isReplyUser(user) || parentFragment.getChatMode() != 0) { - if (subtitleTextView.getVisibility() != GONE) { - subtitleTextView.setVisibility(GONE); + if ((UserObject.isUserSelf(user) || UserObject.isReplyUser(user) || parentFragment.getChatMode() != 0) && parentFragment.getChatMode() != ChatActivity.MODE_SAVED) { + if (getSubtitleTextView().getVisibility() != GONE) { + getSubtitleTextView().setVisibility(GONE); } return; } @@ -786,7 +846,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleAnimation = new AnimatorSet(); titleAnimation.playTogether( ObjectAnimator.ofFloat(titleTextView, View.TRANSLATION_Y, AndroidUtilities.dp(9.7f)), - ObjectAnimator.ofFloat(subtitleTextView, View.ALPHA, 0.0f)); + ObjectAnimator.ofFloat(getSubtitleTextView(), View.ALPHA, 0.0f)); titleAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { @@ -796,7 +856,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent @Override public void onAnimationEnd(Animator animation) { if (titleAnimation == animation) { - subtitleTextView.setVisibility(INVISIBLE); + getSubtitleTextView().setVisibility(INVISIBLE); titleAnimation = null; } } @@ -805,13 +865,16 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleAnimation.start(); } else { titleTextView.setTranslationY(AndroidUtilities.dp(9.7f)); - subtitleTextView.setAlpha(0.0f); - subtitleTextView.setVisibility(INVISIBLE); + getSubtitleTextView().setAlpha(0.0f); + getSubtitleTextView().setVisibility(INVISIBLE); } return; } setTypingAnimation(false); - if (parentFragment.isTopic && chat != null) { + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + int messagesCount = parentFragment.getMessagesController().getSavedMessagesController().getMessagesCount(parentFragment.getSavedDialogId()); + newSubtitle = LocaleController.formatPluralString("SavedMessagesCount", Math.max(1, messagesCount)); + } else if (parentFragment.isTopic && chat != null) { TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(chat.id, parentFragment.getTopicId()); int count = 0; if (topic != null) { @@ -854,7 +917,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (parentFragment.isThreadChat()) { if (titleTextView.getTag() != null) { titleTextView.setTag(null); - subtitleTextView.setVisibility(VISIBLE); + getSubtitleTextView().setVisibility(VISIBLE); if (titleAnimation != null) { titleAnimation.cancel(); titleAnimation = null; @@ -863,7 +926,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleAnimation = new AnimatorSet(); titleAnimation.playTogether( ObjectAnimator.ofFloat(titleTextView, View.TRANSLATION_Y, 0), - ObjectAnimator.ofFloat(subtitleTextView, View.ALPHA, 1.0f)); + ObjectAnimator.ofFloat(getSubtitleTextView(), View.ALPHA, 1.0f)); titleAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -874,25 +937,35 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleAnimation.start(); } else { titleTextView.setTranslationY(0.0f); - subtitleTextView.setAlpha(1.0f); + getSubtitleTextView().setAlpha(1.0f); } } } newSubtitle = printString; if (MessagesController.getInstance(currentAccount).getPrintingStringType(parentFragment.getDialogId(), parentFragment.getThreadId()) == 5) { - newSubtitle = Emoji.replaceEmoji(newSubtitle, subtitleTextView.getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(15), false); + newSubtitle = Emoji.replaceEmoji(newSubtitle, getSubtitlePaint().getFontMetricsInt(), AndroidUtilities.dp(15), false); } useOnlineColor = true; setTypingAnimation(true); } lastSubtitleColorKey = useOnlineColor ? Theme.key_chat_status : Theme.key_actionBarDefaultSubtitle; if (lastSubtitle == null) { - subtitleTextView.setText(newSubtitle); - if (overrideSubtitleColor == null) { - subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); - subtitleTextView.setTag(lastSubtitleColorKey); + if (subtitleTextView != null) { + subtitleTextView.setText(newSubtitle); + if (overrideSubtitleColor == null) { + subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + subtitleTextView.setTag(lastSubtitleColorKey); + } else { + subtitleTextView.setTextColor(overrideSubtitleColor); + } } else { - subtitleTextView.setTextColor(overrideSubtitleColor); + animatedSubtitleTextView.setText(newSubtitle, animated); + if (overrideSubtitleColor == null) { + animatedSubtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + animatedSubtitleTextView.setTag(lastSubtitleColorKey); + } else { + animatedSubtitleTextView.setTextColor(overrideSubtitleColor); + } } } else { lastSubtitle = newSubtitle; @@ -984,6 +1057,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (avatarImageView != null) { avatarImageView.setImage(null, null, avatarDrawable, user); } + } else if (UserObject.isAnonymous(user)) { + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_ANONYMOUS); + avatarDrawable.setScaleSize(.8f); + if (avatarImageView != null) { + avatarImageView.setImage(null, null, avatarDrawable, user); + } } else if (UserObject.isUserSelf(user) && !showSelf) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); avatarDrawable.setScaleSize(.8f); @@ -1004,6 +1083,16 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } TLRPC.User user = parentFragment.getCurrentUser(); TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + long dialogId = parentFragment.getSavedDialogId(); + if (dialogId >= 0) { + user = parentFragment.getMessagesController().getUser(dialogId); + chat = null; + } else { + user = null; + chat = parentFragment.getMessagesController().getChat(-dialogId); + } + } if (user != null) { avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { @@ -1012,6 +1101,18 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (avatarImageView != null) { avatarImageView.setImage(null, null, avatarDrawable, user); } + } else if (UserObject.isAnonymous(user)) { + avatarDrawable.setScaleSize(.8f); + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_ANONYMOUS); + if (avatarImageView != null) { + avatarImageView.setImage(null, null, avatarDrawable, user); + } + } else if (UserObject.isUserSelf(user) && parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + avatarDrawable.setScaleSize(.8f); + avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_MY_NOTES); + if (avatarImageView != null) { + avatarImageView.setImage(null, null, avatarDrawable, user); + } } else if (UserObject.isUserSelf(user)) { avatarDrawable.setScaleSize(.8f); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); @@ -1062,6 +1163,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (parentFragment != null) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didUpdateConnectionState); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + } currentConnectionState = ConnectionsManager.getInstance(currentAccount).getConnectionState(); updateCurrentConnectionState(); } @@ -1076,6 +1180,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (parentFragment != null) { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didUpdateConnectionState); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); + if (parentFragment.getChatMode() == ChatActivity.MODE_SAVED) { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.savedMessagesDialogsUpdate); + } } if (emojiStatusDrawable != null) { emojiStatusDrawable.detach(); @@ -1094,10 +1201,12 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (titleTextView != null) { titleTextView.invalidate(); } - if (subtitleTextView != null) { - subtitleTextView.invalidate(); + if (getSubtitleTextView() != null) { + getSubtitleTextView().invalidate(); } invalidate(); + } else if (id == NotificationCenter.savedMessagesDialogsUpdate) { + updateSubtitle(true); } } @@ -1114,25 +1223,49 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } if (title == null) { if (lastSubtitle != null) { - subtitleTextView.setText(lastSubtitle); - lastSubtitle = null; - if (overrideSubtitleColor != null) { - subtitleTextView.setTextColor(overrideSubtitleColor); - } else if (lastSubtitleColorKey >= 0) { - subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); - subtitleTextView.setTag(lastSubtitleColorKey); + if (subtitleTextView != null) { + subtitleTextView.setText(lastSubtitle); + lastSubtitle = null; + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else if (lastSubtitleColorKey >= 0) { + subtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + subtitleTextView.setTag(lastSubtitleColorKey); + } + } else if (animatedSubtitleTextView != null) { + animatedSubtitleTextView.setText(lastSubtitle, !LocaleController.isRTL); + lastSubtitle = null; + if (overrideSubtitleColor != null) { + animatedSubtitleTextView.setTextColor(overrideSubtitleColor); + } else if (lastSubtitleColorKey >= 0) { + animatedSubtitleTextView.setTextColor(getThemedColor(lastSubtitleColorKey)); + animatedSubtitleTextView.setTag(lastSubtitleColorKey); + } } } } else { - if (lastSubtitle == null) { - lastSubtitle = subtitleTextView.getText(); - } - subtitleTextView.setText(title); - if (overrideSubtitleColor != null) { - subtitleTextView.setTextColor(overrideSubtitleColor); - } else { - subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); - subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + if (subtitleTextView != null) { + if (lastSubtitle == null) { + lastSubtitle = subtitleTextView.getText(); + } + subtitleTextView.setText(title); + if (overrideSubtitleColor != null) { + subtitleTextView.setTextColor(overrideSubtitleColor); + } else { + subtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + } + } else if (animatedSubtitleTextView != null) { + if (lastSubtitle == null) { + lastSubtitle = animatedSubtitleTextView.getText(); + } + animatedSubtitleTextView.setText(title, !LocaleController.isRTL); + if (overrideSubtitleColor != null) { + animatedSubtitleTextView.setTextColor(overrideSubtitleColor); + } else { + animatedSubtitleTextView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + animatedSubtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); + } } } } @@ -1151,7 +1284,11 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent sb.append(rightDrawable2ContentDescription); } sb.append("\n"); - sb.append(subtitleTextView.getText()); + if (subtitleTextView != null) { + sb.append(subtitleTextView.getText()); + } else if (animatedSubtitleTextView != null) { + sb.append(animatedSubtitleTextView.getText()); + } info.setContentDescription(sb); if (info.isClickable() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, LocaleController.getString("OpenProfile", R.string.OpenProfile))); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java index 63d0a6d3f..bbde88ed1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatGreetingsView.java @@ -1,24 +1,46 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.text.Layout; import android.util.TypedValue; import android.view.Gravity; import android.view.View; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; +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.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Premium.PremiumButtonView; +import org.telegram.ui.Components.Premium.StarParticlesView; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.HintView2; import java.util.Locale; @@ -44,18 +66,16 @@ public class ChatGreetingsView extends LinearLayout { titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setGravity(Gravity.CENTER_HORIZONTAL); + titleView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + titleView.setGravity(Gravity.CENTER); descriptionView = new TextView(context); + descriptionView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + descriptionView.setGravity(Gravity.CENTER); descriptionView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); descriptionView.setGravity(Gravity.CENTER_HORIZONTAL); - - stickerToSendView = new BackupImageView(context); - - addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 20, 14, 20, 14)); - addView(descriptionView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 20, 12, 20, 0)); - addView(stickerToSendView, LayoutHelper.createLinear(112, 112, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 16)); + updateLayout(); updateColors(); @@ -66,6 +86,7 @@ public class ChatGreetingsView extends LinearLayout { titleView.setText(LocaleController.formatString("NearbyPeopleGreetingsMessage", R.string.NearbyPeopleGreetingsMessage, user.first_name, LocaleController.formatDistance(distance, 1))); descriptionView.setText(LocaleController.getString("NearbyPeopleGreetingsDescription", R.string.NearbyPeopleGreetingsDescription)); } + descriptionView.setMaxWidth(HintView2.cutInFancyHalf(descriptionView.getText(), descriptionView.getPaint())); stickerToSendView.setContentDescription(descriptionView.getText()); preloadedGreetingsSticker = sticker; @@ -74,6 +95,126 @@ public class ChatGreetingsView extends LinearLayout { } } + private ImageView premiumIconView; + private TextView premiumTextView; + private TextView premiumButtonView; + + private boolean premiumLock; + public void setPremiumLock(boolean lock, long dialogId) { + if (premiumLock == lock) return; + premiumLock = lock; + if (premiumLock) { + if (premiumIconView == null) { + premiumIconView = new ImageView(getContext()); + premiumIconView.setScaleType(ImageView.ScaleType.CENTER); + premiumIconView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + premiumIconView.setBackground(Theme.createCircleDrawable(dp(78), 0x1c000000)); + premiumIconView.setImageResource(R.drawable.large_message_lock); + } + if (premiumTextView == null) { + premiumTextView = new TextView(getContext()); + premiumTextView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + premiumTextView.setGravity(Gravity.CENTER); + premiumTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + } + String username = ""; + if (dialogId >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (user != null) { + username = UserObject.getUserName(user); + } + } + String text; + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { + text = LocaleController.formatString(R.string.MessageLockedPremiumLocked, username); + } else { + text = LocaleController.formatString(R.string.MessageLockedPremium, username); + } + premiumTextView.setText(AndroidUtilities.replaceTags(text)); + premiumTextView.setMaxWidth(HintView2.cutInFancyHalf(premiumTextView.getText(), premiumTextView.getPaint())); + premiumTextView.setTextColor(getThemedColor(Theme.key_chat_serviceText)); + premiumTextView.setLineSpacing(dp(2f), 1f); + if (premiumButtonView == null) { + premiumButtonView = new TextView(getContext()) { + StarParticlesView.Drawable starParticlesDrawable; + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + starParticlesDrawable = new StarParticlesView.Drawable(10); + starParticlesDrawable.type = 100; + starParticlesDrawable.isCircle = false; + starParticlesDrawable.roundEffect = true; + starParticlesDrawable.useRotate = false; + starParticlesDrawable.useBlur = true; + starParticlesDrawable.checkBounds = true; + starParticlesDrawable.size1 = 1; + starParticlesDrawable.k1 = starParticlesDrawable.k2 = starParticlesDrawable.k3 = 0.98f; + starParticlesDrawable.paused = false; + starParticlesDrawable.speedScale = 0f; + starParticlesDrawable.minLifeTime = 750; + starParticlesDrawable.randLifeTime = 750; + starParticlesDrawable.init(); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + starParticlesDrawable.rect.set(AndroidUtilities.rectTmp); + starParticlesDrawable.rect2.set(AndroidUtilities.rectTmp); + starParticlesDrawable.resetPositions(); + + clipPath.reset(); + clipPath.addRoundRect(AndroidUtilities.rectTmp, getHeight() / 2f, getHeight() / 2f, Path.Direction.CW); + } + + private final Path clipPath = new Path(); + @Override + protected void onDraw(Canvas canvas) { + if (starParticlesDrawable != null) { + canvas.save(); + canvas.clipPath(clipPath); + starParticlesDrawable.onDraw(canvas); + canvas.restore(); + invalidate(); + } + super.onDraw(canvas); + } + }; + premiumButtonView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + premiumButtonView.setGravity(Gravity.CENTER); + premiumButtonView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + premiumButtonView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + premiumButtonView.setPadding(dp(13), dp(6.66f), dp(13), dp(7)); + premiumButtonView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(15), 0x1e000000, 0x33000000)); + + ScaleStateListAnimator.apply(premiumButtonView); + } + premiumButtonView.setText(LocaleController.getString(R.string.MessagePremiumUnlock)); + premiumButtonView.setTextColor(getThemedColor(Theme.key_chat_serviceText)); + premiumButtonView.setOnClickListener(v -> { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment != null) { + fragment.presentFragment(new PremiumPreviewFragment("contact")); + } + }); + } + updateLayout(); + } + + private void updateLayout() { + removeAllViews(); + if (premiumLock) { + addView(premiumIconView, LayoutHelper.createLinear(78, 78, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 20, 17, 20, 9)); + final boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); + addView(premiumTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 20, 0, 20, premiumLocked ? 13 : 9)); + if (!premiumLocked) { + addView(premiumButtonView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 30, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 20, 2, 20, 13)); + } + } else { + addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 20, 14, 20, 6)); + addView(descriptionView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 20, 6, 20, 0)); + addView(stickerToSendView, LayoutHelper.createLinear(112, 112, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 16)); + } + } + private void setSticker(TLRPC.Document sticker) { if (sticker == null) { return; @@ -116,7 +257,7 @@ public class ChatGreetingsView extends LinearLayout { if (photoWidth == 0) { photoHeight = (int) maxHeight; - photoWidth = photoHeight + AndroidUtilities.dp(100); + photoWidth = photoHeight + dp(100); } photoHeight *= maxWidth / photoWidth; photoWidth = (int) maxWidth; @@ -202,4 +343,59 @@ public class ChatGreetingsView extends LinearLayout { private int getThemedColor(int key) { return Theme.getColor(key, resourcesProvider); } + + public static void showPremiumSheet(Context context, int currentAccount, long dialogId, Theme.ResourcesProvider resourcesProvider) { + BottomSheet sheet = new BottomSheet(context, false, resourcesProvider); + sheet.fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(dp(16), 0, dp(16), 0); + + RLottieImageView imageView = new RLottieImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setAnimation(R.raw.large_message_lock, 80, 80); + imageView.playAnimation(); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createCircleDrawable(dp(80), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider))); + layout.addView(imageView, LayoutHelper.createLinear(80, 80, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 16)); + + final boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); + + TextView headerView = new TextView(context); + headerView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + headerView.setGravity(Gravity.CENTER); + headerView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + headerView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + headerView.setText(LocaleController.getString(premiumLocked ? R.string.PremiumMessageHeaderLocked : R.string.PremiumMessageHeader)); + layout.addView(headerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 0, 12, 0)); + + TextView descriptionView = new TextView(context); + descriptionView.setGravity(Gravity.CENTER); + descriptionView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + descriptionView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + String username = ""; + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + username = UserObject.getFirstName(user); + } + descriptionView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(premiumLocked ? R.string.PremiumMessageTextLocked : R.string.PremiumMessageText, username, username))); + layout.addView(descriptionView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 9, 12, 19)); + + if (!premiumLocked) { + PremiumButtonView button2 = new PremiumButtonView(context, true, resourcesProvider); + button2.setOnClickListener(v2 -> { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + lastFragment.presentFragment(new PremiumPreviewFragment("contact")); + sheet.dismiss(); + } + }); + button2.setOverlayText(LocaleController.getString(R.string.PremiumMessageButton), false, false); + layout.addView(button2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 4)); + } + + sheet.setCustomView(layout); + sheet.show(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java index 67f0190e7..a7f418216 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatNotificationsPopupWrapper.java @@ -158,7 +158,7 @@ public class ChatNotificationsPopupWrapper { lastDismissTime = System.currentTimeMillis(); } - public void update(long dialogId, int topicId, HashSet topicExceptions) { + public void update(long dialogId, long topicId, HashSet topicExceptions) { if (System.currentTimeMillis() - lastDismissTime < 200) { //do on popup close AndroidUtilities.runOnUIThread(() -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EarListener.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EarListener.java new file mode 100644 index 000000000..9cccda9a6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EarListener.java @@ -0,0 +1,330 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.media.AudioDeviceInfo; +import android.media.AudioManager; +import android.os.Build; +import android.os.PowerManager; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.voip.VoIPService; +import org.telegram.ui.PhotoViewer; + +public class EarListener implements SensorEventListener { + + private final Context context; + private final SensorManager sensorManager; + private final PowerManager powerManager; + private final AudioManager audioManager; + + private Sensor proximitySensor; + private Sensor accelerometerSensor; + private Sensor linearSensor; + private Sensor gravitySensor; + private PowerManager.WakeLock proximityWakeLock; + + public EarListener(@NonNull Context context) { + this.context = context; + + sensorManager = (SensorManager) ApplicationLoader.applicationContext.getSystemService(Context.SENSOR_SERVICE); + proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + linearSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); + if (linearSensor == null || gravitySensor == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("gravity or linear sensor not found"); + } + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + linearSensor = null; + gravitySensor = null; + } + + powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + proximityWakeLock = powerManager.newWakeLock(0x00000020, "telegram:proximity_lock2"); + + audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE); + } + + private boolean attached; + public void attach() { + if (!attached) { + if (gravitySensor != null) { + sensorManager.registerListener(this, gravitySensor, 30000); + } + if (linearSensor != null) { + sensorManager.registerListener(this, linearSensor, 30000); + } + if (accelerometerSensor != null) { + sensorManager.registerListener(this, accelerometerSensor, 30000); + } + sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); + if (proximityWakeLock != null && !disableWakeLockWhenNotUsed()) { + proximityWakeLock.acquire(); + } + attached = true; + } + } + + public void detach() { + if (attached) { + if (gravitySensor != null) { + sensorManager.unregisterListener(this, gravitySensor); + } + if (linearSensor != null) { + sensorManager.unregisterListener(this, linearSensor); + } + if (accelerometerSensor != null) { + sensorManager.unregisterListener(this, accelerometerSensor); + } + sensorManager.unregisterListener(this, proximitySensor); + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + attached = false; + } + } + + private boolean raised; + + public boolean isRaised() { + return raised; + } + + private VideoPlayer currentPlayer; + public void attachPlayer(VideoPlayer player) { + currentPlayer = player; + updateRaised(); + } + + protected void updateRaised() { + if (currentPlayer == null) { + return; + } + currentPlayer.setStreamType(raised ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC); + } + + private boolean accelerometerVertical; + private long lastAccelerometerDetected; + private int raisedToTop; + private int raisedToTopSign; + private int raisedToBack; + private int countLess; + private long timeSinceRaise; + private long lastTimestamp = 0; + private boolean proximityTouched; + private boolean proximityHasDifferentValues; + private float lastProximityValue = -100; + private float previousAccValue; + private float[] gravity = new float[3]; + private float[] gravityFast = new float[3]; + private float[] linearAcceleration = new float[3]; + + @Override + public void onSensorChanged(SensorEvent event) { + if (!attached || VoIPService.getSharedInstance() != null) { + return; + } + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("proximity changed to " + event.values[0] + " max value = " + event.sensor.getMaximumRange()); + } + if (lastProximityValue != event.values[0]) { + proximityHasDifferentValues = true; + } + lastProximityValue = event.values[0]; + if (proximityHasDifferentValues) { + proximityTouched = isNearToSensor(event.values[0]); + } + } else if (event.sensor == accelerometerSensor) { + final double alpha = lastTimestamp == 0 ? 0.98f : 1.0 / (1.0 + (event.timestamp - lastTimestamp) / 1000000000.0); + final float alphaFast = 0.8f; + lastTimestamp = event.timestamp; + gravity[0] = (float) (alpha * gravity[0] + (1.0 - alpha) * event.values[0]); + gravity[1] = (float) (alpha * gravity[1] + (1.0 - alpha) * event.values[1]); + gravity[2] = (float) (alpha * gravity[2] + (1.0 - alpha) * event.values[2]); + gravityFast[0] = (alphaFast * gravity[0] + (1.0f - alphaFast) * event.values[0]); + gravityFast[1] = (alphaFast * gravity[1] + (1.0f - alphaFast) * event.values[1]); + gravityFast[2] = (alphaFast * gravity[2] + (1.0f - alphaFast) * event.values[2]); + + linearAcceleration[0] = event.values[0] - gravity[0]; + linearAcceleration[1] = event.values[1] - gravity[1]; + linearAcceleration[2] = event.values[2] - gravity[2]; + } else if (event.sensor == linearSensor) { + linearAcceleration[0] = event.values[0]; + linearAcceleration[1] = event.values[1]; + linearAcceleration[2] = event.values[2]; + } else if (event.sensor == gravitySensor) { + gravityFast[0] = gravity[0] = event.values[0]; + gravityFast[1] = gravity[1] = event.values[1]; + gravityFast[2] = gravity[2] = event.values[2]; + } + final float minDist = 15.0f; + final int minCount = 6; + final int countLessMax = 10; + if (event.sensor == linearSensor || event.sensor == gravitySensor || event.sensor == accelerometerSensor) { + float val = gravity[0] * linearAcceleration[0] + gravity[1] * linearAcceleration[1] + gravity[2] * linearAcceleration[2]; + if (raisedToBack != minCount) { + if (val > 0 && previousAccValue > 0 || val < 0 && previousAccValue < 0) { + boolean goodValue; + int sign; + if (val > 0) { + goodValue = val > minDist; + sign = 1; + } else { + goodValue = val < -minDist; + sign = 2; + } + if (raisedToTopSign != 0 && raisedToTopSign != sign) { + if (raisedToTop == minCount && goodValue) { + if (raisedToBack < minCount) { + raisedToBack++; + if (raisedToBack == minCount) { + raisedToTop = 0; + raisedToTopSign = 0; + countLess = 0; + timeSinceRaise = System.currentTimeMillis(); + if (BuildVars.LOGS_ENABLED && BuildVars.DEBUG_PRIVATE_VERSION) { + FileLog.d("motion detected"); + } + } + } + } else { + if (!goodValue) { + countLess++; + } + if (countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToTop = 0; + raisedToTopSign = 0; + raisedToBack = 0; + countLess = 0; + } + } + } else { + if (goodValue && raisedToBack == 0 && (raisedToTopSign == 0 || raisedToTopSign == sign)) { + if (raisedToTop < minCount && !proximityTouched) { + raisedToTopSign = sign; + raisedToTop++; + if (raisedToTop == minCount) { + countLess = 0; + } + } + } else { + if (!goodValue) { + countLess++; + } + if (raisedToTopSign != sign || countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToBack = 0; + raisedToTop = 0; + raisedToTopSign = 0; + countLess = 0; + } + } + } + } + } + previousAccValue = val; + accelerometerVertical = gravityFast[1] > 2.5f && Math.abs(gravityFast[2]) < 4.0f && Math.abs(gravityFast[0]) > 1.5f; + } + if (raisedToBack == minCount || accelerometerVertical) { + lastAccelerometerDetected = System.currentTimeMillis(); + } + final boolean accelerometerDetected = raisedToBack == minCount || accelerometerVertical || System.currentTimeMillis() - lastAccelerometerDetected < 60; + final boolean wakelockAllowed = accelerometerDetected && !forbidRaiseToListen() && !VoIPService.isAnyKindOfCallActive() && !PhotoViewer.getInstance().isVisible(); + if (proximityWakeLock != null && disableWakeLockWhenNotUsed()) { + final boolean held = proximityWakeLock.isHeld(); + if (held && !wakelockAllowed) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("wake lock releasing"); + } + proximityWakeLock.release(); + } else if (!held && wakelockAllowed) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("wake lock acquiring"); + } + proximityWakeLock.acquire(); + } + } + if (proximityTouched && wakelockAllowed) { + if (!raised) { + raised = true; + updateRaised(); + } + raisedToBack = 0; + raisedToTop = 0; + raisedToTopSign = 0; + countLess = 0; + } else if (proximityTouched && ((accelerometerSensor == null || linearSensor == null) && gravitySensor == null) && !VoIPService.isAnyKindOfCallActive()) { + if (!raised) { + raised = true; + updateRaised(); + } + } else if (!proximityTouched) { + if (raised) { + raised = false; + updateRaised(); + } + } + if (timeSinceRaise != 0 && raisedToBack == minCount && Math.abs(System.currentTimeMillis() - timeSinceRaise) > 1000) { + raisedToBack = 0; + raisedToTop = 0; + raisedToTopSign = 0; + countLess = 0; + timeSinceRaise = 0; + } + } + + private boolean isNearToSensor(float value) { + return value < 5.0f && value != proximitySensor.getMaximumRange(); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } + + private boolean disableWakeLockWhenNotUsed() { + // Pixel devices cap phone fps to 60 when wake lock is held + // Samsung devices do much worse proximity detection when wake lock is not held + + // Solution: enable wake lock only when accelerometer detects raising, except for Samsung + return !Build.MANUFACTURER.equalsIgnoreCase("samsung"); + } + + protected boolean forbidRaiseToListen() { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo device : devices) { + final int type = device.getType(); + if (( + type == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP || + type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO || + type == AudioDeviceInfo.TYPE_BLE_HEADSET || + type == AudioDeviceInfo.TYPE_BLE_SPEAKER || + type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES || + type == AudioDeviceInfo.TYPE_WIRED_HEADSET + ) && device.isSink()) { + return true; + } + } + return false; + } else { + return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn() || audioManager.isBluetoothScoOn(); + } + } catch (Exception e) { + FileLog.e(e); + } + return false; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java index d4005f942..d55d682d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java @@ -1140,7 +1140,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N removeButtonView.setOnClickListener(ev -> { dismiss(); if (fragment != null) { - MediaDataController.getInstance(fragment.getCurrentAccount()).removeMultipleStickerSets(fragment.getFragmentView().getContext(), fragment, installedPacks); + MediaDataController.getInstance(fragment.getCurrentAccount()).removeMultipleStickerSets(fragment.getContext(), fragment, installedPacks); } else { for (int i = 0; i < installedPacks.size(); ++i) { TLRPC.TL_messages_stickerSet stickerSet = installedPacks.get(i); 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 9b4ed0589..f87e28cb7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -8985,9 +8985,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private final int currentAccount; private final long dialogId; - private final int threadId; + private final long threadId; - public ChooseStickerActionTracker(int currentAccount, long dialogId, int threadId) { + public ChooseStickerActionTracker(int currentAccount, long dialogId, long threadId) { this.currentAccount = currentAccount; this.dialogId = dialogId; this.threadId = threadId; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java index 082d2dba3..2bec00178 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java @@ -16,13 +16,10 @@ import android.text.TextUtils; import android.text.style.DynamicDrawableSpan; import android.text.style.ImageSpan; import android.util.SparseArray; -import android.util.SparseIntArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; @@ -87,12 +84,12 @@ public class ForumUtilities { return new GeneralTopicDrawable(context, scale, color, isDialog); } - public static void filterMessagesByTopic(int threadMessageId, ArrayList messageObjects) { + public static void filterMessagesByTopic(long threadMessageId, ArrayList messageObjects) { if (messageObjects == null) { return; } for (int i = 0; i < messageObjects.size(); i++) { - if (threadMessageId != MessageObject.getTopicId(messageObjects.get(i).messageOwner, true)) { + if (threadMessageId != MessageObject.getTopicId(messageObjects.get(i).currentAccount, messageObjects.get(i).messageOwner, true)) { messageObjects.remove(i); i--; } @@ -368,7 +365,7 @@ public class ForumUtilities { if (messageObject.getDialogId() > 0) { return; } - TLRPC.TL_forumTopic topic = MessagesController.getInstance(messageObject.currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), MessageObject.getTopicId(messageObject.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(messageObject.currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), MessageObject.getTopicId(messageObject.currentAccount, messageObject.messageOwner, true)); if (topic != null && messageObject.topicIconDrawable[0] instanceof ForumBubbleDrawable) { ((ForumBubbleDrawable) messageObject.topicIconDrawable[0]).setColor(topic.icon_color); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java index 6d6afa2ba..5fadf30bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -16,7 +16,6 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; -import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothProfile; import android.content.Context; @@ -73,7 +72,6 @@ import androidx.core.graphics.ColorUtils; import com.google.android.exoplayer2.ExoPlayer; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.AutoDeleteMediaTask; import org.telegram.messenger.BuildVars; @@ -98,11 +96,10 @@ import org.telegram.messenger.camera.Size; import org.telegram.messenger.video.MP4Builder; import org.telegram.messenger.video.Mp4Movie; import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.Stories.recorder.StoryEntry; import java.io.File; import java.io.FileOutputStream; @@ -163,7 +160,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private boolean deviceHasGoodCamera; private boolean requestingPermissions; private File cameraFile; + private File previewFile; private long recordStartTime; + private long recordPlusTime; private boolean recording; private long recordedTime; private boolean cancelled; @@ -401,6 +400,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter }; addView(textureOverlayView, new LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER)); + setVisibilityFromPause = false; setVisibility(INVISIBLE); blurBehindDrawable = new BlurBehindDrawable(parentView, this, 0, resourcesProvider); } @@ -494,17 +494,24 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } + protected void clipBlur(Canvas canvas) { + + } + @Override protected void onDraw(Canvas canvas) { if (drawBlur) { + canvas.save(); + clipBlur(canvas); blurBehindDrawable.draw(canvas); + canvas.restore(); } float x = cameraContainer.getX(); float y = cameraContainer.getY(); rect.set(x - AndroidUtilities.dp(8), y - AndroidUtilities.dp(8), x + cameraContainer.getMeasuredWidth() + AndroidUtilities.dp(8), y + cameraContainer.getMeasuredHeight() + AndroidUtilities.dp(8)); if (recording) { - recordedTime = System.currentTimeMillis() - recordStartTime; + recordedTime = System.currentTimeMillis() - recordStartTime + recordPlusTime; progress = Math.min(1f, recordedTime / 60000.0f); invalidate(); } @@ -519,6 +526,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } + private boolean setVisibilityFromPause; @Override public void setVisibility(int visibility) { super.setVisibility(visibility); @@ -531,10 +539,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter muteImageView.setAlpha(0.0f); muteImageView.setScaleX(1.0f); muteImageView.setScaleY(1.0f); - cameraContainer.setScaleX(0.1f); - cameraContainer.setScaleY(0.1f); - textureOverlayView.setScaleX(0.1f); - textureOverlayView.setScaleY(0.1f); + cameraContainer.setScaleX(setVisibilityFromPause ? 1f : 0.1f); + cameraContainer.setScaleY(setVisibilityFromPause ? 1f : 0.1f); + textureOverlayView.setScaleX(setVisibilityFromPause ? 1f : 0.1f); + textureOverlayView.setScaleY(setVisibilityFromPause ? 1f : 0.1f); if (cameraContainer.getMeasuredWidth() != 0) { cameraContainer.setPivotX(cameraContainer.getMeasuredWidth() / 2); cameraContainer.setPivotY(cameraContainer.getMeasuredHeight() / 2); @@ -552,7 +560,41 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - public void showCamera() { + public void togglePause() { + if (recording) { + cancelled = recordedTime < 800; + recording = false; + if (cameraThread != null) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recordStopped, recordingGuid, cancelled ? 4 : 2); + saveLastCameraBitmap(); + cameraThread.shutdown(cancelled ? 0 : 2, cancelled ? 0 : -2); + cameraThread = null; + } + if (cancelled) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.audioRecordTooShort, recordingGuid, true, (int) recordedTime); + startAnimation(false, false); + MediaController.getInstance().requestAudioFocus(false); + } else { + videoEncoder.pause(); + } + } else if (videoEncoder != null) { + videoEncoder.resume(); + hideCamera(false); + if (videoPlayer != null) { + videoPlayer.releasePlayer(true); + videoPlayer = null; + } + showCamera(true); + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + AndroidUtilities.lockOrientation(delegate.getParentActivity()); + invalidate(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recordResumed); + } + } + + public void showCamera(boolean fromPaused) { if (textureView != null) { return; } @@ -581,10 +623,12 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter textureOverlayView.setImageResource(R.drawable.icplaceholder); } cameraReady = false; - isFrontface = true; selectedCamera = null; - recordedTime = 0; - progress = 0; + if (!fromPaused) { + isFrontface = true; + recordedTime = 0; + progress = 0; + } cancelled = false; file = null; encryptedFile = null; @@ -603,15 +647,17 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - cameraFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), System.currentTimeMillis() + "_" + SharedConfig.getLastLocalId() + ".mp4") { - @Override - public boolean delete() { - if (BuildVars.LOGS_ENABLED) { - FileLog.e("delete camera file"); + if (!fromPaused) { + cameraFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), System.currentTimeMillis() + "_" + SharedConfig.getLastLocalId() + ".mp4") { + @Override + public boolean delete() { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("delete camera file"); + } + return super.delete(); } - return super.delete(); - } - }; + }; + } SharedConfig.saveConfig(); AutoDeleteMediaTask.lockFile(cameraFile); @@ -667,9 +713,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraContainer.addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); updateTextureViewSize = true; + setVisibilityFromPause = fromPaused; setVisibility(VISIBLE); - startAnimation(true); + startAnimation(true, fromPaused); MediaController.getInstance().requestAudioFocus(true); } @@ -677,7 +724,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter return cameraContainer; } - public void startAnimation(boolean open) { + public void startAnimation(boolean open, boolean fromPaused) { if (animatorSet != null) { animatorSet.removeAllListeners(); animatorSet.cancel(); @@ -690,7 +737,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraContainer.setTranslationX(0); textureOverlayView.setTranslationX(0); - animationTranslationY = getMeasuredHeight() / 2f; + animationTranslationY = fromPaused ? 0 : getMeasuredHeight() / 2f; updateTranslationY(); } opened = open; @@ -705,7 +752,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } ValueAnimator translationYAnimator = ValueAnimator.ofFloat(open ? 1f : 0f, open ? 0 : 1f); translationYAnimator.addUpdateListener(animation -> { - animationTranslationY = (getMeasuredHeight() / 2f) * (float) animation.getAnimatedValue(); + animationTranslationY = fromPaused ? 0 : (getMeasuredHeight() / 2f) * (float) animation.getAnimatedValue(); updateTranslationY(); }); animatorSet.playTogether( @@ -728,6 +775,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter public void onAnimationEnd(Animator animation) { if (animation.equals(animatorSet)) { hideCamera(true); + setVisibilityFromPause = false; setVisibility(INVISIBLE); } } @@ -775,6 +823,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter videoPlayer = null; } if (state == 4) { + if (videoEncoder != null && recordedTime > 800) { + videoEncoder.stopRecording(VideoRecorder.ENCODER_SEND_SEND, ttl); + return; + } if (BuildVars.DEBUG_VERSION && !cameraFile.exists()) { FileLog.e(new RuntimeException("file not found :( round video")); } @@ -807,7 +859,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter entry.ttl = ttl; delegate.sendMedia(entry, videoEditedInfo, notify, scheduleDate, false); if (scheduleDate != 0) { - startAnimation(false); + startAnimation(false, false); } MediaController.getInstance().requestAudioFocus(false); } else { @@ -835,7 +887,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } if (cancelled) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.audioRecordTooShort, recordingGuid, true, (int) recordedTime); - startAnimation(false); + startAnimation(false, false); MediaController.getInstance().requestAudioFocus(false); } } @@ -875,6 +927,8 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter saveLastCameraBitmap(); cameraThread.shutdown(0, 0); cameraThread = null; + } else if (videoEncoder != null) { + videoEncoder.stopRecording(VideoRecorder.ENCODER_SEND_CANCEL, 0); } if (cameraFile != null) { if (BuildVars.LOGS_ENABLED) { @@ -885,7 +939,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraFile = null; } MediaController.getInstance().requestAudioFocus(false); - startAnimation(false); + startAnimation(false, false); blurBehindDrawable.show(false); invalidate(); } @@ -1224,6 +1278,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraFile = null; } + private VideoRecorder videoEncoder; + + private Bitmap firstFrameThumb; + public class CameraGLThread extends DispatchQueue { private final static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; @@ -1254,8 +1312,6 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private Integer cameraId = 0; - private VideoRecorder videoEncoder; - private int surfaceWidth; private int surfaceHeight; @@ -1392,7 +1448,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter 0.5f + tX, 0.5f + tY }; - videoEncoder = new VideoRecorder(); + if (videoEncoder == null) { + videoEncoder = new VideoRecorder(); + } vertexBuffer = ByteBuffer.allocateDirect(verticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); vertexBuffer.put(verticesData).position(0); @@ -1509,18 +1567,32 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } cameraSurface.updateTexImage(); + boolean captureFirstFrameThumb = false; if (!recording) { + if (videoEncoder == null) { + videoEncoder = new VideoRecorder(); + } + if (videoEncoder.started) { + if (!cameraReady) { + cameraReady = true; + AndroidUtilities.runOnUIThread(() -> textureOverlayView.animate().setDuration(120).alpha(0.0f).setInterpolator(new DecelerateInterpolator()).start()); + } + } else { + captureFirstFrameThumb = true; + } videoEncoder.startRecording(cameraFile, EGL14.eglGetCurrentContext()); - recording = true; int orientation = currentSession.getCurrentOrientation(); if (orientation == 90 || orientation == 270) { float temp = scaleX; scaleX = scaleY; scaleY = temp; } + recording = true; } - videoEncoder.frameAvailable(cameraSurface, cameraId, System.nanoTime()); + if (videoEncoder != null) { + videoEncoder.frameAvailable(cameraSurface, cameraId, System.nanoTime()); + } cameraSurface.getTransformMatrix(mSTMatrix); @@ -1545,6 +1617,19 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter GLES20.glUseProgram(0); egl10.eglSwapBuffers(eglDisplay, eglSurface); + + if (captureFirstFrameThumb) { + AndroidUtilities.runOnUIThread(() -> { + if (textureView == null) { + return; + } + if (firstFrameThumb != null) { + firstFrameThumb.recycle(); + firstFrameThumb = null; + } + firstFrameThumb = textureView.getBitmap(); + }); + } } @Override @@ -1563,7 +1648,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter break; case DO_SHUTDOWN_MESSAGE: finish(); - if (recording) { + if (recording && inputMessage.arg2 != -2) { videoEncoder.stopRecording(inputMessage.arg1, inputMessage.arg2); } Looper looper = Looper.myLooper(); @@ -1657,6 +1742,8 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private static final int MSG_STOP_RECORDING = 1; private static final int MSG_VIDEOFRAME_AVAILABLE = 2; private static final int MSG_AUDIOFRAME_AVAILABLE = 3; + private static final int MSG_PAUSE_RECORDING = 4; + private static final int MSG_RESUME_RECORDING = 5; private static class EncoderHandler extends Handler { private WeakReference mWeakEncoder; @@ -1681,7 +1768,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (BuildVars.LOGS_ENABLED) { FileLog.e("InstantCamera start encoder"); } - encoder.prepareEncoder(); + encoder.prepareEncoder(inputMessage.arg1 == 1); } catch (Exception e) { FileLog.e(e); encoder.handleStopRecording(0, 0); @@ -1696,6 +1783,20 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter encoder.handleStopRecording(inputMessage.arg1, inputMessage.arg2); break; } + case MSG_PAUSE_RECORDING: { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("InstantCamera pause encoder"); + } + encoder.handlePauseRecording(); + break; + } + case MSG_RESUME_RECORDING: { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("InstantCamera resume encoder"); + } + encoder.handleResumeRecording(); + break; + } case MSG_VIDEOFRAME_AVAILABLE: { long timestamp = (((long) inputMessage.arg1) << 32) | (((long) inputMessage.arg2) & 0xffffffffL); Integer cameraId = (Integer) inputMessage.obj; @@ -1769,6 +1870,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private long lastCommitedFrameTime; private long audioStartTime = -1; + private boolean firstVideoFrameSincePause; private long currentTimestamp = 0; private long lastTimestamp = -1; @@ -1786,7 +1888,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private long desyncTime; private long videoFirst = -1; private long videoLast; + private long videoLastDt; + private long videoDiff; + private long prevVideoLast = -1; private long audioFirst = -1; + private long audioLast = -1; + private long audioLastDt = 0; + private long prevAudioLast = -1; + private long audioDiff; private boolean audioStopedByTime; private int drawProgram; @@ -1809,6 +1918,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter DispatchQueue fileWriteQueue; + private volatile boolean pauseRecorder; private Runnable recorderRunnable = new Runnable() { @RequiresApi(api = Build.VERSION_CODES.N) @@ -1821,7 +1931,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter boolean shouldUseTimestamp = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; while (!done) { - if (!running && audioRecorder.getRecordingState() != AudioRecord.RECORDSTATE_STOPPED) { + if ((!running || pauseRecorder) && audioRecorder.getRecordingState() != AudioRecord.RECORDSTATE_STOPPED) { try { audioRecorder.stop(); } catch (Exception e) { @@ -1870,12 +1980,15 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } break; } + long timestamp; if (shouldUseTimestamp) { audioRecorder.getTimestamp(audioTimestamp, AudioTimestamp.TIMEBASE_MONOTONIC); - buffer.offset[a] = audioTimestamp.nanoTime / 1000; + timestamp = audioTimestamp.nanoTime / 1000; } else { - buffer.offset[a] = audioPresentationTimeUs; + timestamp = audioPresentationTimeUs; } + buffer.offset[a] = timestamp; + buffer.read[a] = readResult; int bufferDurationUs = 1000000 * readResult / audioSampleRate / 2; if (!shouldUseTimestamp) { @@ -1904,11 +2017,22 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } catch (Exception e) { FileLog.e(e); } - handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, sendWhenDoneTTL)); + if (!pauseRecorder) { + handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, sendWhenDoneTTL)); + } } }; + private boolean started; + public void startRecording(File outputFile, android.opengl.EGLContext sharedContext) { + if (started) { + sharedEglContext = sharedContext; + handler.sendMessage(handler.obtainMessage(MSG_START_RECORDING, 1, 0)); + return; + } + + started = true; int resolution = MessagesController.getInstance(currentAccount).roundVideoSize; int bitrate = MessagesController.getInstance(currentAccount).roundVideoBitrate * 1024; AndroidUtilities.runOnUIThread(() -> { @@ -1949,7 +2073,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter generateKeyframeThumbsQueue.cleanupQueue(); generateKeyframeThumbsQueue.recycle(); } - generateKeyframeThumbsQueue = new DispatchQueue("keyframes_thumb_queque"); + generateKeyframeThumbsQueue = new DispatchQueue("keyframes_thumb_queue"); handler.sendMessage(handler.obtainMessage(MSG_START_RECORDING)); } @@ -1960,6 +2084,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter }); } + public void pause() { + handler.sendMessage(handler.obtainMessage(MSG_PAUSE_RECORDING)); + } + + public void resume() { + handler.sendMessage(handler.obtainMessage(MSG_RESUME_RECORDING)); + } + long prevTimestamp; public void frameAvailable(SurfaceTexture st, Integer cameraId, long timestampInternal) { synchronized (sync) { @@ -2002,6 +2134,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void handleAudioFrameAvailable(AudioBufferInfo input) { + if (pauseRecorder) { + return; + } if (audioStopedByTime) { return; } @@ -2016,7 +2151,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter while (true) { boolean ok = false; for (int a = 0; a < input.results; a++) { - if (a == 0 && Math.abs(videoFirst - input.offset[a]) > 10000000L) { + if (a == 0 && Math.abs(videoFirst - input.offset[a]) > 10_000_000L) { desyncTime = videoFirst - input.offset[a]; audioFirst = input.offset[a]; ok = true; @@ -2119,7 +2254,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } } - audioEncoder.queueInputBuffer(inputBufferIndex, 0, inputBuffer.position(), startWriteTime == 0 ? 0 : startWriteTime - audioStartTime, isLast ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); + long time = startWriteTime == 0 ? 0 : startWriteTime - audioStartTime; + long realtime = time; + if (prevAudioLast >= 0) { + time += prevAudioLast; + } + audioLastDt = time - audioLast; + audioLast = time; + audioEncoder.queueInputBuffer(inputBufferIndex, 0, inputBuffer.position(), time, isLast ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); } } } catch (Throwable e) { @@ -2128,6 +2270,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void handleVideoFrameAvailable(long timestampNanos, Integer cameraId) { + if (pauseRecorder) { + return; + } try { drainEncoder(false); } catch (Exception e) { @@ -2139,8 +2284,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter cameraChanged = true; lastCameraId = cameraId; } + if (prevVideoLast >= 0) { + if (videoDiff == -1) { + videoDiff = timestampNanos - prevVideoLast; + } + timestampNanos -= videoDiff; + } if (cameraChanged || lastTimestamp == -1) { - if (currentTimestamp != 0) { + if (currentTimestamp != 0 && !firstVideoFrameSincePause) { //real dt lead to asynchron aduio and video //surface may return wrong measured timestamp so big or negative // `\_(._.)_/` @@ -2163,6 +2314,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter alphaDt = dt = (timestampNanos - lastTimestamp); lastTimestamp = timestampNanos; } + firstVideoFrameSincePause = false; lastCommitedFrameTime = System.currentTimeMillis(); if (!skippedFirst) { skippedTime += dt; @@ -2178,6 +2330,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter FileLog.d("InstantCamera first video frame was at " + videoFirst); } } + videoLastDt = timestampNanos - videoLast; videoLast = timestampNanos; FloatBuffer textureBuffer = InstantCameraView.this.textureBuffer; @@ -2254,7 +2407,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } private void createKeyframeThumb() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH && frameCount % 33 == 0) { + if (generateKeyframeThumbsQueue != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH && frameCount % 33 == 0) { GenerateKeyframeThumbTask task = new GenerateKeyframeThumbTask(); generateKeyframeThumbsQueue.postRunnable(task); } @@ -2282,8 +2435,197 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } + private void handlePauseRecording() { + pauseRecorder = true; + if (previewFile != null) { + previewFile.delete(); + previewFile = null; + } + previewFile = StoryEntry.makeCacheFile(currentAccount, true); + try { + FileLog.d("InstantCamera handlePauseRecording drain encoders"); + drainEncoder(false); + } catch (Exception e) { + FileLog.e(e); + } +// if (videoEncoder != null) { +// try { +// videoEncoder.stop(); +// videoEncoder.release(); +// videoEncoder = null; +// } catch (Exception e) { +// FileLog.e(e); +// } +// } +// if (audioEncoder != null) { +// try { +// audioEncoder.stop(); +// audioEncoder.release(); +// audioEncoder = null; +// +// setBluetoothScoOn(false); +// } catch (Exception e) { +// FileLog.e(e); +// } +// } + if (mediaMuxer != null) { + if (WRITE_TO_FILE_IN_BACKGROUND) { + CountDownLatch countDownLatch = new CountDownLatch(1); + fileWriteQueue.postRunnable(() -> { + try { + mediaMuxer.finishMovie(previewFile); + } catch (Exception e) { + e.printStackTrace(); + } + countDownLatch.countDown(); + }); + try { + countDownLatch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + try { + mediaMuxer.finishMovie(previewFile); + } catch (Exception e) { + FileLog.e(e); + } + } + } +// FileLoader.getInstance(currentAccount).cancelFileUpload(videoFile.getAbsolutePath(), false); + AndroidUtilities.runOnUIThread(() -> { + videoEditedInfo = new VideoEditedInfo(); + videoEditedInfo.roundVideo = true; + videoEditedInfo.startTime = -1; + videoEditedInfo.endTime = -1; + videoEditedInfo.file = file; + videoEditedInfo.encryptedFile = encryptedFile; + videoEditedInfo.key = key; + videoEditedInfo.iv = iv; + videoEditedInfo.estimatedSize = Math.max(1, size); + videoEditedInfo.framerate = 25; + videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 360; + videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 360; + videoEditedInfo.originalPath = previewFile.getAbsolutePath(); + setupVideoPlayer(previewFile); + videoEditedInfo.estimatedDuration = recordedTime; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, videoEditedInfo, previewFile.getAbsolutePath(), keyframeThumbs); + }); + } + + private void handleResumeRecording() { + pauseRecorder = false; + } + + private void setupVideoPlayer(File file) { + videoPlayer = new VideoPlayer(); + videoPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + @Override + public void onStateChanged(boolean playWhenReady, int playbackState) { + if (videoPlayer == null) { + return; + } + if (videoPlayer.isPlaying() && playbackState == ExoPlayer.STATE_ENDED) { + videoPlayer.seekTo(videoEditedInfo.startTime > 0 ? videoEditedInfo.startTime : 0); + } + } + + @Override + public void onError(VideoPlayer player, Exception e) { + FileLog.e(e); + } + + @Override + public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + + } + + @Override + public void onRenderedFirstFrame() { + + } + + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + + } + }); + videoPlayer.setTextureView(textureView); + videoPlayer.preparePlayer(Uri.fromFile(file), "other"); + videoPlayer.play(); + videoPlayer.setMute(true); + startProgressTimer(); + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(switchCameraButton, View.ALPHA, 0.0f), + ObjectAnimator.ofInt(paint, AnimationProperties.PAINT_ALPHA, 0), + ObjectAnimator.ofFloat(muteImageView, View.ALPHA, 1.0f)); + animatorSet.setDuration(180); + animatorSet.setInterpolator(new DecelerateInterpolator()); + animatorSet.start(); + + EGL14.eglDestroySurface(eglDisplay, eglSurface); + eglSurface = EGL14.EGL_NO_SURFACE; + if (surface != null) { + surface.release(); + surface = null; + } + if (eglDisplay != EGL14.EGL_NO_DISPLAY) { + EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + EGL14.eglDestroyContext(eglDisplay, eglContext); + EGL14.eglReleaseThread(); + EGL14.eglTerminate(eglDisplay); + } + eglDisplay = EGL14.EGL_NO_DISPLAY; + eglContext = EGL14.EGL_NO_CONTEXT; + eglConfig = null; + } + + public static final int ENCODER_SEND_CANCEL = 0; + public static final int ENCODER_SEND_SEND = 1; + public static final int ENCODER_SEND_PLAYER = 2; + + private boolean sentMedia; + private void handleStopRecording(final int send, final int ttl) { - if (running) { + final boolean runDone; + if (send == ENCODER_SEND_SEND && (videoEditedInfo == null || !videoEditedInfo.needConvert()) && !delegate.isInScheduleMode()) { + runDone = false; + if (!sentMedia) { + sentMedia = true; + AndroidUtilities.runOnUIThread(() -> { + videoEditedInfo = new VideoEditedInfo(); + videoEditedInfo.startTime = -1; + videoEditedInfo.endTime = -1; + videoEditedInfo.estimatedSize = Math.max(1, size); + videoEditedInfo.roundVideo = true; + videoEditedInfo.file = file; + videoEditedInfo.encryptedFile = encryptedFile; + videoEditedInfo.key = key; + videoEditedInfo.iv = iv; + videoEditedInfo.framerate = 25; + videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 360; + videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 360; + videoEditedInfo.originalPath = videoFile.getAbsolutePath(); + videoEditedInfo.notReadyYet = true; + videoEditedInfo.thumb = firstFrameThumb; + videoEditedInfo.estimatedDuration = recordedTime; + firstFrameThumb = null; + MediaController.PhotoEntry entry = new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0); + entry.ttl = ttl; + delegate.sendMedia(entry, videoEditedInfo, true, 0, false); + }); + } + } else { + runDone = true; + } + if (running && !pauseRecorder) { FileLog.d("InstantCamera handleStopRecording running=false"); sendWhenDone = send; sendWhenDoneTTL = ttl; @@ -2316,7 +2658,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter FileLog.e(e); } } - + if (previewFile != null) { + previewFile.delete(); + previewFile = null; + } if (mediaMuxer != null) { if (WRITE_TO_FILE_IN_BACKGROUND) { CountDownLatch countDownLatch = new CountDownLatch(1); @@ -2342,6 +2687,14 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } FileLog.d("InstantCamera handleStopRecording finish muxer"); if (writingToDifferentFile) { + if (videoFile.exists()) { + try { + videoFile.delete(); + } catch (Exception e) { + FileLog.e("InstantCamera copying fileToWrite to videoFile, deleting videoFile error " + videoFile); + FileLog.e(e); + } + } if (!fileToWrite.renameTo(videoFile)) { FileLog.e("InstantCamera unable to rename file, try move file"); try { @@ -2354,112 +2707,90 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } } - if (generateKeyframeThumbsQueue != null) { - generateKeyframeThumbsQueue.cleanupQueue(); - generateKeyframeThumbsQueue.recycle(); - generateKeyframeThumbsQueue = null; + if (send != 2) { + if (generateKeyframeThumbsQueue != null) { + generateKeyframeThumbsQueue.cleanupQueue(); + generateKeyframeThumbsQueue.recycle(); + generateKeyframeThumbsQueue = null; + } } FileLog.d("InstantCamera handleStopRecording send " + send); - if (send != 0) { - AndroidUtilities.runOnUIThread(() -> { - videoEditedInfo = new VideoEditedInfo(); - videoEditedInfo.roundVideo = true; - videoEditedInfo.startTime = -1; - videoEditedInfo.endTime = -1; - videoEditedInfo.file = file; - videoEditedInfo.encryptedFile = encryptedFile; - videoEditedInfo.key = key; - videoEditedInfo.iv = iv; - videoEditedInfo.estimatedSize = Math.max(1, size); - videoEditedInfo.framerate = 25; - videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 360; - videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 360; - videoEditedInfo.originalPath = videoFile.getAbsolutePath(); - if (send == 1) { - if (delegate.isInScheduleMode()) { - AlertsCreator.createScheduleDatePickerDialog(delegate.getParentActivity(), delegate.getDialogId(), (notify, scheduleDate) -> { + if (send == ENCODER_SEND_CANCEL) { + FileLoader.getInstance(currentAccount).cancelFileUpload(videoFile.getAbsolutePath(), false); + try { + fileToWrite.delete(); + } catch (Throwable ignore) {} + try { + videoFile.delete(); + } catch (Throwable ignore) {} + } else { + if (runDone && (send != ENCODER_SEND_SEND || !sentMedia)) { + sentMedia = true; + AndroidUtilities.runOnUIThread(() -> { + if (videoEditedInfo == null) { + videoEditedInfo = new VideoEditedInfo(); + videoEditedInfo.startTime = -1; + videoEditedInfo.endTime = -1; + } + if (videoEditedInfo.needConvert()) { + file = null; + encryptedFile = null; + key = null; + iv = null; + double totalDuration = videoEditedInfo.estimatedDuration; + long startTime = videoEditedInfo.startTime >= 0 ? videoEditedInfo.startTime : 0; + long endTime = videoEditedInfo.endTime >= 0 ? videoEditedInfo.endTime : videoEditedInfo.estimatedDuration; + videoEditedInfo.estimatedDuration = endTime - startTime; + videoEditedInfo.estimatedSize = Math.max(1, (long) (size * (videoEditedInfo.estimatedDuration / totalDuration))); + videoEditedInfo.bitrate = 1000000; + if (videoEditedInfo.startTime > 0) { + videoEditedInfo.startTime *= 1000; + } + if (videoEditedInfo.endTime > 0) { + videoEditedInfo.endTime *= 1000; + } + FileLoader.getInstance(currentAccount).cancelFileUpload(cameraFile.getAbsolutePath(), false); + } else { + videoEditedInfo.estimatedSize = Math.max(1, size); + } + videoEditedInfo.roundVideo = true; + videoEditedInfo.file = file; + videoEditedInfo.encryptedFile = encryptedFile; + videoEditedInfo.key = key; + videoEditedInfo.iv = iv; + videoEditedInfo.framerate = 25; + videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 360; + videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 360; + videoEditedInfo.originalPath = videoFile.getAbsolutePath(); + if (send == ENCODER_SEND_SEND) { + if (delegate.isInScheduleMode()) { + AlertsCreator.createScheduleDatePickerDialog(delegate.getParentActivity(), delegate.getDialogId(), (notify, scheduleDate) -> { + MediaController.PhotoEntry entry = new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0); + entry.ttl = ttl; + delegate.sendMedia(entry, videoEditedInfo, notify, scheduleDate, false); + startAnimation(false, false); + }, () -> { + startAnimation(false, false); + }, resourcesProvider); + } else { MediaController.PhotoEntry entry = new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0); entry.ttl = ttl; - delegate.sendMedia(entry, videoEditedInfo, notify, scheduleDate, false); - startAnimation(false); - }, () -> { - startAnimation(false); - }, resourcesProvider); + delegate.sendMedia(entry, videoEditedInfo, true, 0, false); + } } else { - MediaController.PhotoEntry entry = new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0); - entry.ttl = ttl; - delegate.sendMedia(entry, videoEditedInfo, true, 0, false); + setupVideoPlayer(videoFile); + videoEditedInfo.estimatedDuration = recordedTime; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, videoEditedInfo, videoFile.getAbsolutePath(), keyframeThumbs); } - } else { - videoPlayer = new VideoPlayer(); - videoPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { - @Override - public void onStateChanged(boolean playWhenReady, int playbackState) { - if (videoPlayer == null) { - return; - } - if (videoPlayer.isPlaying() && playbackState == ExoPlayer.STATE_ENDED) { - videoPlayer.seekTo(videoEditedInfo.startTime > 0 ? videoEditedInfo.startTime : 0); - } - } - - @Override - public void onError(VideoPlayer player, Exception e) { - FileLog.e(e); - } - - @Override - public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - - } - - @Override - public void onRenderedFirstFrame() { - - } - - @Override - public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { - return false; - } - - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - - } - }); - videoPlayer.setTextureView(textureView); - videoPlayer.preparePlayer(Uri.fromFile(videoFile), "other"); - videoPlayer.play(); - videoPlayer.setMute(true); - startProgressTimer(); - - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether( - ObjectAnimator.ofFloat(switchCameraButton, View.ALPHA, 0.0f), - ObjectAnimator.ofInt(paint, AnimationProperties.PAINT_ALPHA, 0), - ObjectAnimator.ofFloat(muteImageView, View.ALPHA, 1.0f)); - animatorSet.setDuration(180); - animatorSet.setInterpolator(new DecelerateInterpolator()); - animatorSet.start(); - videoEditedInfo.estimatedDuration = recordedTime; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.audioDidSent, recordingGuid, videoEditedInfo, videoFile.getAbsolutePath(), keyframeThumbs); + }); + } + AndroidUtilities.runOnUIThread(() -> { + if (sentMedia && videoEditedInfo != null) { + videoEditedInfo.notReadyYet = false; } didWriteData(videoFile, 0, true); MediaController.getInstance().requestAudioFocus(false); }); - } else { - FileLoader.getInstance(currentAccount).cancelFileUpload(videoFile.getAbsolutePath(), false); - try { - fileToWrite.delete(); - } catch (Throwable ignore) { - - } - try { - videoFile.delete(); - } catch (Throwable ignore) { - - } } EGL14.eglDestroySurface(eglDisplay, eglSurface); eglSurface = EGL14.EGL_NO_SURFACE; @@ -2477,6 +2808,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter eglContext = EGL14.EGL_NO_CONTEXT; eglConfig = null; handler.exit(); + AndroidUtilities.runOnUIThread(() -> { + InstantCameraView.this.videoEncoder = null; + }); } private void setBluetoothScoOn(boolean scoOn) { @@ -2498,7 +2832,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - private void prepareEncoder() { + private void prepareEncoder(boolean fromPause) { setBluetoothScoOn(true); try { @@ -2510,14 +2844,37 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (bufferSize < recordBufferSize) { bufferSize = ((recordBufferSize / 2048) + 1) * 2048 * 2; } + buffers.clear(); for (int a = 0; a < 3; a++) { buffers.add(new AudioBufferInfo()); } + + if (fromPause) { + prevVideoLast = videoLast + videoLastDt; + prevAudioLast = audioLast + audioLastDt; + firstVideoFrameSincePause = true; + } else { + prevVideoLast = -1; + prevAudioLast = -1; + currentTimestamp = 0; + } + lastTimestamp = -1; + lastCommitedFrameTime = 0; + audioStartTime = -1; + audioFirst = -1; + videoFirst = -1; + videoLast = -1; + videoDiff = -1; + audioLast = -1; + audioDiff = -1; + skippedFirst = false; + audioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, audioSampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); audioRecorder.startRecording(); if (BuildVars.LOGS_ENABLED) { FileLog.d("InstantCamera initied audio record with channels " + audioRecorder.getChannelCount() + " sample rate = " + audioRecorder.getSampleRate() + " bufferSize = " + bufferSize); } + pauseRecorder = false; Thread thread = new Thread(recorderRunnable); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); @@ -2545,40 +2902,40 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter format.setInteger(MediaFormat.KEY_BIT_RATE, videoBitrate); format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL); - /*if (Build.VERSION.SDK_INT >= 21) { - format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); - if (Build.VERSION.SDK_INT >= 23) { - format.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel5); - } - }*/ + /*if (Build.VERSION.SDK_INT >= 21) { + format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); + if (Build.VERSION.SDK_INT >= 23) { + format.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel5); + } + }*/ videoEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); surface = videoEncoder.createInputSurface(); videoEncoder.start(); - boolean isSdCard = ImageLoader.isSdCardPath(videoFile); - fileToWrite = videoFile; - if (isSdCard) { - try { - fileToWrite = new File(ApplicationLoader.getFilesDirFixed(), "camera_tmp.mp4"); - if (fileToWrite.exists()) { - fileToWrite.delete(); + if (!fromPause) { + boolean isSdCard = ImageLoader.isSdCardPath(videoFile); + fileToWrite = videoFile; + if (isSdCard) { + try { + fileToWrite = new File(ApplicationLoader.getFilesDirFixed(), "camera_tmp.mp4"); + if (fileToWrite.exists()) { + fileToWrite.delete(); + } + writingToDifferentFile = true; + } catch (Throwable e) { + FileLog.e(e); + fileToWrite = videoFile; + writingToDifferentFile = false; } - writingToDifferentFile = true; - } catch (Throwable e) { - FileLog.e(e); - fileToWrite = videoFile; - writingToDifferentFile = false; } + Mp4Movie movie = new Mp4Movie(); + movie.setCacheFile(fileToWrite); + movie.setRotation(0); + movie.setSize(videoWidth, videoHeight); + mediaMuxer = new MP4Builder().createMovie(movie, isSecretChat, false); + mediaMuxer.setAllowSyncFiles(allowSendingWhileRecording = SharedConfig.deviceIsHigh()); } - Mp4Movie movie = new Mp4Movie(); - movie.setCacheFile(fileToWrite); - movie.setRotation(0); - movie.setSize(videoWidth, videoHeight); - mediaMuxer = new MP4Builder().createMovie(movie, isSecretChat, false); - allowSendingWhileRecording = SharedConfig.deviceIsHigh(); - - mediaMuxer.setAllowSyncFiles(allowSendingWhileRecording); AndroidUtilities.runOnUIThread(() -> { if (cancelled) { @@ -2590,8 +2947,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } AndroidUtilities.lockOrientation(delegate.getParentActivity()); - recording = true; + recordPlusTime = fromPause ? recordedTime : 0; recordStartTime = System.currentTimeMillis(); + recording = true; invalidate(); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recordStarted, recordingGuid, false); }); @@ -2714,7 +3072,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter while (true) { int encoderStatus = videoEncoder.dequeueOutputBuffer(videoBufferInfo, 10000); if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { - if (!endOfStream) { + if (!endOfStream || pauseRecorder) { break; } } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { @@ -2832,7 +3190,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter while (true) { int encoderStatus = audioEncoder.dequeueOutputBuffer(audioBufferInfo, 0); if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { - if (!endOfStream || !running && sendWhenDone == 0) { + if (!endOfStream || !running && sendWhenDone == ENCODER_SEND_CANCEL || pauseRecorder) { break; } } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 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 34e1b166e..853df57b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -135,8 +135,8 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha } if (this.sharedMediaPreloader == null) { this.sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(this); - this.sharedMediaPreloader.addDelegate(this); } + this.sharedMediaPreloader.addDelegate(this); return super.onFragmentCreate(); } @@ -537,6 +537,9 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha hideFloatingButton(true, false); } + if (type == TYPE_MEDIA && dialogId == getUserConfig().getClientUserId() && !getMessagesController().getSavedMessagesController().unsupported && getMessagesController().getSavedMessagesController().getAllCount() > 0) { + initialTab = SharedMediaLayout.TAB_SAVED_DIALOGS; + } sharedMediaLayout = new SharedMediaLayout(context, dialogId, sharedMediaPreloader, 0, null, currentChatInfo, currentUserInfo, initialTab, this, new SharedMediaLayout.Delegate() { @Override public void scrollToSharedMedia() { @@ -582,7 +585,7 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha @Override protected boolean canShowSearchItem() { - return false; + return type != TYPE_STORIES && type != TYPE_ARCHIVED_CHANNEL_STORIES; } @Override @@ -611,6 +614,11 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha return type == TYPE_STORIES || type == TYPE_ARCHIVED_CHANNEL_STORIES; } + @Override + protected boolean includeSavedDialogs() { + return type == TYPE_MEDIA && dialogId == getUserConfig().getClientUserId(); + } + @Override protected boolean isArchivedOnlyStoriesView() { return type == TYPE_ARCHIVED_CHANNEL_STORIES; @@ -937,6 +945,12 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha return; } + if (id == SharedMediaLayout.TAB_SAVED_DIALOGS) { + showSubtitle(i, true, true); + int count = getMessagesController().getSavedMessagesController().getAllCount(); + subtitleTextView[i].setText(LocaleController.formatPluralString("SavedDialogsTabCount", count), animated); + return; + } if (id < 0 || id < mediaCount.length && mediaCount[id] < 0) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java index 8f637faf0..df84143da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java @@ -69,7 +69,7 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific private RecyclerListView.OnItemClickListener mentionsOnItemClickListener; private Delegate delegate; - public MentionsContainerView(@NonNull Context context, long dialogId, int threadMessageId, BaseFragment baseFragment, SizeNotifierFrameLayout container, Theme.ResourcesProvider resourcesProvider) { + public MentionsContainerView(@NonNull Context context, long dialogId, long threadMessageId, BaseFragment baseFragment, SizeNotifierFrameLayout container, Theme.ResourcesProvider resourcesProvider) { super(context, container); this.baseFragment = baseFragment; this.sizeNotifierFrameLayout = container; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePrivateSeenView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePrivateSeenView.java new file mode 100644 index 000000000..6930c5103 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePrivateSeenView.java @@ -0,0 +1,323 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.ui.ActionBar.Theme.key_dialogGrayLine; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +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.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Premium.PremiumButtonView; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.HintView2; + +public class MessagePrivateSeenView extends FrameLayout { + + private final int currentAccount; + private final Theme.ResourcesProvider resourcesProvider; + + private final LinearLayout valueLayout; + private final TextView valueTextView; + private final TextView premiumTextView; + private final TextView loadingView; + + private final long dialogId; + private final int messageId; + private final Runnable dismiss; + + public MessagePrivateSeenView(Context context, @NonNull MessageObject messageObject, Runnable dismiss, Theme.ResourcesProvider resourcesProvider) { + super(context); + + currentAccount = messageObject.currentAccount; + this.resourcesProvider = resourcesProvider; + this.dismiss = dismiss; + + dialogId = messageObject.getDialogId(); + messageId = messageObject.getId(); + + ImageView iconView = new ImageView(context); + addView(iconView, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.CENTER_VERTICAL, 11, 0, 0, 0)); + Drawable drawable = ContextCompat.getDrawable(context, messageObject.isVoice() ? R.drawable.msg_played : R.drawable.msg_seen).mutate(); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + iconView.setImageDrawable(drawable); + + loadingView = new TextView(context); + SpannableStringBuilder text = new SpannableStringBuilder("loading text "); + text.setSpan(new LoadingSpan(loadingView, dp(96), dp(2), resourcesProvider), 0, text.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + loadingView.setTextColor(Theme.multAlpha(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider), .7f)); + loadingView.setText(text); + loadingView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + addView(loadingView, LayoutHelper.createFrame(96, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 40, -1, 8, 0)); + + valueLayout = new LinearLayout(context); + valueLayout.setOrientation(LinearLayout.HORIZONTAL); + valueLayout.setAlpha(0f); + addView(valueLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 38, 0, 8, 0)); + + valueTextView = new TextView(context); + valueTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + valueLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 0, -1, 0, 0)); + + premiumTextView = new TextView(context); + premiumTextView.setBackground(Theme.createRoundRectDrawable(dp(20), Theme.multAlpha(Theme.getColor(Theme.key_divider, resourcesProvider), .75f))); + premiumTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + premiumTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); + premiumTextView.setPadding(dp(5.33f), dp(2), dp(5.33f), dp(2.33f)); + valueLayout.addView(premiumTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 4, 0, 0, 0)); + + request(); + } + + private void request() { + setOnClickListener(null); + valueLayout.setAlpha(0f); + loadingView.setAlpha(1f); + premiumTextView.setVisibility(View.VISIBLE); + + TLRPC.TL_messages_getOutboxReadDate req = new TLRPC.TL_messages_getOutboxReadDate(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + req.msg_id = messageId; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + if ("USER_PRIVACY_RESTRICTED".equals(err.text)) { + valueTextView.setText(LocaleController.getString(R.string.PmReadUnknown)); + premiumTextView.setVisibility(View.GONE); + } else if ("YOUR_PRIVACY_RESTRICTED".equals(err.text)) { + isPremiumLocked = true; + valueTextView.setText(LocaleController.getString(R.string.PmRead)); + premiumTextView.setText(LocaleController.getString(R.string.PmReadShowWhen)); + } else { + valueTextView.setText(LocaleController.getString("UnknownError")); + premiumTextView.setVisibility(View.GONE); + BulletinFactory.of(Bulletin.BulletinWindow.make(getContext()), resourcesProvider).showForError(err); + } + } else if (res instanceof TLRPC.TL_outboxReadDate) { + TLRPC.TL_outboxReadDate r = (TLRPC.TL_outboxReadDate) res; + valueTextView.setText(LocaleController.formatString(R.string.PmReadAt, LocaleController.formatSeenDate(r.date))); + premiumTextView.setVisibility(View.GONE); + } + valueLayout.animate().alpha(1f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(320).start(); + loadingView.animate().alpha(0f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(320).start(); + + if (isPremiumLocked) { + setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), 6, 0)); + setOnClickListener(v -> showSheet(getContext(), currentAccount, dialogId, false, dismiss, this::request, resourcesProvider)); + } else { + setBackground(null); + setOnClickListener(null); + } + })); + } + + public boolean isPremiumLocked = false; + + public static void showSheet(Context context, int currentAccount, long dialogId, boolean lastSeen, Runnable dismiss, Runnable updated, Theme.ResourcesProvider resourcesProvider) { + BottomSheet sheet = new BottomSheet(context, false, resourcesProvider); + sheet.fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + + final boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(dp(16), 0, dp(16), 0); + + RLottieImageView imageView = new RLottieImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setAnimation(lastSeen ? R.raw.large_lastseen : R.raw.large_readtime, 70, 70); + imageView.playAnimation(); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createCircleDrawable(dp(80), Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider))); + layout.addView(imageView, LayoutHelper.createLinear(80, 80, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 16)); + + TextView headerView = new TextView(context); + headerView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + headerView.setGravity(Gravity.CENTER); + headerView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + headerView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + headerView.setText(LocaleController.getString(lastSeen ? R.string.PremiumLastSeenHeader1 : R.string.PremiumReadHeader1)); + layout.addView(headerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 0, 12, 0)); + + TextView descriptionView = new TextView(context); + descriptionView.setGravity(Gravity.CENTER); + descriptionView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + descriptionView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + String username = ""; + if (dialogId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + username = UserObject.getFirstName(user); + } + descriptionView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(lastSeen ? (premiumLocked ? R.string.PremiumLastSeenText1Locked : R.string.PremiumLastSeenText1) : (premiumLocked ? R.string.PremiumReadText1Locked : R.string.PremiumReadText1), username))); + layout.addView(descriptionView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 9, 32, 19)); + + ButtonWithCounterView button1 = new ButtonWithCounterView(context, resourcesProvider); + button1.setText(LocaleController.getString(lastSeen ? R.string.PremiumLastSeenButton1 : R.string.PremiumReadButton1), false); + layout.addView(button1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_HORIZONTAL)); + button1.setOnClickListener(v -> { + button1.setLoading(true); + if (lastSeen) { + TLRPC.TL_account_setPrivacy req = new TLRPC.TL_account_setPrivacy(); + req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + req.rules.add(new TLRPC.TL_inputPrivacyValueAllowAll()); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.global().showForError(err); + return; + } + + button1.setLoading(false); + sheet.dismiss(); + + BulletinFactory.global().createSimpleBulletin(R.raw.chats_infotip, LocaleController.getString(R.string.PremiumLastSeenSet)).show(); + if (updated != null) { + updated.run(); + } + })); + } else { + TLRPC.TL_account_setGlobalPrivacySettings req = new TLRPC.TL_account_setGlobalPrivacySettings(); + req.settings = ContactsController.getInstance(currentAccount).getGlobalPrivacySettings(); + if (req.settings == null) { + req.settings = new TLRPC.TL_globalPrivacySettings(); + } + req.settings.hide_read_marks = false; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (err != null) { + BulletinFactory.of(Bulletin.BulletinWindow.make(context), resourcesProvider).showForError(err); + return; + } + + button1.setLoading(false); + sheet.dismiss(); + + BulletinFactory.of(Bulletin.BulletinWindow.make(context), resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, LocaleController.getString(R.string.PremiumReadSet)).show(); + if (updated != null) { + updated.run(); + } + })); + } + }); + + if (!premiumLocked) { + SimpleTextView or = new SimpleTextView(context) { + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + paint.setColor(Theme.getColor(Theme.key_dialogGrayLine, resourcesProvider)); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(1); + final float cy = getHeight() / 2f; + canvas.drawLine(0, cy, getWidth() / 2f - getTextWidth() / 2f - dp(8), cy, paint); + canvas.drawLine(getWidth() / 2f + getTextWidth() / 2f + dp(8), cy, getWidth(), cy, paint); + + super.dispatchDraw(canvas); + } + }; + or.setGravity(Gravity.CENTER); + or.setAlignment(Layout.Alignment.ALIGN_CENTER); + or.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); + or.setText(" " + LocaleController.getString(R.string.PremiumOr) + " "); + or.setTextSize(14); + layout.addView(or, LayoutHelper.createLinear(270, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 17, 12, 17)); + + TextView headerView2 = new TextView(context); + headerView2.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + headerView2.setGravity(Gravity.CENTER); + headerView2.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + headerView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + headerView2.setText(LocaleController.getString(lastSeen ? R.string.PremiumLastSeenHeader2 : R.string.PremiumReadHeader2)); + layout.addView(headerView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 0, 12, 0)); + + TextView descriptionView2 = new TextView(context); + descriptionView2.setGravity(Gravity.CENTER); + descriptionView2.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + descriptionView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + descriptionView2.setText(AndroidUtilities.replaceTags(LocaleController.formatString(lastSeen ? R.string.PremiumLastSeenText2 : R.string.PremiumReadText2, username))); + layout.addView(descriptionView2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 9, 32, 19)); + + PremiumButtonView button2 = new PremiumButtonView(context, true, resourcesProvider); + button2.setOnClickListener(v2 -> { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + lastFragment.presentFragment(new PremiumPreviewFragment(lastSeen ? "lastseen" : "readtime")); + sheet.dismiss(); + if (dismiss != null) { + dismiss.run(); + } + } + }); + button2.setOverlayText(LocaleController.getString(lastSeen ? R.string.PremiumLastSeenButton2 : R.string.PremiumReadButton2), false, false); + layout.addView(button2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 4)); + } + + sheet.setCustomView(layout); + sheet.show(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.hideVisible(); + } + + float minWidth = -1; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + View parent = (View) getParent(); + int width = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + + if (minWidth < 0) { + minWidth = 0; + minWidth = Math.max(minWidth, dp(40 + 96 + 8)); + minWidth = Math.max(minWidth, dp(40 + 8) + valueTextView.getPaint().measureText(LocaleController.getString(R.string.PmReadUnknown))); + minWidth = Math.max(minWidth, dp(40 + 16 + 8) + valueTextView.getPaint().measureText(LocaleController.getString(R.string.PmRead) + premiumTextView.getPaint().measureText(LocaleController.getString(R.string.PmReadShowWhen)))); + minWidth = Math.max(minWidth, dp(40 + 8) + valueTextView.getPaint().measureText(LocaleController.formatString(R.string.PmReadAt, LocaleController.formatString(R.string.TodayAtFormattedWithToday, "99:99")))); + minWidth = Math.max(minWidth, dp(40 + 8) + valueTextView.getPaint().measureText(LocaleController.formatString(R.string.PmReadAt, LocaleController.formatString(R.string.YesterdayAtFormatted, "99:99")))); + minWidth = Math.max(minWidth, dp(40 + 8) + valueTextView.getPaint().measureText(LocaleController.formatString(R.string.PmReadAt, LocaleController.formatString(R.string.formatDateAtTime, "99.99.99", "99:99")))); + } + + if (width < minWidth) { + width = (int) minWidth; + } + if (parent != null && parent.getWidth() > 0) { + width = parent.getWidth(); + widthMode = MeasureSpec.EXACTLY; + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index 38aff838f..f3a056e5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -2742,23 +2742,25 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); } - TextView duplicateView = new TextView(getContext()); - duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - duplicateView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - duplicateView.setGravity(Gravity.CENTER_VERTICAL); - duplicateView.setEllipsize(TextUtils.TruncateAt.END); - duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); - duplicateView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - duplicateView.setTag(2); - duplicateView.setText(LocaleController.getString("PaintDuplicate", R.string.PaintDuplicate)); - duplicateView.setOnClickListener(v -> { - duplicateSelectedEntity(); + if (!(entityView instanceof PhotoView)) { + TextView duplicateView = new TextView(getContext()); + duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + duplicateView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + duplicateView.setGravity(Gravity.CENTER_VERTICAL); + duplicateView.setEllipsize(TextUtils.TruncateAt.END); + duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); + duplicateView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + duplicateView.setTag(2); + duplicateView.setText(LocaleController.getString("PaintDuplicate", R.string.PaintDuplicate)); + duplicateView.setOnClickListener(v -> { + duplicateSelectedEntity(); - if (popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(true); - } - }); - parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + } if (entityView instanceof PhotoView && ((PhotoView) entityView).hasSegmentedImage()) { PhotoView photoView = (PhotoView) entityView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/MessageEntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/MessageEntityView.java index e357f7460..d17b18c29 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/MessageEntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/MessageEntityView.java @@ -97,7 +97,7 @@ public class MessageEntityView extends EntityView { messageOwner.fwd_from = null; } messageOwner.voiceTranscriptionOpen = false; - MessageObject newMsg = new MessageObject(msg.currentAccount, messageOwner, msg.replyMessageObject, MessagesController.getInstance(msg.currentAccount).getUsers(), MessagesController.getInstance(msg.currentAccount).getChats(), null, null, true, true, 0, true, isRepostVideoPreview); + MessageObject newMsg = new MessageObject(msg.currentAccount, messageOwner, msg.replyMessageObject, MessagesController.getInstance(msg.currentAccount).getUsers(), MessagesController.getInstance(msg.currentAccount).getChats(), null, null, true, true, 0, true, isRepostVideoPreview, false); messageObjects.add(newMsg); } // dateCell = new ChatActionCell(context, false, resourcesProvider) { 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 bb7edab91..3f4405419 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java @@ -638,8 +638,8 @@ public class PhonebookShareAlert extends BottomSheet { buttonTextView.setText(LocaleController.getString("ShareContactTitle", R.string.ShareContactTitle)); } buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); - frameLayout.addView(buttonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 42, Gravity.LEFT | Gravity.BOTTOM, 16, 16, 16, 16)); + buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); + frameLayout.addView(buttonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 14, 14, 14, 14)); buttonTextView.setOnClickListener(v -> { if (isImport) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java index 7d6403951..5ddb693e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipRoundVideoView.java @@ -77,13 +77,19 @@ public class PipRoundVideoView implements NotificationCenter.NotificationCenterD @SuppressLint("StaticFieldLeak") private static PipRoundVideoView instance; + public class PipFrameLayout extends FrameLayout { + public PipFrameLayout(Context context) { + super(context); + } + } + public void show(Activity activity, Runnable closeRunnable) { if (activity == null) { return; } instance = this; onCloseRunnable = closeRunnable; - windowView = new FrameLayout(activity) { + windowView = new PipFrameLayout(activity) { private float startX; private float startY; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java index d127a3262..2e55a79a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PipVideoOverlay.java @@ -967,7 +967,7 @@ public class PipVideoOverlay { path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(ROUNDED_CORNERS_DP), AndroidUtilities.dp(ROUNDED_CORNERS_DP), Path.Direction.CW); } }; - contentView = new ViewGroup(context) { + contentView = new PipVideoViewGroup(context) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { contentFrameLayout.layout(0, 0, pipWidth, pipHeight); @@ -1240,4 +1240,15 @@ public class PipVideoOverlay { return mPrefs.getFloat("y", -1); } } + + public static class PipVideoViewGroup extends ViewGroup { + public PipVideoViewGroup(Context context) { + super(context); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + + } + } } \ No newline at end of file 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 a570f423f..f30ecf63c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java @@ -268,7 +268,7 @@ public class PollVotesAlert extends BottomSheet { private TLRPC.User currentUser; private TLRPC.Chat currentChat; - private String lastName; + private CharSequence lastName; private int lastStatus; private TLRPC.FileLocation lastAvatar; @@ -296,9 +296,10 @@ public class PollVotesAlert extends BottomSheet { nameTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setTextSize(16); - nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 65, 14, LocaleController.isRTL ? 65 : 28, 0)); - statusBadgeComponent = new StatusBadgeComponent(nameTextView); + nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : 65, 12, LocaleController.isRTL ? 65 : 28, 0)); + + statusBadgeComponent = new StatusBadgeComponent(nameTextView, 20); } public void setData(TLObject object, int num, boolean divider) { @@ -390,7 +391,7 @@ public class PollVotesAlert extends BottomSheet { } else if (currentChat != null) { newName = currentChat.title; } - if (!newName.equals(lastName)) { + if (!TextUtils.equals(newName, lastName)) { continueUpdate = true; } } @@ -412,13 +413,15 @@ public class PollVotesAlert extends BottomSheet { if (currentUser != null) { lastName = newName == null ? UserObject.getUserName(currentUser) : newName; + lastName = Emoji.replaceEmoji(lastName, nameTextView.getPaint().getFontMetricsInt(), false); } else if (currentChat != null) { lastName = currentChat.title; + lastName = Emoji.replaceEmoji(lastName, nameTextView.getPaint().getFontMetricsInt(), false); } else { lastName = ""; } nameTextView.setText(lastName); - nameTextView.setRightDrawable(statusBadgeComponent.updateDrawable(currentUser, currentChat, Theme.getColor(Theme.key_chats_verifiedBackground), false)); + nameTextView.setRightDrawable(statusBadgeComponent.updateDrawable(currentUser, currentChat, Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider), false)); lastAvatar = photo; if (currentChat != null) { 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 573dbce89..05072ce5b 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 @@ -130,6 +130,8 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public static final int TYPE_BOOSTS_FOR_REPLY_ICON = 26; public static final int TYPE_BOOSTS_FOR_PROFILE_ICON = 27; + public static final int TYPE_PIN_SAVED_DIALOGS = 28; + private boolean canSendLink; private int linkRow = -1; private long dialogId; @@ -280,7 +282,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp private int requiredLvl = 0; public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { - super(fragment, false, hasFixedSize(type), false, resourcesProvider); + super(context, fragment, false, hasFixedSize(type), false, resourcesProvider); fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, this.resourcesProvider)); this.parentFragment = fragment; this.currentAccount = currentAccount; @@ -826,6 +828,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp private static boolean hasFixedSize(int type) { return ( type == TYPE_PIN_DIALOGS || + type == TYPE_PIN_SAVED_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || type == TYPE_LARGE_FILE || @@ -1358,8 +1361,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp currentValue = MessagesController.getInstance(currentAccount).dialogFilters.size() - 1; } else if (type == TYPE_ACCOUNTS) { currentValue = UserConfig.getActivatedAccountsCount(); - } - if (type == TYPE_PIN_DIALOGS) { + } else if (type == TYPE_PIN_DIALOGS) { int pinnedCount = 0; ArrayList dialogs = MessagesController.getInstance(currentAccount).getDialogs(0); for (int a = 0, N = dialogs.size(); a < N; a++) { @@ -1685,6 +1687,13 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp limitParams.descriptionStr = LocaleController.formatString("LimitReachedPinDialogs", R.string.LimitReachedPinDialogs, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedPinDialogsPremium", R.string.LimitReachedPinDialogsPremium, limitParams.premiumLimit); limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedPinDialogsLocked", R.string.LimitReachedPinDialogsLocked, limitParams.defaultLimit); + } else if (type == TYPE_PIN_SAVED_DIALOGS) { + limitParams.defaultLimit = MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitDefault; + limitParams.premiumLimit = MessagesController.getInstance(currentAccount).savedDialogsPinnedLimitPremium; + limitParams.icon = R.drawable.msg_limit_pin; + limitParams.descriptionStr = LocaleController.formatString(R.string.LimitReachedPinSavedDialogs, limitParams.defaultLimit, limitParams.premiumLimit); + limitParams.descriptionStrPremium = LocaleController.formatString(R.string.LimitReachedPinSavedDialogsPremium, limitParams.premiumLimit); + limitParams.descriptionStrLocked = LocaleController.formatString(R.string.LimitReachedPinSavedDialogsLocked, limitParams.defaultLimit); } else if (type == TYPE_PUBLIC_LINKS) { limitParams.defaultLimit = MessagesController.getInstance(currentAccount).publicLinksLimitDefault; limitParams.premiumLimit = MessagesController.getInstance(currentAccount).publicLinksLimitPremium; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/UserSelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/UserSelectorBottomSheet.java index aa55dd99a..6ecddba60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/UserSelectorBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/UserSelectorBottomSheet.java @@ -417,7 +417,7 @@ public class UserSelectorBottomSheet extends BottomSheetWithRecyclerListView imp View child = recyclerListView.getChildAt(i); if (child instanceof SelectorUserCell) { int position = recyclerListView.getChildAdapterPosition(child); - if (position <= 0) { + if (position - 1 < 0 || position - 1 >= items.size()) { continue; } if (visibleItemsFrom == -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 68d1f2347..90246cc14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -1191,6 +1191,9 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma drawInternal(canvas, paint, false, 0, 0); } + public boolean scaleByCanvas; + public Rect srcRect = new Rect(); + public void drawInternal(Canvas canvas, Paint overridePaint, boolean drawInBackground, long time, int threadIndex) { if (!canLoadFrames() || destroyWhenDone) { return; @@ -1228,11 +1231,17 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (!needScale) { canvas.drawBitmap(renderingBitmap, rect.left, rect.top, paint); } else { - canvas.save(); - canvas.translate(rect.left, rect.top); - canvas.scale(scaleX, scaleY); - canvas.drawBitmap(renderingBitmap, 0, 0, paint); - canvas.restore(); + if (scaleByCanvas) { + // save-restore breaks cutting with xfer + srcRect.set(0, 0, renderingBitmap.getWidth(), renderingBitmap.getHeight()); + canvas.drawBitmap(renderingBitmap, srcRect, rect, paint); + } else { + canvas.save(); + canvas.translate(rect.left, rect.top); + canvas.scale(scaleX, scaleY); + canvas.drawBitmap(renderingBitmap, 0, 0, paint); + canvas.restore(); + } } if (isRunning && !drawInBackground) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java index f54636982..850c9a0eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java @@ -15,8 +15,11 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import androidx.annotation.Keep; + +import android.graphics.drawable.Drawable; import android.view.View; import org.telegram.messenger.AndroidUtilities; @@ -81,6 +84,15 @@ public class RadioButton extends View { size = value; } + private Drawable icon; + public void setIcon(Drawable drawable) { + icon = drawable; + if (icon != null) { + icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + } + invalidate(); + } + public int getColor() { return color; } @@ -88,11 +100,17 @@ public class RadioButton extends View { public void setColor(int color1, int color2) { color = color1; checkedColor = color2; + if (icon != null) { + icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + } invalidate(); } public void setBackgroundColor(int color1) { color = color1; + if (icon != null) { + icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + } invalidate(); } @@ -175,6 +193,15 @@ public class RadioButton extends View { paint.setColor(c); checkedPaint.setColor(c); } + if (icon != null) { + icon.setBounds( + (int) (getWidth() / 2f - icon.getIntrinsicWidth() / 2f), + (int) (getHeight() / 2f - icon.getIntrinsicHeight() / 2f), + (int) (getWidth() / 2f + icon.getIntrinsicWidth() / 2f), + (int) (getHeight() / 2f + icon.getIntrinsicHeight() / 2f) + ); + icon.draw(canvas); + } if (bitmap != null) { bitmap.eraseColor(0); float rad = size / 2 - (1 + circleProgress) * AndroidUtilities.density; 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 f20c5ecd7..3c6bfd6ee 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 @@ -1,15 +1,22 @@ package org.telegram.ui.Components.Reactions; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.RectF; import android.text.TextPaint; import android.text.TextUtils; import android.view.Gravity; import android.view.MotionEvent; +import android.view.View; import android.view.ViewConfiguration; import androidx.core.graphics.ColorUtils; @@ -48,6 +55,8 @@ public class ReactionsLayoutInBubble { public float drawServiceShaderBackground; private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private static Paint tagPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private static Paint cutTagPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private static TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); public boolean isSmall; @@ -104,14 +113,16 @@ public class ReactionsLayoutInBubble { return 0; } + public boolean tags; public ReactionsLayoutInBubble(ChatMessageCell parentView) { this.parentView = parentView; currentAccount = UserConfig.selectedAccount; paint.setColor(Theme.getColor(Theme.key_chat_inLoader, resourcesProvider)); textPaint.setColor(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider)); - textPaint.setTextSize(AndroidUtilities.dp(12)); + textPaint.setTextSize(dp(12)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); touchSlop = ViewConfiguration.get(ApplicationLoader.applicationContext).getScaledTouchSlop(); + cutTagPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } public static boolean equalsTLReaction(TLRPC.Reaction reaction, TLRPC.Reaction reaction1) { @@ -148,7 +159,7 @@ public class ReactionsLayoutInBubble { // break; // } // } - ReactionButton button = new ReactionButton(old, reactionCount, isSmall); + ReactionButton button = new ReactionLayoutButton(old, reactionCount, isSmall); reactionButtons.add(button); if (!isSmall && messageObject.messageOwner.reactions.recent_reactions != null) { ArrayList users = null; @@ -201,8 +212,8 @@ public class ReactionsLayoutInBubble { } } if (isSmall && reactionCount.count > 1 && reactionCount.chosen) { - // TODO: also reuse here - reactionButtons.add(new ReactionButton(null, reactionCount, isSmall)); + ReactionButton button2 = new ReactionLayoutButton(null, reactionCount, isSmall); + reactionButtons.add(button2); reactionButtons.get(0).isSelected = false; reactionButtons.get(1).isSelected = true; reactionButtons.get(0).realCount = 1; @@ -248,29 +259,29 @@ public class ReactionsLayoutInBubble { for (int i = 0; i < reactionButtons.size(); i++) { ReactionButton button = reactionButtons.get(i); if (button.isSmall) { - button.width = AndroidUtilities.dp(14); - button.height = AndroidUtilities.dp(14); + button.width = dp(14); + button.height = dp(14); } else { - button.width = (int) (AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(4)); + button.width = (int) (dp(8) + dp(20) + dp(4)); if (button.avatarsDrawable != null && button.users.size() > 0) { button.users.size(); int c1 = 1; int c2 = button.users.size() > 1 ? button.users.size() - 1 : 0; - button.width += AndroidUtilities.dp(2) + c1 * AndroidUtilities.dp(20) + c2 * AndroidUtilities.dp(20) * 0.8f + AndroidUtilities.dp(1); - button.avatarsDrawable.height = AndroidUtilities.dp(26); + button.width += dp(2) + c1 * dp(20) + c2 * dp(20) * 0.8f + dp(1); + button.avatarsDrawable.height = dp(26); } else { - button.width += button.counterDrawable.textPaint.measureText(button.countText) + AndroidUtilities.dp(8); + button.width += button.counterDrawable.textPaint.measureText(button.countText) + dp(8); } - button.height = AndroidUtilities.dp(26); + button.height = dp(26); } if (currentX + button.width > availableWidth) { currentX = 0; - currentY += button.height + AndroidUtilities.dp(4); + currentY += button.height + dp(4); } button.x = currentX; button.y = currentY; - currentX += button.width + AndroidUtilities.dp(4); + currentX += button.width + dp(4); if (currentX > maxWidth) { maxWidth = currentX; } @@ -299,7 +310,7 @@ public class ReactionsLayoutInBubble { } else { width = maxWidth; } - height = currentY + (reactionButtons.size() == 0 ? 0 : AndroidUtilities.dp(26)); + height = currentY + (reactionButtons.size() == 0 ? 0 : dp(26)); drawServiceShaderBackground = 0f; } @@ -388,7 +399,7 @@ public class ReactionsLayoutInBubble { button.fromBackgroundColor = lastButton.lastDrawnBackgroundColor; button.animationType = ANIMATION_TYPE_MOVE; - if (button.count != lastButton.count) { + if (button.count != lastButton.count && button.counterDrawable != null) { button.counterDrawable.setCount(lastButton.count, false); button.counterDrawable.setCount(button.count, true); } @@ -399,7 +410,7 @@ public class ReactionsLayoutInBubble { if (lastButton.avatarsDrawable == null) { lastButton.setUsers(new ArrayList<>()); } - if (!equalsUsersList(lastButton.users, button.users)) { + if (!equalsUsersList(lastButton.users, button.users) && button.avatarsDrawable != null) { button.avatarsDrawable.animateFromState(lastButton.avatarsDrawable, currentAccount, false); } } @@ -485,7 +496,43 @@ public class ReactionsLayoutInBubble { this.scrimViewReaction = scrimViewReaction; } - public class ReactionButton { + public class ReactionLayoutButton extends ReactionButton { + public ReactionLayoutButton(ReactionButton reuseFrom, TLRPC.ReactionCount reactionCount, boolean isSmall) { + super(reuseFrom, currentAccount, parentView, reactionCount, isSmall, resourcesProvider); + } + + @Override + protected boolean isPlaying() { + return ReactionsEffectOverlay.isPlaying(messageObject.getId(), messageObject.getGroupId(), visibleReaction); + } + + @Override + protected boolean isOutOwner() { + return messageObject.isOutOwner(); + } + + @Override + protected float getDrawServiceShaderBackground() { + return drawServiceShaderBackground; + } + + @Override + protected boolean supportsImageReceiverCache() { + return true; + } + + @Override + protected ImageReceiver getImageReceiver() { + return animatedReactions.get(visibleReaction); + } + + @Override + protected void removeImageReceiver() { + animatedReactions.remove(visibleReaction); + } + } + + public static class ReactionButton { private final TLRPC.ReactionCount reactionCount; private final boolean isSmall; @@ -503,12 +550,12 @@ public class ReactionsLayoutInBubble { public String key; public boolean choosen; - String countText; + public String countText; TLRPC.Reaction reaction; VisibleReaction visibleReaction; android.graphics.Rect drawingImageRect = new Rect(); - int count; + public int count; public int x; public int y; public int width; @@ -516,19 +563,31 @@ public class ReactionsLayoutInBubble { ImageReceiver imageReceiver; AnimatedEmojiDrawable animatedEmojiDrawable; int animatedEmojiDrawableColor; - CounterView.CounterDrawable counterDrawable; + public CounterView.CounterDrawable counterDrawable; int backgroundColor; int textColor; int serviceBackgroundColor; int serviceTextColor; - int lastDrawnTextColor; - int lastDrawnBackgroundColor; + public int lastDrawnTextColor; + public int lastDrawnBackgroundColor; boolean isSelected; + AvatarsDrawable avatarsDrawable; ArrayList users; - public ReactionButton(ReactionButton reuseFrom, TLRPC.ReactionCount reactionCount, boolean isSmall) { + private final int currentAccount; + private final View parentView; + private final Theme.ResourcesProvider resourcesProvider; + + protected int getCacheType() { + return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; + } + + public ReactionButton(ReactionButton reuseFrom, int currentAccount, View parentView, TLRPC.ReactionCount reactionCount, boolean isSmall, Theme.ResourcesProvider resourcesProvider) { + this.currentAccount = currentAccount; + this.parentView = parentView; + this.resourcesProvider = resourcesProvider; if (reuseFrom != null) { counterDrawable = reuseFrom.counterDrawable; } @@ -568,23 +627,31 @@ public class ReactionsLayoutInBubble { imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", svgThumb, "webp", r, 1); } } else if (visibleReaction.documentId != 0) { - animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, visibleReaction.documentId); + animatedEmojiDrawable = new AnimatedEmojiDrawable(getCacheType(), currentAccount, visibleReaction.documentId); } } - counterDrawable.setSize(AndroidUtilities.dp(26), AndroidUtilities.dp(100)); + counterDrawable.setSize(dp(26), dp(100)); counterDrawable.textPaint = textPaint; counterDrawable.setCount(count, false); counterDrawable.setType(CounterView.CounterDrawable.TYPE_CHAT_REACTIONS); counterDrawable.gravity = Gravity.LEFT; } + protected boolean isOutOwner() { + return false; + } + + protected boolean drawCounter() { + return count != 0 || counterDrawable.countChangeProgress != 1f; + } + 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((int) x, (int) y, AndroidUtilities.dp(14), AndroidUtilities.dp(14)); + drawingImageRect.set((int) x, (int) y, dp(14), dp(14)); imageReceiver.setImageCoords(drawingImageRect); imageReceiver.setRoundRadius(0); drawImage(canvas, alpha); @@ -592,13 +659,13 @@ public class ReactionsLayoutInBubble { } if (choosen) { - backgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); - textColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonTextSelected : Theme.key_chat_inReactionButtonTextSelected, resourcesProvider); - serviceTextColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); - serviceBackgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble); + backgroundColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); + textColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outReactionButtonTextSelected : Theme.key_chat_inReactionButtonTextSelected, resourcesProvider); + serviceTextColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); + serviceBackgroundColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble); } else { - textColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonText : Theme.key_chat_inReactionButtonText, resourcesProvider); - backgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); + textColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outReactionButtonText : Theme.key_chat_inReactionButtonText, resourcesProvider); + backgroundColor = Theme.getColor(isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider); backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, (int) (Color.alpha(backgroundColor) * 0.156f)); serviceTextColor = Theme.getColor(Theme.key_chat_serviceText, resourcesProvider); serviceBackgroundColor = Color.TRANSPARENT; @@ -607,7 +674,6 @@ public class ReactionsLayoutInBubble { textPaint.setColor(lastDrawnTextColor); paint.setColor(lastDrawnBackgroundColor); - if (alpha != 1f) { textPaint.setAlpha((int) (textPaint.getAlpha() * alpha)); paint.setAlpha((int) (paint.getAlpha() * alpha)); @@ -622,22 +688,22 @@ public class ReactionsLayoutInBubble { } 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 = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); + if (getDrawServiceShaderBackground() > 0) { + Paint paint1 = Theme.getThemePaint(Theme.key_paint_chatActionBackground, resourcesProvider); + Paint paint2 = Theme.getThemePaint(Theme.key_paint_chatActionBackgroundDarken, resourcesProvider); int oldAlpha = paint1.getAlpha(); int oldAlpha2 = paint2.getAlpha(); - paint1.setAlpha((int) (oldAlpha * alpha * drawServiceShaderBackground)); - paint2.setAlpha((int) (oldAlpha2 * alpha * drawServiceShaderBackground)); + paint1.setAlpha((int) (oldAlpha * alpha * getDrawServiceShaderBackground())); + paint2.setAlpha((int) (oldAlpha2 * alpha * getDrawServiceShaderBackground())); canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint1); - if (hasGradientService()) { + if (resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService()) { canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint2); } paint1.setAlpha(oldAlpha); paint2.setAlpha(oldAlpha2); } - if (drawServiceShaderBackground < 1 && drawOverlayScrim) { - Theme.MessageDrawable messageBackground = parentView.getCurrentBackgroundDrawable(false); + if (drawOverlayScrim && getDrawServiceShaderBackground() < 1 && parentView instanceof ChatMessageCell) { + Theme.MessageDrawable messageBackground = ((ChatMessageCell) parentView).getCurrentBackgroundDrawable(false); if (messageBackground != null) { canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, messageBackground.getPaint()); } @@ -647,12 +713,12 @@ public class ReactionsLayoutInBubble { if (imageReceiver != null) { int size, X; if (animatedEmojiDrawable != null) { - size = AndroidUtilities.dp(24); - X = AndroidUtilities.dp(6); - imageReceiver.setRoundRadius(AndroidUtilities.dp(6)); + size = dp(24); + X = dp(6); + imageReceiver.setRoundRadius(dp(6)); } else { - size = AndroidUtilities.dp(20); - X = AndroidUtilities.dp(8); + size = dp(20); + X = dp(8); imageReceiver.setRoundRadius(0); } int Y = (int) ((height - size) / 2f); @@ -661,16 +727,16 @@ public class ReactionsLayoutInBubble { drawImage(canvas, alpha); } - if (counterDrawable != null && (count != 0 || counterDrawable.countChangeProgress != 1f)) { + if (counterDrawable != null && drawCounter()) { canvas.save(); - canvas.translate(x + AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); + canvas.translate(x + dp(8) + dp(20) + dp(2), y); counterDrawable.draw(canvas); canvas.restore(); } if (avatarsDrawable != null) { canvas.save(); - canvas.translate(x + AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); + canvas.translate(x + dp(10) + dp(20) + dp(2), y); avatarsDrawable.setAlpha(alpha); avatarsDrawable.setTransitionProgress(progress); avatarsDrawable.onDraw(canvas); @@ -678,9 +744,33 @@ public class ReactionsLayoutInBubble { } } - private void updateColors(float progress) { - lastDrawnTextColor = ColorUtils.blendARGB(fromTextColor, ColorUtils.blendARGB(textColor, serviceTextColor, drawServiceShaderBackground), progress); - lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, ColorUtils.blendARGB(backgroundColor, serviceBackgroundColor, drawServiceShaderBackground), progress); + protected void updateColors(float progress) { + lastDrawnTextColor = ColorUtils.blendARGB(fromTextColor, ColorUtils.blendARGB(textColor, serviceTextColor, getDrawServiceShaderBackground()), progress); + lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, ColorUtils.blendARGB(backgroundColor, serviceBackgroundColor, getDrawServiceShaderBackground()), progress); + } + + protected boolean isPlaying() { + return false; + } + + protected ImageReceiver getImageReceiver() { + return null; + } + + protected void removeImageReceiver() { + + } + + protected boolean supportsImageReceiverCache() { + return false; + } + + protected float getDrawServiceShaderBackground() { + return 0; + } + + protected boolean drawTagDot() { + return true; } private void drawImage(Canvas canvas, float alpha) { @@ -688,8 +778,8 @@ public class ReactionsLayoutInBubble { if (animatedEmojiDrawable != null && animatedEmojiDrawableColor != lastDrawnTextColor) { animatedEmojiDrawable.setColorFilter(new PorterDuffColorFilter(animatedEmojiDrawableColor = lastDrawnTextColor, PorterDuff.Mode.SRC_IN)); } - if (drawImage && ((realCount > 1 || !ReactionsEffectOverlay.isPlaying(messageObject.getId(), messageObject.getGroupId(), visibleReaction)) || !isSelected)) { - ImageReceiver imageReceiver2 = animatedReactions.get(visibleReaction); + if (drawImage && (realCount > 1 || !isPlaying() || !isSelected)) { + ImageReceiver imageReceiver2 = getImageReceiver(); boolean drawStaticImage = true; if (imageReceiver2 != null) { if (imageReceiver2.getLottieAnimation() != null && imageReceiver2.getLottieAnimation().hasBitmap()) { @@ -699,7 +789,7 @@ public class ReactionsLayoutInBubble { imageReceiver2.setAlpha(alpha); if (alpha <= 0) { imageReceiver2.onDetachedFromWindow(); - animatedReactions.remove(visibleReaction); + removeImageReceiver(); } } else { if (imageReceiver2.getLottieAnimation() != null && !imageReceiver2.getLottieAnimation().isRunning()) { @@ -707,7 +797,7 @@ public class ReactionsLayoutInBubble { float alpha1 = imageReceiver2.getAlpha() - 16f / 200; if (alpha1 <= 0) { imageReceiver2.onDetachedFromWindow(); - animatedReactions.remove(visibleReaction); + removeImageReceiver(); } else { imageReceiver2.setAlpha(alpha1); } @@ -736,10 +826,10 @@ public class ReactionsLayoutInBubble { avatarsDrawable = new AvatarsDrawable(parentView, false); avatarsDrawable.transitionDuration = ChatListItemAnimator.DEFAULT_DURATION; avatarsDrawable.transitionInterpolator = ChatListItemAnimator.DEFAULT_INTERPOLATOR; - avatarsDrawable.setSize(AndroidUtilities.dp(20)); - avatarsDrawable.width = AndroidUtilities.dp(100); + avatarsDrawable.setSize(dp(20)); + avatarsDrawable.width = dp(100); avatarsDrawable.height = height; - avatarsDrawable.setAvatarsTextSize(AndroidUtilities.dp(22)); + avatarsDrawable.setAvatarsTextSize(dp(22)); } if (attached) { avatarsDrawable.onAttachedToWindow(); @@ -754,7 +844,9 @@ public class ReactionsLayoutInBubble { } } + public boolean attached; public void attach() { + attached = true; if (imageReceiver != null) { imageReceiver.onAttachedToWindow(); } @@ -767,6 +859,7 @@ public class ReactionsLayoutInBubble { } public void detach() { + attached = false; if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); } @@ -947,6 +1040,17 @@ public class ReactionsLayoutInBubble { return visibleReaction; } + public TLRPC.Reaction toTLReaction() { + if (emojicon != null) { + TLRPC.TL_reactionEmoji r = new TLRPC.TL_reactionEmoji(); + r.emoticon = emojicon; + return r; + } + TLRPC.TL_reactionCustomEmoji r = new TLRPC.TL_reactionCustomEmoji(); + r.document_id = documentId; + return r; + } + public static VisibleReaction fromEmojicon(TLRPC.TL_availableReaction reaction) { VisibleReaction visibleReaction = new VisibleReaction(); visibleReaction.emojicon = reaction.reaction; @@ -996,6 +1100,11 @@ public class ReactionsLayoutInBubble { } public boolean isSame(TLRPC.Reaction reaction) { + if (reaction instanceof TLRPC.TL_reactionEmoji) { + return TextUtils.equals(((TLRPC.TL_reactionEmoji) reaction).emoticon, emojicon); + } else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { + return ((TLRPC.TL_reactionCustomEmoji) reaction).document_id == documentId; + } return false; } } 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 0c3c43dc4..cc6195f2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -94,6 +94,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio public final static int TYPE_DEFAULT = 0; public final static int TYPE_STORY = 1; public static final int TYPE_STORY_LIKES = 2; + public static final int TYPE_TAGS = 3; private final static int ALPHA_DURATION = 150; private final static float SIDE_SCALE = 0.6f; @@ -1053,7 +1054,10 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio return; } } - if (reactionsChat != null) { + if (type == TYPE_TAGS) { + allReactionsAvailable = UserConfig.getInstance(currentAccount).isPremium(); + fillRecentReactionsList(visibleReactions); + } else if (reactionsChat != null) { if (reactionsChat.available_reactions instanceof TLRPC.TL_chatReactionsAll) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(reactionsChat.id); if (chat != null && !ChatObject.isChannelAndNotMegaGroup(chat)) { @@ -1127,20 +1131,59 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio private void fillRecentReactionsList(List visibleReactions) { if (!allReactionsAvailable) { - //fill default reactions - List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); - for (int i = 0; i < enabledReactions.size(); i++) { - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(enabledReactions.get(i)); - visibleReactions.add(visibleReaction); + if (type == TYPE_TAGS) { + ArrayList topReactions = MediaDataController.getInstance(currentAccount).getSavedReactions(); + HashSet hashSet = new HashSet<>(); + int added = 0; + for (int i = 0; i < topReactions.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(topReactions.get(i)); + if (!hashSet.contains(visibleReaction)) { + hashSet.add(visibleReaction); + visibleReactions.add(visibleReaction); + added++; + } + if (added == 16) { + break; + } + } + } else { + //fill default reactions + List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); + for (int i = 0; i < enabledReactions.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(enabledReactions.get(i)); + visibleReactions.add(visibleReaction); + } } return; } - ArrayList topReactions = MediaDataController.getInstance(currentAccount).getTopReactions(); + + ArrayList topReactions; + if (type == TYPE_TAGS) { + topReactions = MediaDataController.getInstance(currentAccount).getSavedReactions(); + } else { + topReactions = MediaDataController.getInstance(currentAccount).getTopReactions(); + } HashSet hashSet = new HashSet<>(); int added = 0; + if (type == TYPE_TAGS) { + TLRPC.TL_messages_savedReactionsTags savedTags = MessagesController.getInstance(currentAccount).getSavedReactionTags(); + if (savedTags != null) { + for (int i = 0; i < savedTags.tags.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(savedTags.tags.get(i).reaction); + if (!hashSet.contains(visibleReaction)) { + hashSet.add(visibleReaction); + visibleReactions.add(visibleReaction); + added++; + } + if (added == 16) { + break; + } + } + } + } for (int i = 0; i < topReactions.size(); i++) { ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(topReactions.get(i)); - if (!hashSet.contains(visibleReaction) && (UserConfig.getInstance(currentAccount).isPremium() || visibleReaction.documentId == 0)) { + if (!hashSet.contains(visibleReaction) && (type == TYPE_TAGS || UserConfig.getInstance(currentAccount).isPremium() || visibleReaction.documentId == 0)) { hashSet.add(visibleReaction); visibleReactions.add(visibleReaction); added++; @@ -1150,22 +1193,24 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } } - ArrayList recentReactions = MediaDataController.getInstance(currentAccount).getRecentReactions(); - for (int i = 0; i < recentReactions.size(); i++) { - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(recentReactions.get(i)); - if (!hashSet.contains(visibleReaction)) { - hashSet.add(visibleReaction); - visibleReactions.add(visibleReaction); + if (type != TYPE_TAGS || UserConfig.getInstance(currentAccount).isPremium()) { + ArrayList recentReactions = MediaDataController.getInstance(currentAccount).getRecentReactions(); + for (int i = 0; i < recentReactions.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(recentReactions.get(i)); + if (!hashSet.contains(visibleReaction)) { + hashSet.add(visibleReaction); + visibleReactions.add(visibleReaction); + } } - } - //fill default reactions - List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); - for (int i = 0; i < enabledReactions.size(); i++) { - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(enabledReactions.get(i)); - if (!hashSet.contains(visibleReaction)) { - hashSet.add(visibleReaction); - visibleReactions.add(visibleReaction); + //fill default reactions + List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); + for (int i = 0; i < enabledReactions.size(); i++) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(enabledReactions.get(i)); + if (!hashSet.contains(visibleReaction)) { + hashSet.add(visibleReaction); + visibleReactions.add(visibleReaction); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java index f07567be2..35fa30cce 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -2083,7 +2083,7 @@ public class RecyclerListView extends RecyclerView { return false; } if (disallowInterceptTouchEvents) { - requestDisallowInterceptTouchEvent(true); + requestDisallowInterceptTouchEvent(this, true); } return onInterceptTouchListener != null && onInterceptTouchListener.onInterceptTouchEvent(e) || super.onInterceptTouchEvent(e); } @@ -2675,6 +2675,19 @@ public class RecyclerListView extends RecyclerView { super.requestLayout(); } + public ViewParent getTouchParent() { + return null; + } + private void requestDisallowInterceptTouchEvent(View view, boolean disallow) { + if (view == null) return; + ViewParent parent = view.getParent(); + if (parent == null) return; + parent.requestDisallowInterceptTouchEvent(disallow); + parent = getTouchParent(); + if (parent == null) return; + parent.requestDisallowInterceptTouchEvent(disallow); + } + public void setAnimateEmptyView(boolean animate, int emptyViewAnimationType) { animateEmptyView = animate; this.emptyViewAnimationType = emptyViewAnimationType; @@ -2726,7 +2739,7 @@ public class RecyclerListView extends RecyclerView { listPaddings = new int[2]; selectedPositions = new HashSet<>(); - getParent().requestDisallowInterceptTouchEvent(true); + requestDisallowInterceptTouchEvent(this, true); this.multiSelectionListener = multiSelectionListener; multiSelectionGesture = true; @@ -2748,7 +2761,7 @@ public class RecyclerListView extends RecyclerView { } if (!multiSelectionGestureStarted && Math.abs(e.getY() - lastY) > touchSlop) { multiSelectionGestureStarted = true; - getParent().requestDisallowInterceptTouchEvent(true); + requestDisallowInterceptTouchEvent(this, true); } if (multiSelectionGestureStarted) { chekMultiselect(e.getX(), e.getY()); @@ -2767,7 +2780,7 @@ public class RecyclerListView extends RecyclerView { lastY = Float.MAX_VALUE; multiSelectionGesture = false; multiSelectionGestureStarted = false; - getParent().requestDisallowInterceptTouchEvent(false); + requestDisallowInterceptTouchEvent(this, false); cancelMultiselectScroll(); return super.onTouchEvent(e); } 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 bc2e55cc3..6c8cc6ad5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java @@ -145,6 +145,7 @@ public class ReplyMessageLine { public static final int TYPE_QUOTE = 1; public static final int TYPE_CODE = 2; public static final int TYPE_LINK = 3; + public static final int TYPE_CONTACT = 4; 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(); @@ -155,6 +156,24 @@ public class ReplyMessageLine { color1 = color2 = color3 = Theme.getColor(Theme.key_chat_inReplyLine, resourcesProvider); backgroundColor = Theme.multAlpha(color1, dark ? 0.12f : 0.10f); return nameColorAnimated.set(nameColor = Theme.getColor(Theme.key_chat_inReplyNameText, resourcesProvider)); + } else if (type == TYPE_CONTACT + && messageObject.messageOwner != null + && MessageObject.getMedia(messageObject.messageOwner) != null + && MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaContact + ) { + int colorId = 0; + TLRPC.User user = null; + long uid = MessageObject.getMedia(messageObject.messageOwner).user_id; + if (uid != 0) { + user = MessagesController.getInstance(messageObject.currentAccount).getUser(uid); + } + if (user != null) { + colorId = UserObject.getColorId(user); + emojiDocumentId = UserObject.getEmojiId(user); + } + resolveColor(messageObject, colorId, resourcesProvider); + backgroundColor = Theme.multAlpha(color1, 0.10f); + nameColor = color1; } else if (type != TYPE_REPLY && ( messageObject.overrideLinkColor >= 0 || messageObject.messageOwner != null && ( @@ -294,7 +313,7 @@ public class ReplyMessageLine { backgroundColor = Theme.multAlpha(color3, dark ? 0.12f : 0.10f); nameColor = Theme.getColor(Theme.key_chat_outReplyNameText, resourcesProvider); } - if ((type == TYPE_REPLY || type == TYPE_LINK) && messageObject != null && messageObject.overrideLinkEmoji != -1) { + if ((type == TYPE_REPLY || type == TYPE_LINK || type == TYPE_CONTACT) && messageObject != null && messageObject.overrideLinkEmoji != -1) { emojiDocumentId = messageObject.overrideLinkEmoji; } if (emojiDocumentId != 0 && emoji == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java new file mode 100644 index 000000000..bb13929e7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchTagsList.java @@ -0,0 +1,426 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.lerp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.LongSparseArray; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; + +public class SearchTagsList extends BlurredFrameLayout implements NotificationCenter.NotificationCenterDelegate { + + private final int currentAccount; + private final Theme.ResourcesProvider resourcesProvider; + public final RecyclerListView listView; + private final Adapter adapter; + + private long chosen; + private final ArrayList oldItems = new ArrayList<>(); + private final ArrayList items = new ArrayList<>(); + + private static class Item { + ReactionsLayoutInBubble.VisibleReaction reaction; + int count; + + public static Item get(ReactionsLayoutInBubble.VisibleReaction reaction, int count) { + Item item = new Item(); + item.reaction = reaction; + item.count = count; + return item; + } + + public long hash() { + return reaction.hash; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof Item)) { + return false; + } + Item that = (Item) obj; + return this.count == that.count && this.reaction.hash == that.reaction.hash; + } + } + + public SearchTagsList(Context context, SizeNotifierFrameLayout contentView, int currentAccount, Theme.ResourcesProvider resourcesProvider) { + super(context, contentView); + + this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + + listView = new RecyclerListView(context, resourcesProvider) { + @Override + public Integer getSelectorColor(int position) { + return 0; + } + }; + listView.setPadding(dp(5.66f), 0, dp(5.66f), 0); + listView.setClipToPadding(false); + final LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(RecyclerView.HORIZONTAL); + listView.setLayoutManager(layoutManager); + listView.setAdapter(adapter = new Adapter()); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setOnItemClickListener((view, position) -> { + if (position < 0 || position >= items.size()) { + return; + } + listView.forAllChild(view2 -> { + if (view2 instanceof TagButton) { + ((TagButton) view2).setChosen(false, true); + } + }); + long hash = items.get(position).hash(); + if (chosen == hash) { + chosen = 0; + setFilter(null); + } else { + chosen = hash; + setFilter(items.get(position).reaction); + ((TagButton) view).setChosen(true, true); + } + }); + + DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { + @Override + public boolean animateMove(RecyclerView.ViewHolder holder, ItemHolderInfo info, int fromX, int fromY, int toX, int toY) { + int position = holder.getAdapterPosition(); + if (position >= 0 && position < items.size()) { + Item item = items.get(position); + TagButton btn = (TagButton) holder.itemView; + boolean updatedChosen = btn.setChosen(chosen == item.hash(), true); + boolean updatedCount = btn.setCount(item.count); + if (updatedChosen || updatedCount) { + return true; + } + } + return super.animateMove(holder, info, fromX, fromY, toX, toY); + } + + @Override + protected void animateMoveImpl(RecyclerView.ViewHolder holder, MoveInfo moveInfo) { + super.animateMoveImpl(holder, moveInfo); + } + }; + itemAnimator.setSupportsChangeAnimations(false); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDurations(320); + listView.setItemAnimator(itemAnimator); + + MediaDataController.getInstance(currentAccount).loadSavedReactions(false); + updateTags(); + } + + public boolean hasFilters() { + return !items.isEmpty(); + } + + public void clear() { + listView.forAllChild(view2 -> { + if (view2 instanceof TagButton) { + ((TagButton) view2).setChosen(false, true); + } + }); + chosen = 0; + } + + protected void setFilter(ReactionsLayoutInBubble.VisibleReaction reaction) { + + } + + public void attach() { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.savedReactionTagsUpdate); + } + + public void detach() { + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.savedReactionTagsUpdate); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.savedReactionTagsUpdate) { + updateTags(); + } + } + + public void updateTags() { + HashSet hashes = new HashSet<>(); + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + TLRPC.TL_messages_savedReactionsTags savedReactionsTags = MessagesController.getInstance(currentAccount).getSavedReactionTags(); + if (savedReactionsTags != null) { + for (int i = 0; i < savedReactionsTags.tags.size(); ++i) { + TLRPC.TL_savedReactionTag tag = savedReactionsTags.tags.get(i); + ReactionsLayoutInBubble.VisibleReaction r = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(tag.reaction); + if (!hashes.contains(r.hash)) { + items.add(Item.get(r, tag.count)); + hashes.add(r.hash); + } + } + } +// ArrayList defaultReactions = MediaDataController.getInstance(currentAccount).getSavedReactions(); +// for (int i = 0; i < defaultReactions.size(); ++i) { +// ReactionsLayoutInBubble.VisibleReaction r = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(defaultReactions.get(i)); +// if (!hashes.contains(r.hash)) { +// items.add(Item.get(r, 0)); +// hashes.add(r.hash); +// } +// } + + DiffUtil.calculateDiff(new DiffUtil.Callback() { + @Override + public int getOldListSize() { + return oldItems.size(); + } + @Override + public int getNewListSize() { + return items.size(); + } + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return oldItems.get(oldItemPosition).equals(items.get(newItemPosition)); + } + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return oldItems.get(oldItemPosition).hash() == items.get(newItemPosition).hash(); + } + }).dispatchUpdatesTo(adapter); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(40), MeasureSpec.EXACTLY)); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (shownT < .5f) { + return false; + } + return super.dispatchTouchEvent(ev); + } + + private float shownT; + public void setShown(float shownT) { + this.shownT = shownT; + listView.setPivotX(listView.getWidth() / 2f); + listView.setPivotY(0); + listView.setScaleX(lerp(0.8f, 1, shownT)); + listView.setScaleY(lerp(0.8f, 1, shownT)); + listView.setAlpha(shownT); + invalidate(); + } + + public boolean shown() { + return shownT > 0.5f; + } + +// private final Paint backgroundPaint = new Paint(); +// @Override +// public void setBackgroundColor(int color) { +// backgroundPaint.setColor(color); +// } + + public int getCurrentHeight() { + return (int) (getMeasuredHeight() * shownT); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); +// canvas.drawRect(0, 0, getWidth(), getCurrentHeight(), backgroundPaint); + canvas.clipRect(0, 0, getWidth(), getCurrentHeight()); + super.dispatchDraw(canvas); + canvas.restore(); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + public Adapter() { +// setHasStableIds(true); + } + +// @Override +// public long getItemId(int position) { +// if (position < 0 || position >= items.size()) return position; +// return items.get(position).hash(); +// } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = new TagButton(getContext()); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position < 0 || position >= items.size()) return; + final Item item = items.get(position); + ((TagButton) holder.itemView).set(item.reaction.toTLReaction(), item.count); + ((TagButton) holder.itemView).setChosen(item.hash() == chosen, false); + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + } + + private class TagButton extends View { + public ReactionsLayoutInBubble.ReactionButton reactionButton; + + public TagButton(Context context) { + super(context); + ScaleStateListAnimator.apply(this); + } + + private int count; + public void set(TLRPC.Reaction reaction, Integer count) { + TLRPC.TL_reactionCount reactionCount = new TLRPC.TL_reactionCount(); + reactionCount.reaction = reaction; + reactionCount.count = this.count = count == null ? 0 : count; + + reactionButton = new ReactionsLayoutInBubble.ReactionButton(null, currentAccount, this, reactionCount, false, resourcesProvider) { + @Override + protected void updateColors(float progress) { + lastDrawnTextColor = ColorUtils.blendARGB(fromTextColor, chosen ? Theme.getColor(Theme.key_chat_inReactionButtonTextSelected) : Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), progress); + lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, chosen ? Theme.getColor(Theme.key_chat_inReactionButtonBackground, resourcesProvider) : Theme.getColor(Theme.key_actionBarActionModeReaction, resourcesProvider), progress); + } + + @Override + protected boolean drawTagDot() { + return !drawCounter(); + } + + @Override + protected int getCacheType() { + return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_EMOJI_STATUS; + } + + @Override + protected boolean drawCounter() { + return count > 0 || counterDrawable.countChangeProgress != 1f; + } + }; + reactionButton.width = dp(44.33f); + reactionButton.counterDrawable.setCount(reactionCount.count, false); + if (reactionButton.counterDrawable != null && reactionButton.count > 0) { + reactionButton.width += reactionButton.counterDrawable.textPaint.measureText(reactionButton.countText); + } + reactionButton.height = dp(28); + reactionButton.choosen = chosen; + if (attached) { + reactionButton.attach(); + } + } + + private boolean chosen; + public boolean setChosen(boolean value, boolean animated) { + if (chosen == value) return false; + chosen = value; + if (reactionButton != null) { + reactionButton.choosen = value; + + if (animated) { + reactionButton.fromTextColor = reactionButton.lastDrawnTextColor; + reactionButton.fromBackgroundColor = reactionButton.lastDrawnBackgroundColor; + progress.set(0, true); + } else { + progress.set(1, true); + } + invalidate(); + } + return true; + } + + public boolean setCount(int count) { + if (this.count != count && reactionButton != null) { + reactionButton.animateFromWidth = reactionButton.width; + reactionButton.count = count; + reactionButton.width = dp(44.33f); + reactionButton.counterDrawable.setCount(count, true); + if (reactionButton.counterDrawable != null && reactionButton.count > 0) { + reactionButton.width += reactionButton.counterDrawable.textPaint.measureText(reactionButton.countText); + } + progress.set(0, true); + invalidate(); + return true; + } + return false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(dp(8.67f) + (reactionButton != null ? reactionButton.width : dp(44.33f)), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(40), MeasureSpec.EXACTLY)); + } + + + private AnimatedFloat progress = new AnimatedFloat(this, 0, 260, CubicBezierInterpolator.EASE_OUT_QUINT); + + @Override + protected void onDraw(Canvas canvas) { + reactionButton.draw(canvas, (getWidth() - reactionButton.width) / 2f, (getHeight() - reactionButton.height) / 2f, progress.set(1f), 1f, false); + } + + private boolean attached; + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (!attached) { + if (reactionButton != null) { + reactionButton.attach(); + } + attached = true; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (attached) { + if (reactionButton != null) { + reactionButton.detach(); + } + attached = false; + } + } + } +} 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 8888144a9..d134cb85a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -66,6 +66,7 @@ import org.telegram.SQLite.SQLiteCursor; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; @@ -93,6 +94,7 @@ import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; 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.SimpleTextView; import org.telegram.ui.ActionBar.Theme; @@ -107,6 +109,7 @@ import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; import org.telegram.ui.LaunchActivity; import org.telegram.ui.MessageStatisticActivity; +import org.telegram.ui.PremiumPreviewFragment; import java.util.ArrayList; import java.util.Collections; @@ -124,6 +127,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi private FrameLayout writeButtonContainer; private View selectedCountView; private TextView pickerBottomLayout; + private FrameLayout bulletinContainer; private LinearLayout sharesCountLayout; private AnimatorSet animatorSet; private RecyclerListView topicsGridView; @@ -598,7 +602,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi protected void onPanTranslationUpdate(float y, float progress, boolean keyboardVisible) { super.onPanTranslationUpdate(y, progress, keyboardVisible); for (int i = 0; i < containerView.getChildCount(); i++) { - if (containerView.getChildAt(i) != pickerBottomLayout && containerView.getChildAt(i) != shadow[1] && containerView.getChildAt(i) != sharesCountLayout + if (containerView.getChildAt(i) != pickerBottomLayout && containerView.getChildAt(i) != bulletinContainer && containerView.getChildAt(i) != shadow[1] && containerView.getChildAt(i) != sharesCountLayout && containerView.getChildAt(i) != frameLayout2 && containerView.getChildAt(i) != writeButtonContainer && containerView.getChildAt(i) != selectedCountView) { containerView.getChildAt(i).setTranslationY(y); } @@ -1314,6 +1318,9 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi shadow[1].setAlpha(0.0f); } + bulletinContainer = new FrameLayout(context); + containerView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, pickerBottomLayout != null ? 48 : 0)); + frameLayout2 = new FrameLayout(context) { private final Paint p = new Paint(); @@ -1573,12 +1580,51 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi protected void onShareStory(View cell) { } + + private void showPremiumBlockedToast(View view, long dialogId) { + AndroidUtilities.shakeViewSpring(view, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + String username = ""; + if (dialogId >= 0) { + username = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } + Bulletin bulletin; + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { + bulletin = BulletinFactory.of(bulletinContainer, resourcesProvider).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username))); + } else { + bulletin = BulletinFactory.of(bulletinContainer, resourcesProvider).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username)), LocaleController.getString(R.string.UserBlockedNonPremiumButton), () -> { + Runnable openPremium = () -> { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + lastFragment.showAsSheet(new PremiumPreviewFragment("noncontacts"), params); + } + }; + if (isKeyboardVisible()) { + if (searchView != null) { + AndroidUtilities.hideKeyboard(searchView.searchEditText); + } + AndroidUtilities.runOnUIThread(openPremium, 300); + } else { + openPremium.run(); + } + }); + } + bulletin.show(); + } + private int shiftDp = 4; private void selectDialog(View cell, TLRPC.Dialog dialog) { if (dialog instanceof ShareDialogsAdapter.MyStoryDialog) { onShareStory(cell); return; } + if (dialog != null && (cell instanceof ShareDialogCell && ((ShareDialogCell) cell).isBlocked() || cell instanceof ProfileSearchCell && ((ProfileSearchCell) cell).isBlocked())) { + showPremiumBlockedToast(cell, dialog.id); + return; + } if (topicsGridView.getVisibility() != View.GONE || parentActivity == null) { return; } @@ -3023,7 +3069,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi break; } case 0: { - view = new ProfileSearchCell(context, resourcesProvider).useCustomPaints(); + view = new ProfileSearchCell(context, resourcesProvider).useCustomPaints().showPremiumBlock(true); break; } default: @@ -3053,7 +3099,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi }; layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); - horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true, resourcesProvider) { + horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true, true, resourcesProvider) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { HintDialogCell cell = (HintDialogCell) holder.itemView; @@ -3088,6 +3134,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } }); horizontalListView.setOnItemClickListener((view1, position) -> { + HintDialogCell cell = (HintDialogCell) view1; TLRPC.TL_topPeer peer = MediaDataController.getInstance(currentAccount).hints.get(position); TLRPC.Dialog dialog = new TLRPC.TL_dialog(); TLRPC.Chat chat = null; @@ -3100,9 +3147,12 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi } else if (peer.peer.chat_id != 0) { did = -peer.peer.chat_id; } + if (cell.isBlocked()) { + showPremiumBlockedToast(cell, did); + return; + } dialog.id = did; selectDialog(null, dialog); - HintDialogCell cell = (HintDialogCell) view1; cell.setChecked(selectedDialogs.indexOfKey(did) >= 0, true); }); view = horizontalListView; @@ -3211,7 +3261,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi ((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); + ((ShareDialogCell) holder.itemView).setDialog(id, selectedDialogs.indexOfKey(id) >= 0, name); } } else if (holder.getItemViewType() == 2) { ((RecyclerListView) holder.itemView).getAdapter().notifyDataSetChanged(); 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 1063714f7..68688774a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -10,11 +10,11 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; 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; @@ -58,13 +58,16 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; +import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; @@ -81,6 +84,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SavedMessagesController; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; @@ -96,6 +100,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; @@ -120,7 +125,9 @@ import org.telegram.ui.Cells.SharedPhotoVideoCell; import org.telegram.ui.Cells.SharedPhotoVideoCell2; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatActivityContainer; import org.telegram.ui.Components.Forum.ForumUtilities; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.DialogsActivity; import org.telegram.ui.PhotoViewer; import org.telegram.ui.PremiumPreviewFragment; @@ -136,9 +143,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Objects; @SuppressWarnings("unchecked") -public class SharedMediaLayout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { +public class SharedMediaLayout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate, DialogCell.DialogCellDelegate { public static final int TAB_PHOTOVIDEO = 0; public static final int TAB_FILES = 1; @@ -151,6 +159,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 TAB_SAVED_DIALOGS = 11; + public static final int TAB_SAVED_MESSAGES = 12; public static final int FILTER_PHOTOS_AND_VIDEOS = 0; public static final int FILTER_PHOTOS_ONLY = 1; @@ -194,7 +204,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter ActionBarPopupWindow optionsWindow; FlickerLoadingView globalGradientView; private final int viewType; - private int topicId; + private long topicId; private UndoView undoView; @@ -386,10 +396,42 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } + @Override + public void onButtonClicked(DialogCell dialogCell) { + + } + + @Override + public void onButtonLongPress(DialogCell dialogCell) { + + } + + @Override + public boolean canClickButtonInside() { + return false; + } + + @Override + public void openStory(DialogCell dialogCell, Runnable onDone) { + if (profileActivity == null) return; + if (profileActivity.getMessagesController().getStoriesController().hasStories(dialogCell.getDialogId())) { + profileActivity.getOrCreateStoryViewer().doOnAnimationReady(onDone); + profileActivity.getOrCreateStoryViewer().open(profileActivity.getContext(), dialogCell.getDialogId(), StoriesListPlaceProvider.of((RecyclerListView) dialogCell.getParent())); + } + } + + @Override + public void showChatPreview(DialogCell dialogCell) {} + + @Override + public void openHiddenStories() {} + private static class MediaPage extends FrameLayout { public long lastCheckScrollTime; public boolean fastScrollEnabled; public ObjectAnimator fastScrollAnimator; + private DefaultItemAnimator itemAnimator; + private RecyclerView.RecycledViewPool viewPool, searchViewPool; private InternalListView listView; private InternalListView animationSupportingListView; private GridLayoutManager animationSupportingLayoutManager; @@ -506,6 +548,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter private GifAdapter gifAdapter; private CommonGroupsAdapter commonGroupsAdapter; private ChannelRecommendationsAdapter channelRecommendationsAdapter; + private SavedDialogsAdapter savedDialogsAdapter; + private SavedMessagesSearchAdapter savedMessagesSearchAdapter; + private ChatActivityContainer savedMessagesContainer; private ChatUsersAdapter chatUsersAdapter; private StoriesAdapter storiesAdapter; private StoriesAdapter animationSupportingStoriesAdapter; @@ -521,6 +566,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public ImageView photoVideoOptionsItem; private ActionBarMenuItem forwardItem; private ActionBarMenuItem gotoItem; + private ActionBarMenuItem pinItem; + private ActionBarMenuItem unpinItem; private int searchItemState; private Drawable pinnedHeaderShadowDrawable; private boolean ignoreSearchCollapse; @@ -592,9 +639,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter private int[] mediaMergeCount = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; private int[] lastMediaCount = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; private int[] lastLoadMediaCount = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + public boolean hasSavedMessages; + private boolean checkedHasSavedMessages; private SharedMediaData[] sharedMediaData; private long dialogId; - private int topicId; + private long topicId; private long mergeDialogId; private BaseFragment parentFragment; private ArrayList delegates = new ArrayList<>(); @@ -607,10 +656,38 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter dialogId = chatActivity.getDialogId(); mergeDialogId = chatActivity.getMergeDialogId(); topicId = chatActivity.getTopicId(); + if (dialogId != fragment.getUserConfig().getClientUserId()) { + fragment.getMessagesController().getSavedMessagesController().hasSavedMessages(dialogId, hasMessages -> { + this.hasSavedMessages = hasMessages; + this.checkedHasSavedMessages = true; + if (hasSavedMessages) { + for (int a = 0, N = delegates.size(); a < N; a++) { + delegates.get(a).mediaCountUpdated(); + } + } + }); + } } else if (fragment instanceof ProfileActivity) { ProfileActivity profileActivity = (ProfileActivity) fragment; - dialogId = profileActivity.getDialogId(); - topicId = profileActivity.getTopicId(); + if (profileActivity.saved) { + dialogId = profileActivity.getUserConfig().getClientUserId(); + topicId = profileActivity.getDialogId(); + } else { + dialogId = profileActivity.getDialogId(); + topicId = profileActivity.getTopicId(); + + if (dialogId != fragment.getUserConfig().getClientUserId()) { + fragment.getMessagesController().getSavedMessagesController().hasSavedMessages(dialogId, hasMessages -> { + this.hasSavedMessages = hasMessages; + this.checkedHasSavedMessages = true; + if (hasSavedMessages) { + for (int a = 0, N = delegates.size(); a < N; a++) { + delegates.get(a).mediaCountUpdated(); + } + } + }); + } + } } else if (fragment instanceof MediaActivity) { MediaActivity mediaActivity = (MediaActivity) fragment; dialogId = mediaActivity.getDialogId(); @@ -634,6 +711,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter notificationCenter.addObserver(this, NotificationCenter.chatInfoDidLoad); notificationCenter.addObserver(this, NotificationCenter.fileLoaded); notificationCenter.addObserver(this, NotificationCenter.storiesListUpdated); + notificationCenter.addObserver(this, NotificationCenter.savedMessagesDialogsUpdate); } public void addDelegate(SharedMediaPreloaderDelegate delegate) { @@ -660,6 +738,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter notificationCenter.removeObserver(this, NotificationCenter.chatInfoDidLoad); notificationCenter.removeObserver(this, NotificationCenter.fileLoaded); notificationCenter.removeObserver(this, NotificationCenter.storiesListUpdated); + notificationCenter.removeObserver(this, NotificationCenter.savedMessagesDialogsUpdate); } public int[] getLastMediaCount() { @@ -674,7 +753,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.mediaCountsDidLoad) { long did = (Long) args[0]; - int topicId = (int) args[1]; + long topicId = (Long) args[1]; if (this.topicId == topicId && (did == dialogId || did == mergeDialogId)) { int[] counts = (int[]) args[2]; if (did == dialogId) { @@ -710,7 +789,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } else if (id == NotificationCenter.mediaCountDidLoad) { long did = (Long) args[0]; - long topicId = (Integer) args[1]; + long topicId = (Long) args[1]; if ((did == dialogId || did == mergeDialogId) && this.topicId == topicId) { int type = (Integer) args[4]; int mCount = (Integer) args[2]; @@ -738,9 +817,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (dialogId == (Long) args[0]) { boolean enc = DialogObject.isEncryptedDialog(dialogId); ArrayList arr = (ArrayList) args[1]; + final int currentAccount = parentFragment != null ? parentFragment.getCurrentAccount() : -1; for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); - if (topicId != 0 && topicId != MessageObject.getTopicId(obj.messageOwner, true)) { + if (topicId != 0 && topicId != MessageObject.getTopicId(currentAccount, obj.messageOwner, true)) { continue; } if (MessageObject.getMedia(obj.messageOwner) == null || obj.needDrawBluredPreview()) { @@ -826,11 +906,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter boolean changed = false; int type; ArrayList markAsDeletedMessages = (ArrayList) args[0]; + final int currentAccount = parentFragment != null ? parentFragment.getCurrentAccount() : -1; for (int a = 0, N = markAsDeletedMessages.size(); a < N; a++) { for (int b = 0; b < sharedMediaData.length; b++) { MessageObject messageObject = sharedMediaData[b].deleteMessage(markAsDeletedMessages.get(a), 0); if (messageObject != null) { - if (messageObject.getDialogId() == dialogId && (topicId == 0 || MessageObject.getTopicId(messageObject.messageOwner, true) == topicId)) { + if (messageObject.getDialogId() == dialogId && (topicId == 0 || MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true) == topicId)) { if (mediaCount[b] > 0) { mediaCount[b]--; } @@ -865,10 +946,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } int loadIndex = did == dialogId ? 0 : 1; ArrayList messageObjects = (ArrayList) args[1]; + final int currentAccount = parentFragment != null ? parentFragment.getCurrentAccount() : -1; for (int b = 0, N = messageObjects.size(); b < N; b++) { MessageObject messageObject = messageObjects.get(b); int mid = messageObject.getId(); - int topicId = MessageObject.getTopicId(messageObject.messageOwner, true); + long topicId = MessageObject.getTopicId(currentAccount, messageObject.messageOwner, true); int type = MediaDataController.getMediaType(messageObject.messageOwner); if (this.topicId != 0 && topicId != this.topicId) { continue; @@ -926,6 +1008,14 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } }); } + } else if (id == NotificationCenter.savedMessagesDialogsUpdate) { + final boolean newHasMessages = (parentFragment != null && parentFragment.getMessagesController().getSavedMessagesController().containsDialog(dialogId)); + if (checkedHasSavedMessages && hasSavedMessages != newHasMessages) { + hasSavedMessages = newHasMessages; + for (int a = 0, N = delegates.size(); a < N; a++) { + delegates.get(a).mediaCountUpdated(); + } + } } } @@ -1240,6 +1330,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter private final static int forward = 100; private final static int delete = 101; private final static int gotochat = 102; + private final static int pin = 103; + private final static int unpin = 104; private BaseFragment profileActivity; @@ -1275,6 +1367,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter hasMedia = new int[]{mediaCount[0], mediaCount[1], mediaCount[2], mediaCount[3], mediaCount[4], mediaCount[5], topicId == 0 ? commonGroupsCount : 0}; if (initialTab == TAB_RECOMMENDED_CHANNELS) { this.initialTab = initialTab; + } else if (initialTab == TAB_SAVED_DIALOGS) { + 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) { @@ -1319,6 +1413,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); + profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.savedMessagesDialogsUpdate); for (int a = 0; a < 10; a++) { //cellCache.add(new SharedPhotoVideoCell(context)); @@ -1360,6 +1455,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } cantDeleteMessagesCount = 0; actionModeViews.clear(); + if (savedDialogsAdapter != null) { + savedDialogsAdapter.unselectAll(); + } final ActionBarMenu menu = actionBar.createMenu(); menu.addOnLayoutChangeListener(new OnLayoutChangeListener() { @@ -1387,6 +1485,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter linksSearchAdapter.search(null, true); audioSearchAdapter.search(null, true); groupUsersSearchAdapter.search(null, true); + if (savedMessagesSearchAdapter != null) { + savedMessagesSearchAdapter.search(null); + } onSearchStateChanged(false); if (ignoreSearchCollapse) { ignoreSearchCollapse = false; @@ -1424,6 +1525,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return; } groupUsersSearchAdapter.search(text, true); + } else if (mediaPages[0].selectedType == TAB_SAVED_DIALOGS) { + if (savedMessagesSearchAdapter == null) { + return; + } + savedMessagesSearchAdapter.search(text); } } @@ -1677,6 +1783,24 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter actionModeViews.add(forwardItem); forwardItem.setOnClickListener(v -> onActionBarItemClick(v, forward)); + pinItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); + pinItem.setIcon(R.drawable.msg_pin); + pinItem.setContentDescription(LocaleController.getString(R.string.PinMessage)); + pinItem.setDuplicateParentStateEnabled(false); + pinItem.setVisibility(View.GONE); + actionModeLayout.addView(pinItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeViews.add(pinItem); + pinItem.setOnClickListener(v -> onActionBarItemClick(v, pin)); + + unpinItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); + unpinItem.setIcon(R.drawable.msg_unpin); + unpinItem.setContentDescription(LocaleController.getString(R.string.UnpinMessage)); + unpinItem.setDuplicateParentStateEnabled(false); + unpinItem.setVisibility(View.GONE); + actionModeLayout.addView(unpinItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeViews.add(unpinItem); + unpinItem.setOnClickListener(v -> onActionBarItemClick(v, unpin)); + updateForwardItem(); } deleteItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); @@ -1708,6 +1832,16 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter groupUsersSearchAdapter = new GroupUsersSearchAdapter(context); commonGroupsAdapter = new CommonGroupsAdapter(context); channelRecommendationsAdapter = new ChannelRecommendationsAdapter(context); + savedDialogsAdapter = new SavedDialogsAdapter(context); + savedMessagesSearchAdapter = new SavedMessagesSearchAdapter(context); + if (!isStoriesView() && !includeSavedDialogs()) { + Bundle args = new Bundle(); + args.putLong("user_id", profileActivity.getUserConfig().getClientUserId()); + args.putInt("chatMode", ChatActivity.MODE_SAVED); + savedMessagesContainer = new ChatActivityContainer(context, profileActivity.getParentLayout(), args); + savedMessagesContainer.chatActivity.setSavedDialog(dialog_id); + savedMessagesContainer.chatActivity.reversed = true; + } chatUsersAdapter = new ChatUsersAdapter(context); if (topicId == 0) { chatUsersAdapter.sortedUsers = sortedUsers; @@ -1765,6 +1899,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } final MediaPage mediaPage = new MediaPage(context) { + @Override public void setTranslationX(float translationX) { super.setTranslationX(translationX); @@ -1891,6 +2026,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return mediaPage.layoutManager.getSpanSizeForItem(position); } }); + mediaPages[a].itemAnimator = new DefaultItemAnimator(); + mediaPages[a].itemAnimator.setDurations(280); + mediaPages[a].itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + mediaPages[a].itemAnimator.setSupportsChangeAnimations(false); mediaPages[a].listView = new InternalListView(context) { final HashSet excludeDrawViews = new HashSet<>(); @@ -2452,6 +2591,55 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter args.putLong("chat_id", channelRecommendationsAdapter.chats.get(position).id); profileActivity.presentFragment(new ChatActivity(args)); } + } else if (mediaPage.selectedType == TAB_SAVED_DIALOGS) { + if (mediaPage.listView.getAdapter() == savedMessagesSearchAdapter) { + if (position < 0) { + return; + } + if (position < savedMessagesSearchAdapter.dialogs.size()) { + SavedMessagesController.SavedDialog d = savedMessagesSearchAdapter.dialogs.get(position); + + Bundle args = new Bundle(); + args.putLong("user_id", profileActivity.getUserConfig().getClientUserId()); + args.putInt("chatMode", ChatActivity.MODE_SAVED); + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.setSavedDialog(d.dialogId); + profileActivity.presentFragment(chatActivity); + return; + } + + position -= savedMessagesSearchAdapter.dialogs.size(); + if (position < savedMessagesSearchAdapter.messages.size()) { + MessageObject msg = savedMessagesSearchAdapter.messages.get(position); + + Bundle args = new Bundle(); + args.putLong("user_id", profileActivity.getUserConfig().getClientUserId()); + args.putInt("message_id", msg.getId()); + args.putInt("chatMode", ChatActivity.MODE_SAVED); + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.setSavedDialog(msg.getSavedDialogId()); + chatActivity.setHighlightMessageId(msg.getId()); + profileActivity.presentFragment(chatActivity); + } + return; + } + if (isActionModeShowed) { + if (savedDialogsAdapter.itemTouchHelper.isIdle()) { + savedDialogsAdapter.select(view); + } + return; + } + + Bundle args = new Bundle(); + if (position < 0 || position >= savedDialogsAdapter.dialogs.size()) { + return; + } + SavedMessagesController.SavedDialog d = savedDialogsAdapter.dialogs.get(position); + args.putLong("user_id", profileActivity.getUserConfig().getClientUserId()); + args.putInt("chatMode", ChatActivity.MODE_SAVED); + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.setSavedDialog(d.dialogId); + profileActivity.presentFragment(chatActivity); } }); mediaPages[a].listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -2463,10 +2651,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { checkLoadMoreScroll(mediaPage, (RecyclerListView) recyclerView, layoutManager); - if (dy != 0 && (mediaPages[0].selectedType == 0 || mediaPages[0].selectedType == 5) && !sharedMediaData[0].messages.isEmpty()) { + if (dy != 0 && (mediaPages[0].selectedType == TAB_PHOTOVIDEO || mediaPages[0].selectedType == TAB_GIF) && !sharedMediaData[0].messages.isEmpty()) { showFloatingDateView(); } - if (dy != 0 && (mediaPage.selectedType == 0 || mediaPage.selectedType == TAB_STORIES || mediaPage.selectedType == TAB_ARCHIVED_STORIES)) { + if (dy != 0 && (mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_STORIES || mediaPage.selectedType == TAB_ARCHIVED_STORIES)) { showFastScrollHint(mediaPage, sharedMediaData, true); } mediaPage.listView.checkSection(true); @@ -2482,7 +2670,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (photoVideoChangeColumnsAnimation) { return false; } - if (isActionModeShowed) { + if (isActionModeShowed && mediaPage.selectedType != TAB_SAVED_DIALOGS) { mediaPage.listView.clickItem(view, position); return true; } @@ -2524,6 +2712,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { channelRecommendationsAdapter.openPreview(position); return true; + } else if (mediaPage.selectedType == TAB_SAVED_DIALOGS) { + savedDialogsAdapter.select(view); + return true; } return false; } @@ -2661,6 +2852,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return true; } + protected boolean includeSavedDialogs() { + return false; + } + protected int getInitialTab() { return 0; } @@ -2813,7 +3008,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } Bundle bundle = new Bundle(); bundle.putLong("dialog_id", dialog_id); - bundle.putInt("topic_id", topicId); + bundle.putLong("topic_id", topicId); int date = 0; if (fromFastScroll) { MediaPage mediaPage = getMediaPage(0); @@ -3376,13 +3571,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return; } mediaPage.lastCheckScrollTime = currentTime; - if (searching && searchWas || mediaPage.selectedType == TAB_GROUPUSERS) { + if (searching && searchWas && mediaPage.selectedType != TAB_SAVED_DIALOGS || mediaPage.selectedType == TAB_GROUPUSERS) { return; } int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : Math.abs(layoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; - int totalItemCount = recyclerView.getAdapter().getItemCount(); - if (mediaPage.selectedType == 0 || mediaPage.selectedType == 1 || mediaPage.selectedType == 2 || mediaPage.selectedType == 4) { + int totalItemCount = recyclerView.getAdapter() == null ? 0 : recyclerView.getAdapter().getItemCount(); + if (mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_FILES || mediaPage.selectedType == TAB_VOICE || mediaPage.selectedType == TAB_AUDIO) { int type = mediaPage.selectedType; totalItemCount = sharedMediaData[type].getStartOffset() + sharedMediaData[type].messages.size(); if (sharedMediaData[type].fastScrollDataLoaded && sharedMediaData[type].fastScrollPeriods.size() > 2 && mediaPage.selectedType == 0 && sharedMediaData[type].messages.size() != 0) { @@ -3423,7 +3618,23 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter commonGroupsAdapter.getChats(commonGroupsAdapter.chats.get(commonGroupsAdapter.chats.size() - 1).id, 100); } } - } else if (mediaPage.selectedType != TAB_RECOMMENDED_CHANNELS) { + } else if (mediaPage.selectedType == TAB_SAVED_DIALOGS) { + int lastVisiblePosition = -1; + for (int i = 0; i < mediaPage.listView.getChildCount(); ++i) { + View child = mediaPage.listView.getChildAt(i); + int position = mediaPage.listView.getChildAdapterPosition(child); + lastVisiblePosition = Math.max(position, lastVisiblePosition); + } + if (mediaPage.listView.getAdapter() == savedMessagesSearchAdapter) { + if (lastVisiblePosition + 1 >= savedMessagesSearchAdapter.dialogs.size() + savedMessagesSearchAdapter.messages.size()) { + savedMessagesSearchAdapter.loadMore(); + } + return; + } + if (lastVisiblePosition + 1 >= profileActivity.getMessagesController().getSavedMessagesController().getLoadedCount()) { + profileActivity.getMessagesController().getSavedMessagesController().loadDialogs(); + } + } else if (mediaPage.selectedType != TAB_RECOMMENDED_CHANNELS && mediaPage.selectedType != TAB_SAVED_MESSAGES) { final int threshold; if (mediaPage.selectedType == 0) { threshold = 3; @@ -3469,9 +3680,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (firstVisibleItem - startOffset < threshold + 1 && !sharedMediaData[mediaPage.selectedType].loading && !sharedMediaData[mediaPage.selectedType].startReached && !sharedMediaData[mediaPage.selectedType].loadingAfterFastScroll) { loadFromStart(mediaPage.selectedType); } - if (mediaPages[0].listView == recyclerView && (mediaPages[0].selectedType == 0 || mediaPages[0].selectedType == 5) && firstVisibleItem != RecyclerView.NO_POSITION) { + if (mediaPages[0].listView == recyclerView && (mediaPages[0].selectedType == TAB_PHOTOVIDEO || mediaPages[0].selectedType == TAB_GIF) && firstVisibleItem != RecyclerView.NO_POSITION) { RecyclerListView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(firstVisibleItem); - if (holder != null && holder.getItemViewType() == 0) { + if (holder != null && (holder.getItemViewType() == VIEW_TYPE_PHOTOVIDEO || holder.getItemViewType() == VIEW_TYPE_GIF)) { if (holder.itemView instanceof SharedPhotoVideoCell) { SharedPhotoVideoCell cell = (SharedPhotoVideoCell) holder.itemView; MessageObject messageObject = cell.getMessageObject(0); @@ -3526,6 +3737,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[0].selectedType != TAB_VOICE && mediaPages[0].selectedType != TAB_GIF && mediaPages[0].selectedType != TAB_COMMON_GROUPS && + mediaPages[0].selectedType != TAB_SAVED_MESSAGES && mediaPages[0].selectedType != TAB_RECOMMENDED_CHANNELS ); } @@ -3586,6 +3798,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); + profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.savedMessagesDialogsUpdate); if (storiesAdapter != null && storiesAdapter.storiesList != null) { storiesAdapter.destroy(); @@ -3738,6 +3951,53 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void onActionBarItemClick(View v, int id) { if (id == delete) { + if (getSelectedTab() == TAB_SAVED_DIALOGS) { + final SavedMessagesController controller = profileActivity.getMessagesController().getSavedMessagesController(); + final ArrayList selectedDialogs = new ArrayList<>(); + for (int i = 0; i < controller.allDialogs.size(); ++i) { + final long did = controller.allDialogs.get(i).dialogId; + if (savedDialogsAdapter.selectedDialogs.contains(did)) { + selectedDialogs.add(did); + } + } + String firstDialog = ""; + if (!selectedDialogs.isEmpty()) { + long did = selectedDialogs.get(0); + if (did < 0) { + TLRPC.Chat chat = profileActivity.getMessagesController().getChat(-did); + if (chat != null) { + firstDialog = chat.title; + } + } else if (did >= 0) { + TLRPC.User user = profileActivity.getMessagesController().getUser(did); + if (user != null) { + if (UserObject.isAnonymous(user)) { + firstDialog = LocaleController.getString(R.string.AnonymousForward); + } else { + firstDialog = UserObject.getUserName(user); + } + } + } + } + AlertDialog dialog = new AlertDialog.Builder(getContext(), resourcesProvider) + .setTitle(selectedDialogs.size() == 1 ? LocaleController.formatString(R.string.ClearHistoryTitleSingle, firstDialog) : LocaleController.formatPluralString("ClearHistoryTitleMultiple", selectedDialogs.size())) + .setMessage(selectedDialogs.size() == 1 ? LocaleController.formatString(R.string.ClearHistoryMessageSingle, firstDialog) : LocaleController.formatPluralString("ClearHistoryMessageMultiple", selectedDialogs.size())) + .setPositiveButton(LocaleController.getString(R.string.Remove), (di, w) -> { + for (int i = 0; i < selectedDialogs.size(); ++i) { + final long did = selectedDialogs.get(i); + profileActivity.getMessagesController().deleteSavedDialog(did); + } + closeActionMode(); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .create(); + profileActivity.showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + } + return; + } TLRPC.Chat currentChat = null; TLRPC.User currentUser = null; TLRPC.EncryptedChat currentEncryptedChat = null; @@ -3748,7 +4008,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else { currentChat = profileActivity.getMessagesController().getChat(-dialog_id); } - AlertsCreator.createDeleteMessagesAlert(profileActivity, currentUser, currentChat, currentEncryptedChat, null, mergeDialogId, null, selectedFiles, null, false, 1, () -> { + AlertsCreator.createDeleteMessagesAlert(profileActivity, currentUser, currentChat, currentEncryptedChat, null, mergeDialogId, null, selectedFiles, null, false, false, 1, () -> { showActionMode(false); actionBar.closeSearchField(); cantDeleteMessagesCount = 0; @@ -3795,6 +4055,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } cantDeleteMessagesCount = 0; showActionMode(false); + if (savedDialogsAdapter != null) { + savedDialogsAdapter.unselectAll(); + } if (dids.size() > 1 || dids.get(0).dialogId == profileActivity.getUserConfig().getClientUserId() || message != null) { updateRowsSelection(true); @@ -3872,6 +4135,27 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter args.putInt("message_id", messageObject.getId()); } profileActivity.presentFragment(chatActivity, false); + } else if (id == pin || id == unpin) { + final SavedMessagesController controller = profileActivity.getMessagesController().getSavedMessagesController(); + final ArrayList selectedDialogs = new ArrayList<>(); + for (int i = 0; i < controller.allDialogs.size(); ++i) { + final long did = controller.allDialogs.get(i).dialogId; + if (savedDialogsAdapter.selectedDialogs.contains(did)) { + selectedDialogs.add(did); + } + } + if (!controller.updatePinned(selectedDialogs, id == pin)) { + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(profileActivity, getContext(), LimitReachedBottomSheet.TYPE_PIN_SAVED_DIALOGS, profileActivity.getCurrentAccount(), null); + profileActivity.showDialog(limitReachedBottomSheet); + } else { + for (int i = 0; i < mediaPages.length; ++i) { + if (mediaPages[i].selectedType == TAB_SAVED_DIALOGS) { + mediaPages[i].layoutManager.scrollToPositionWithOffset(0, 0); + break; + } + } + } + closeActionMode(true); } } @@ -3999,6 +4283,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } public RecyclerListView getCurrentListView() { + if (mediaPages[0].selectedType == TAB_SAVED_MESSAGES && savedMessagesContainer != null) { + return savedMessagesContainer.chatActivity.getChatListView(); + } return mediaPages[0].listView; } @@ -4232,6 +4519,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter cantDeleteMessagesCount = 0; showActionMode(false); updateRowsSelection(uncheckAnimated); + if (savedDialogsAdapter != null) { + savedDialogsAdapter.unselectAll(); + } return true; } else { return false; @@ -4659,6 +4949,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter updateTabs(true); checkCurrentTabValid(); } + } else if (id == NotificationCenter.savedMessagesDialogsUpdate) { + if (dialog_id == 0 || dialog_id == profileActivity.getUserConfig().getClientUserId()) { + savedDialogsAdapter.update(true); + updateTabs(true); + checkCurrentTabValid(); + onSelectedTabChanged(); + } } } @@ -4827,6 +5124,15 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter for (int a = 0; a < mediaPages.length; a++) { fixLayoutInternal(a); } + if (savedMessagesContainer != null) { + savedMessagesContainer.onResume(); + } + } + + public void onPause() { + if (savedMessagesContainer != null) { + savedMessagesContainer.onPause(); + } } public void onConfigurationChanged(android.content.res.Configuration newConfig) { @@ -4878,7 +5184,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void setChatUsers(ArrayList sortedUsers, TLRPC.ChatFull chatInfo) { for (int a = 0; a < mediaPages.length; a++) { if (mediaPages[a].selectedType == TAB_GROUPUSERS) { - if (mediaPages[a].listView.getAdapter().getItemCount() != 0 && profileActivity.getMessagesController().getStoriesController().hasLoadingStories()) { + if (mediaPages[a].listView.getAdapter() != null && mediaPages[a].listView.getAdapter().getItemCount() != 0 && profileActivity.getMessagesController().getStoriesController().hasLoadingStories()) { return; } } @@ -4889,7 +5195,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } updateTabs(true); for (int a = 0; a < mediaPages.length; a++) { - if (mediaPages[a].selectedType == TAB_GROUPUSERS) { + if (mediaPages[a].selectedType == TAB_GROUPUSERS && mediaPages[a].listView.getAdapter() != null) { mediaPages[a].listView.getAdapter().notifyDataSetChanged(); } } @@ -4935,6 +5241,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter ((SharedAudioCell) child).setChecked(false, animated); } else if (child instanceof ContextLinkCell) { ((ContextLinkCell) child).setChecked(false, animated); + } else if (child instanceof DialogCell) { + ((DialogCell) child).setChecked(false, animated); } } } @@ -4952,6 +5260,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter animated = false; } boolean hasRecommendations = false; + boolean hasSavedDialogs = false; + boolean hasSavedMessages = savedMessagesContainer != null && sharedMediaPreloader != null && sharedMediaPreloader.hasSavedMessages; 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++; @@ -4991,6 +5301,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (hasRecommendations != scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { changed++; } + hasSavedDialogs = includeSavedDialogs() && !profileActivity.getMessagesController().getSavedMessagesController().unsupported && profileActivity.getMessagesController().getSavedMessagesController().getAllCount() > 0; + if (hasSavedDialogs != scrollSlidingTextTabStrip.hasTab(TAB_SAVED_DIALOGS)) { + changed++; + } + if (hasSavedMessages != scrollSlidingTextTabStrip.hasTab(TAB_SAVED_MESSAGES)) { + changed++; + } } if (changed > 0) { if (animated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -5050,6 +5367,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } if (!isStoriesView()) { + if (hasSavedDialogs) { + if (!scrollSlidingTextTabStrip.hasTab(TAB_SAVED_DIALOGS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_DIALOGS, LocaleController.getString(R.string.SavedDialogsTab), idToView); + } + } if (chatUsersAdapter.chatInfo != null) { if (!scrollSlidingTextTabStrip.hasTab(TAB_GROUPUSERS)) { scrollSlidingTextTabStrip.addTextTab(TAB_GROUPUSERS, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); @@ -5107,6 +5429,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter scrollSlidingTextTabStrip.addTextTab(TAB_RECOMMENDED_CHANNELS, LocaleController.getString(R.string.SimilarChannelsTab), idToView); } } + if (hasSavedMessages) { + if (!scrollSlidingTextTabStrip.hasTab(TAB_SAVED_MESSAGES)) { + scrollSlidingTextTabStrip.addTextTab(TAB_SAVED_MESSAGES, LocaleController.getString(R.string.SavedMessagesTab), idToView); + } + MessagesController.getGlobalMainSettings().edit().putInt("savedhint", 3).apply(); + } } } int id = scrollSlidingTextTabStrip.getCurrentTabId(); @@ -5149,15 +5477,19 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter RecyclerView.Adapter currentAdapter = mediaPages[a].listView.getAdapter(); RecyclerView.RecycledViewPool viewPool = null; if (searching && searchWas) { + if (mediaPages[a].searchViewPool == null) { + mediaPages[a].searchViewPool = new RecyclerView.RecycledViewPool(); + } + viewPool = mediaPages[a].searchViewPool; if (animated) { - if (mediaPages[a].selectedType == 0 || mediaPages[a].selectedType == 2 || mediaPages[a].selectedType == 5 || mediaPages[a].selectedType == 6 || mediaPages[a].selectedType == 7 && !delegate.canSearchMembers()) { + if (mediaPages[a].selectedType == TAB_PHOTOVIDEO || mediaPages[a].selectedType == TAB_VOICE || mediaPages[a].selectedType == TAB_GIF || mediaPages[a].selectedType == TAB_COMMON_GROUPS || mediaPages[a].selectedType == TAB_GROUPUSERS && !delegate.canSearchMembers()) { searching = false; searchWas = false; switchToCurrentSelectedMode(true); return; } else { String text = searchItem.getSearchField().getText().toString(); - if (mediaPages[a].selectedType == 1) { + if (mediaPages[a].selectedType == TAB_FILES) { if (documentsSearchAdapter != null) { documentsSearchAdapter.search(text, false); if (currentAdapter != documentsSearchAdapter) { @@ -5165,7 +5497,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[a].listView.setAdapter(documentsSearchAdapter); } } - } else if (mediaPages[a].selectedType == 3) { + } else if (mediaPages[a].selectedType == TAB_LINKS) { if (linksSearchAdapter != null) { linksSearchAdapter.search(text, false); if (currentAdapter != linksSearchAdapter) { @@ -5173,7 +5505,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[a].listView.setAdapter(linksSearchAdapter); } } - } else if (mediaPages[a].selectedType == 4) { + } else if (mediaPages[a].selectedType == TAB_AUDIO) { if (audioSearchAdapter != null) { audioSearchAdapter.search(text, false); if (currentAdapter != audioSearchAdapter) { @@ -5181,7 +5513,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[a].listView.setAdapter(audioSearchAdapter); } } - } else if (mediaPages[a].selectedType == 7) { + } else if (mediaPages[a].selectedType == TAB_GROUPUSERS) { if (groupUsersSearchAdapter != null) { groupUsersSearchAdapter.search(text, false); if (currentAdapter != groupUsersSearchAdapter) { @@ -5189,38 +5521,56 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[a].listView.setAdapter(groupUsersSearchAdapter); } } + } else if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + if (savedMessagesSearchAdapter != null) { + savedMessagesSearchAdapter.search(text); + if (currentAdapter != savedMessagesSearchAdapter) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(savedMessagesSearchAdapter); + } + } } } } else { if (mediaPages[a].listView != null) { - if (mediaPages[a].selectedType == 1) { + if (mediaPages[a].selectedType == TAB_FILES) { if (currentAdapter != documentsSearchAdapter) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(documentsSearchAdapter); } documentsSearchAdapter.notifyDataSetChanged(); - } else if (mediaPages[a].selectedType == 3) { + } else if (mediaPages[a].selectedType == TAB_LINKS) { if (currentAdapter != linksSearchAdapter) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(linksSearchAdapter); } linksSearchAdapter.notifyDataSetChanged(); - } else if (mediaPages[a].selectedType == 4) { + } else if (mediaPages[a].selectedType == TAB_AUDIO) { if (currentAdapter != audioSearchAdapter) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(audioSearchAdapter); } audioSearchAdapter.notifyDataSetChanged(); - } else if (mediaPages[a].selectedType == 7) { + } else if (mediaPages[a].selectedType == TAB_GROUPUSERS) { if (currentAdapter != groupUsersSearchAdapter) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(groupUsersSearchAdapter); } groupUsersSearchAdapter.notifyDataSetChanged(); + } else if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + if (currentAdapter != savedMessagesSearchAdapter) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(savedMessagesSearchAdapter); + } + savedMessagesSearchAdapter.notifyDataSetChanged(); } } } } else { + if (mediaPages[a].viewPool == null) { + mediaPages[a].viewPool = new RecyclerView.RecycledViewPool(); + } + viewPool = mediaPages[a].viewPool; mediaPages[a].listView.setPinnedHeaderShadowDrawable(null); mediaPages[a].listView.setPadding( mediaPages[a].listView.getPaddingLeft(), @@ -5305,8 +5655,37 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(channelRecommendationsAdapter); } + } else if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + if (currentAdapter != savedDialogsAdapter) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(savedDialogsAdapter); + savedDialogsAdapter.itemTouchHelper.attachToRecyclerView(savedDialogsAdapter.attachedToRecyclerView = mediaPages[a].listView); + } + viewPool = savedDialogsAdapter.viewPool; + } else if (mediaPages[a].selectedType == TAB_SAVED_MESSAGES) { + if (currentAdapter != null) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(null); + } + if (savedMessagesContainer.getParent() != mediaPages[a]) { + if (savedMessagesContainer.getParent() instanceof ViewGroup) { + ((ViewGroup) savedMessagesContainer.getParent()).removeView(savedMessagesContainer); + } + mediaPages[a].addView(savedMessagesContainer); + } } - 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 (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + mediaPages[a].listView.setItemAnimator(mediaPages[a].itemAnimator); + } else { + mediaPages[a].listView.setItemAnimator(null); + if (savedDialogsAdapter != null && mediaPages[a].listView == savedDialogsAdapter.attachedToRecyclerView) { + savedDialogsAdapter.itemTouchHelper.attachToRecyclerView(savedDialogsAdapter.attachedToRecyclerView = null); + } + } + if (savedMessagesContainer != null && mediaPages[a].selectedType != TAB_SAVED_MESSAGES && savedMessagesContainer.getParent() == mediaPages[a]) { + mediaPages[a].removeView(savedMessagesContainer); + } + 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 || mediaPages[a].selectedType == TAB_SAVED_MESSAGES) { if (animated) { searchItemState = 2; } else { @@ -5355,6 +5734,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter fastScrollVisible = storiesList != null && storiesList.getCount() > 0; } else if (mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { + } else if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + + } else if (mediaPages[a].selectedType == TAB_SAVED_MESSAGES) { + } else { if (!sharedMediaData[mediaPages[a].selectedType].loading && !sharedMediaData[mediaPages[a].selectedType].endReached[0] && sharedMediaData[mediaPages[a].selectedType].messages.isEmpty()) { sharedMediaData[mediaPages[a].selectedType].loading = true; @@ -5389,8 +5772,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter updateFastScrollVisibility(mediaPages[a], false); mediaPages[a].layoutManager.setSpanCount(spanCount); mediaPages[a].listView.invalidateItemDecorations(); - mediaPages[a].listView.setRecycledViewPool(viewPool); - mediaPages[a].animationSupportingListView.setRecycledViewPool(viewPool); + if (viewPool != null) { + mediaPages[a].listView.setRecycledViewPool(viewPool); + mediaPages[a].animationSupportingListView.setRecycledViewPool(viewPool); + } if (searchItemState == 2 && actionBar.isSearchFieldVisible()) { ignoreSearchCollapse = true; @@ -5479,6 +5864,15 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (gotoItem != null) { gotoItem.setVisibility(selectedFiles[0].size() == 1 ? View.VISIBLE : View.GONE); } + if (forwardItem != null) { + forwardItem.setVisibility(View.VISIBLE); + } + if (pinItem != null) { + pinItem.setVisibility(View.GONE); + } + if (unpinItem != null) { + unpinItem.setVisibility(View.GONE); + } } scrolling = false; if (view instanceof SharedDocumentCell) { @@ -5718,18 +6112,18 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_LINK_DATE: view = new GraySectionCell(mContext, resourcesProvider); break; - case 1: + case VIEW_TYPE_LINK: view = new SharedLinkCell(mContext, SharedLinkCell.VIEW_TYPE_DEFAULT, resourcesProvider); ((SharedLinkCell) view).setDelegate(sharedLinkCellDelegate); break; - case 3: + case VIEW_TYPE_LINK_EMPTY: View emptyStubView = createEmptyStubView(mContext, 3, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); - case 2: + case VIEW_TYPE_LINK_LOADING: default: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext, resourcesProvider); flickerLoadingView.setIsSingleCell(true); @@ -5744,19 +6138,24 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(int section, int position, RecyclerView.ViewHolder holder) { - if (holder.getItemViewType() != 2 && holder.getItemViewType() != 3) { + if (holder.getItemViewType() != VIEW_TYPE_LINK_LOADING && holder.getItemViewType() != VIEW_TYPE_LINK_EMPTY) { String name = sharedMediaData[3].sections.get(section); ArrayList messageObjects = sharedMediaData[3].sectionArrays.get(name); switch (holder.getItemViewType()) { - case 0: { + case VIEW_TYPE_LINK_DATE: { MessageObject messageObject = messageObjects.get(0); - ((GraySectionCell) holder.itemView).setText(LocaleController.formatSectionDate(messageObject.messageOwner.date)); + if (holder.itemView instanceof GraySectionCell) { + ((GraySectionCell) holder.itemView).setText(LocaleController.formatSectionDate(messageObject.messageOwner.date)); + } break; } - case 1: { + case VIEW_TYPE_LINK: { if (section != 0) { position--; } + if (!(holder.itemView instanceof SharedLinkCell) || position < 0 || position >= messageObjects.size()) { + return; + } SharedLinkCell sharedLinkCell = (SharedLinkCell) holder.itemView; MessageObject messageObject = messageObjects.get(position); sharedLinkCell.setLink(messageObject, position != messageObjects.size() - 1 || section == sharedMediaData[3].sections.size() - 1 && sharedMediaData[3].loading); @@ -5774,16 +6173,16 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int section, int position) { if (sharedMediaData[3].sections.size() == 0 && !sharedMediaData[3].loading) { - return 3; + return VIEW_TYPE_LINK_EMPTY; } if (section < sharedMediaData[3].sections.size()) { if (section != 0 && position == 0) { - return 0; + return VIEW_TYPE_LINK_DATE; } else { - return 1; + return VIEW_TYPE_LINK; } } - return 2; + return VIEW_TYPE_LINK_LOADING; } @Override @@ -5844,12 +6243,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 1: + case VIEW_TYPE_DOCUMENT: SharedDocumentCell cell = new SharedDocumentCell(mContext, SharedDocumentCell.VIEW_TYPE_DEFAULT, resourcesProvider); cell.setGlobalGradientView(globalGradientView); view = cell; break; - case 2: + case VIEW_TYPE_DOCUMENT_LOADING: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext, resourcesProvider); view = flickerLoadingView; if (currentType == 2) { @@ -5861,11 +6260,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter flickerLoadingView.setIsSingleCell(true); flickerLoadingView.setGlobalGradientView(globalGradientView); break; - case 4: + case VIEW_TYPE_DOCUMENT_EMPTY: View emptyStubView = createEmptyStubView(mContext, currentType, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); - case 3: + case VIEW_TYPE_AUDIO: default: if (currentType == MediaDataController.MEDIA_MUSIC && !audioCellCache.isEmpty()) { view = audioCellCache.get(0); @@ -5904,7 +6303,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { ArrayList messageObjects = sharedMediaData[currentType].messages; switch (holder.getItemViewType()) { - case 1: { + case VIEW_TYPE_DOCUMENT: { + if (!(holder.itemView instanceof SharedDocumentCell)) return; SharedDocumentCell sharedDocumentCell = (SharedDocumentCell) holder.itemView; MessageObject messageObject = messageObjects.get(position - sharedMediaData[currentType].startOffset); sharedDocumentCell.setDocument(messageObject, position != messageObjects.size() - 1); @@ -5915,7 +6315,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } break; } - case 3: { + case VIEW_TYPE_AUDIO: { + if (!(holder.itemView instanceof SharedAudioCell)) return; SharedAudioCell sharedAudioCell = (SharedAudioCell) holder.itemView; MessageObject messageObject = messageObjects.get(position - sharedMediaData[currentType].startOffset); sharedAudioCell.setMessageObject(messageObject, position != messageObjects.size() - 1); @@ -5933,16 +6334,16 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int position) { if (sharedMediaData[currentType].sections.size() == 0 && !sharedMediaData[currentType].loading) { - return 4; + return VIEW_TYPE_DOCUMENT_EMPTY; } if (position >= sharedMediaData[currentType].startOffset && position < sharedMediaData[currentType].startOffset + sharedMediaData[currentType].messages.size()) { if (currentType == 2 || currentType == 4) { - return 3; + return VIEW_TYPE_AUDIO; } else { - return 1; + return VIEW_TYPE_DOCUMENT; } } - return 2; + return VIEW_TYPE_DOCUMENT_LOADING; } @Override @@ -6106,6 +6507,31 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } + public static final int VIEW_TYPE_PHOTOVIDEO = 0; + public static final int VIEW_TYPE_PHOTOVIDEO_LOADING = 2; + public static final int VIEW_TYPE_LINK_DATE = 3; + public static final int VIEW_TYPE_LINK = 4; + public static final int VIEW_TYPE_LINK_EMPTY = 5; + public static final int VIEW_TYPE_LINK_LOADING = 6; + public static final int VIEW_TYPE_DOCUMENT = 7; + public static final int VIEW_TYPE_DOCUMENT_LOADING = 8; + public static final int VIEW_TYPE_DOCUMENT_EMPTY = 9; + public static final int VIEW_TYPE_AUDIO = 10; + public static final int VIEW_TYPE_GIF_LOADING = 11; + public static final int VIEW_TYPE_GIF = 12; + public static final int VIEW_TYPE_SAVED_DIALOG = 13; + public static final int VIEW_TYPE_GROUP = 14; + public static final int VIEW_TYPE_GROUP_EMPTY = 15; + public static final int VIEW_TYPE_GROUP_LOADING = 16; + public static final int VIEW_TYPE_SIMILAR_CHANNEL = 17; + public static final int VIEW_TYPE_SIMILAR_CHANNEL_BLOCK = 18; + public static final int VIEW_TYPE_STORY = 19; + public static final int VIEW_TYPE_GROUPUSER_EMPTY = 20; + public static final int VIEW_TYPE_GROUPUSER = 21; + public static final int VIEW_TYPE_SEARCH_GROUPUSER = 22; + public static final int VIEW_TYPE_SEARCH_SAVED_DIALOG = 23; + public static final int VIEW_TYPE_SEARCH_DOCUMENT = 24; + private class SharedPhotoVideoAdapter extends RecyclerListView.FastScrollAdapter { protected Context mContext; @@ -6172,7 +6598,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_PHOTOVIDEO: + case VIEW_TYPE_STORY: if (sharedResources == null) { sharedResources = new SharedPhotoVideoCell2.SharedResources(parent.getContext(), resourcesProvider); } @@ -6184,7 +6611,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter view = cell; break; default: - case 2: + case VIEW_TYPE_PHOTOVIDEO_LOADING: View emptyStubView = createEmptyStubView(mContext, 0, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); @@ -6195,9 +6622,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { + if (holder.getItemViewType() == VIEW_TYPE_PHOTOVIDEO) { ArrayList messageObjects = sharedMediaData[0].getMessages(); int index = position - sharedMediaData[0].getStartOffset(); + if (!(holder.itemView instanceof SharedPhotoVideoCell2)) return; SharedPhotoVideoCell2 cell = (SharedPhotoVideoCell2) holder.itemView; int oldMessageId = cell.getMessageId(); @@ -6229,13 +6657,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int position) { if (!inFastScrollMode && sharedMediaData[0].getMessages().size() == 0 && !sharedMediaData[0].loading && sharedMediaData[0].startReached) { - return 2; + return VIEW_TYPE_PHOTOVIDEO_LOADING; } int count = sharedMediaData[0].getStartOffset() + sharedMediaData[0].getMessages().size(); if (position - sharedMediaData[0].getStartOffset() >= 0 && position < count) { - return 0; + return VIEW_TYPE_PHOTOVIDEO; } - return 0; + return VIEW_TYPE_PHOTOVIDEO; } @Override @@ -6636,7 +7064,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() != searchResult.size() + globalSearch.size(); + return 0 != searchResult.size() + globalSearch.size(); } @Override @@ -6701,6 +7129,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (currentType == 1) { + if (!(holder.itemView instanceof SharedDocumentCell)) return; SharedDocumentCell sharedDocumentCell = (SharedDocumentCell) holder.itemView; MessageObject messageObject = getItem(position); sharedDocumentCell.setDocument(messageObject, position != getItemCount() - 1); @@ -6710,6 +7139,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter sharedDocumentCell.setChecked(false, !scrolling); } } else if (currentType == 3) { + if (!(holder.itemView instanceof SharedLinkCell)) return; SharedLinkCell sharedLinkCell = (SharedLinkCell) holder.itemView; MessageObject messageObject = getItem(position); sharedLinkCell.setLink(messageObject, position != getItemCount() - 1); @@ -6719,6 +7149,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter sharedLinkCell.setChecked(false, !scrolling); } } else if (currentType == 4) { + if (!(holder.itemView instanceof SharedAudioCell)) return; SharedAudioCell sharedAudioCell = (SharedAudioCell) holder.itemView; MessageObject messageObject = getItem(position); sharedAudioCell.setMessageObject(messageObject, position != getItemCount() - 1); @@ -6732,7 +7163,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int i) { - return 0; + return VIEW_TYPE_SEARCH_DOCUMENT; } } @@ -6768,14 +7199,14 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int position) { if (sharedMediaData[5].messages.size() == 0 && !sharedMediaData[5].loading) { - return 1; + return VIEW_TYPE_GIF_LOADING; } - return 0; + return VIEW_TYPE_GIF; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == 1) { + if (viewType == VIEW_TYPE_GIF_LOADING) { View emptyStubView = createEmptyStubView(mContext, 5, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); @@ -6787,10 +7218,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() != 1) { + if (holder.getItemViewType() == VIEW_TYPE_GIF) { MessageObject messageObject = sharedMediaData[5].messages.get(position); TLRPC.Document document = messageObject.getDocument(); if (document != null) { + if (!(holder.itemView instanceof ContextLinkCell)) return; ContextLinkCell cell = (ContextLinkCell) holder.itemView; cell.setGif(document, messageObject, messageObject.messageOwner.date, false); if (isActionModeShowed) { @@ -6818,6 +7250,405 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } + private class SavedDialogsAdapter extends RecyclerListView.SelectionAdapter { + private final Context mContext; + private final SavedMessagesController controller; + + private final ArrayList oldDialogs = new ArrayList<>(); + private final ArrayList dialogs = new ArrayList<>(); + private boolean orderChanged; + private Runnable notifyOrderUpdate = () -> { + if (!orderChanged) { + return; + } + orderChanged = false; + ArrayList pinnedOrder = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + if (dialogs.get(i).pinned) { + pinnedOrder.add(dialogs.get(i).dialogId); + } + } + profileActivity.getMessagesController().getSavedMessagesController().updatePinnedOrder(pinnedOrder); + }; + + public final RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool(); + public RecyclerListView attachedToRecyclerView; + public final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + + @Override + public boolean isLongPressDragEnabled() { + return true; + } + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + if (!isActionModeShowed) { + return makeMovementFlags(0, 0); + } + SavedMessagesController.SavedDialog d = getDialog(viewHolder); + if (d != null && d.pinned) { + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + return makeMovementFlags(0, 0); + } + + private SavedMessagesController.SavedDialog getDialog(RecyclerView.ViewHolder holder) { + if (holder == null) { + return null; + } + int position = holder.getAdapterPosition(); + if (position < 0 || position >= dialogs.size()) { + return null; + } + return dialogs.get(position); + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (viewHolder != null && attachedToRecyclerView != null) { + attachedToRecyclerView.hideSelector(false); + } + if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) { + AndroidUtilities.cancelRunOnUIThread(notifyOrderUpdate); + AndroidUtilities.runOnUIThread(notifyOrderUpdate, 300); + } + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder sourceHolder, @NonNull RecyclerView.ViewHolder targetHolder) { + if (!isActionModeShowed) { + return false; + } + SavedMessagesController.SavedDialog source = getDialog(sourceHolder); + SavedMessagesController.SavedDialog target = getDialog(targetHolder); + if (source != null && target != null && source.pinned && target.pinned) { + int fromPosition = sourceHolder.getAdapterPosition(); + int toPosition = targetHolder.getAdapterPosition(); + dialogs.remove(fromPosition); + dialogs.add(toPosition, source); + notifyItemMoved(fromPosition, toPosition); + orderChanged = true; + return true; + } + return false; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + viewHolder.itemView.setPressed(false); + } + }); + + public SavedDialogsAdapter(Context context) { + mContext = context; + controller = profileActivity.getMessagesController().getSavedMessagesController(); + if (includeSavedDialogs()) { + controller.loadDialogs(); + } + setHasStableIds(true); + update(false); + } + + @Override + public long getItemId(int position) { + if (position < 0 || position >= dialogs.size()) return position; + return dialogs.get(position).dialogId; + } + + public void update(boolean notify) { + oldDialogs.clear(); + oldDialogs.addAll(dialogs); + dialogs.clear(); + dialogs.addAll(controller.allDialogs); + if (notify) { + notifyDataSetChanged(); + } + } + + public final HashSet selectedDialogs = new HashSet<>(); + + public void select(View view) { + if (!(view instanceof DialogCell)) return; + DialogCell dialogCell = (DialogCell) view; + long dialogId = dialogCell.getDialogId(); + SavedMessagesController.SavedDialog dialog = null; + for (int i = 0; i < dialogs.size(); ++i) { + if (dialogs.get(i).dialogId == dialogId) { + dialog = dialogs.get(i); + break; + } + } + if (dialog == null) return; + + if (selectedDialogs.contains(dialog.dialogId)) { + selectedDialogs.remove(dialog.dialogId); + if (selectedDialogs.size() <= 0 && isActionModeShowed) { + showActionMode(false); + } + } else { + selectedDialogs.add(dialog.dialogId); + if (selectedDialogs.size() > 0 && !isActionModeShowed) { + showActionMode(true); + if (gotoItem != null) { + gotoItem.setVisibility(View.GONE); + } + if (forwardItem != null) { + forwardItem.setVisibility(View.GONE); + } + } + } + selectedMessagesCountTextView.setNumber(selectedDialogs.size(), true); + boolean allSelectedPinned = selectedDialogs.size() > 0; + for (long did : selectedDialogs) { + for (int i = 0; i < dialogs.size(); ++i) { + SavedMessagesController.SavedDialog d = dialogs.get(i); + if (d.dialogId == did) { + if (!d.pinned) { + allSelectedPinned = false; + } + break; + } + } + if (!allSelectedPinned) break; + } + if (pinItem != null) { + pinItem.setVisibility(allSelectedPinned ? View.GONE : View.VISIBLE); + } + if (unpinItem != null) { + unpinItem.setVisibility(allSelectedPinned ? View.VISIBLE : View.GONE); + } + if (view instanceof DialogCell) { + ((DialogCell) view).setChecked(selectedDialogs.contains(dialog.dialogId), true); + } + } + + public void unselectAll() { + selectedDialogs.clear(); + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + DialogCell cell = new DialogCell(null, mContext, false, true) { + + @Override + public boolean isForumCell() { + return false; + } + @Override + public boolean getIsPinned() { + if (attachedToRecyclerView != null && attachedToRecyclerView.getAdapter() == SavedDialogsAdapter.this) { + int position = attachedToRecyclerView.getChildAdapterPosition(this); + if (position >= 0 && position < dialogs.size()) { + return dialogs.get(position).pinned; + } + } + return false; + } + }; + cell.setDialogCellDelegate(SharedMediaLayout.this); + cell.isSavedDialog = true; + cell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + return new RecyclerListView.Holder(cell); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (!(holder.itemView instanceof DialogCell)) return; + DialogCell cell = (DialogCell) holder.itemView; + SavedMessagesController.SavedDialog d = dialogs.get(position); + cell.setDialog(d.dialogId, d.message, d.getDate(), false, false); + cell.setChecked(selectedDialogs.contains(d.dialogId), false); + cell.useSeparator = position + 1 < getItemCount(); + } + + @Override + public int getItemViewType(int position) { + return VIEW_TYPE_SAVED_DIALOG; + } + + @Override + public int getItemCount() { + return dialogs.size(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + } + + private class SavedMessagesSearchAdapter extends RecyclerListView.SelectionAdapter { + private final Context mContext; + private final int currentAccount; + public final ArrayList dialogs = new ArrayList<>(); + public final ArrayList messages = new ArrayList<>(); + public SavedMessagesSearchAdapter(Context context) { + mContext = context; + currentAccount = profileActivity.getCurrentAccount(); + setHasStableIds(true); + } + + private boolean loading; + private boolean endReached = false; + private int oldItemCounts = 0; + private int count = 0; + + private String lastQuery; + private int reqId = -1; + public void search(String query) { + if (TextUtils.equals(query, lastQuery)) { + return; + } + lastQuery = query; + if (reqId >= 0) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + reqId = -1; + } + + messages.clear(); + count = 0; + endReached = false; + loading = true; + + dialogs.clear(); + dialogs.addAll(MessagesController.getInstance(currentAccount).getSavedMessagesController().searchDialogs(query)); + for (int a = 0; a < mediaPages.length; a++) { + if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + mediaPages[a].emptyView.showProgress(true, true); + } + } + notifyDataSetChanged(); + + AndroidUtilities.cancelRunOnUIThread(searchRunnable); + AndroidUtilities.runOnUIThread(searchRunnable, 600); + } + + public void loadMore() { + if (endReached || loading) return; + sendRequest(); + } + + private Runnable searchRunnable = this::sendRequest; + private void sendRequest() { + if (TextUtils.isEmpty(lastQuery)) { + loading = false; + return; + } + TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(UserConfig.getInstance(currentAccount).getClientUserId()); + req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); + req.q = lastQuery; + if (messages.size() > 0) { + MessageObject lastMessage = messages.get(messages.size() - 1); + req.offset_id = lastMessage.getId(); + } + req.limit = 10; + endReached = false; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (!(res instanceof TLRPC.messages_Messages)) { + return; + } + TLRPC.messages_Messages r = (TLRPC.messages_Messages) res; + MessagesController.getInstance(currentAccount).putUsers(r.users, false); + MessagesController.getInstance(currentAccount).putChats(r.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(r.users, r.chats, true, true); + for (int i = 0; i < r.messages.size(); ++i) { + TLRPC.Message msg = r.messages.get(i); + messages.add(new MessageObject(currentAccount, msg, false, false)); + } + if (r instanceof TLRPC.TL_messages_messagesSlice) { + count = r.count; + endReached = messages.size() >= count; + } else if (r instanceof TLRPC.TL_messages_messages) { + count = messages.size(); + endReached = true; + } + + for (int a = 0; a < mediaPages.length; a++) { + if (mediaPages[a].selectedType == TAB_SAVED_DIALOGS) { + if (count == 0 && dialogs.isEmpty()) { + mediaPages[a].emptyView.title.setText(LocaleController.formatString("NoResultFoundFor", R.string.NoResultFoundFor, lastQuery)); + mediaPages[a].emptyView.showProgress(false, true); + } + } + } + oldItemCounts = count; + reqId = -1; + + notifyDataSetChanged(); + loading = false; + })); + } + + @Override + public long getItemId(int position) { + if (position < 0) return position; + if (position < dialogs.size()) { + return Objects.hash(1, dialogs.get(position).dialogId); + } + position -= dialogs.size(); + if (position < messages.size()) { + return Objects.hash(2, messages.get(position).getSavedDialogId(), messages.get(position).getId()); + } + return position; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + DialogCell cell = new DialogCell(null, mContext, false, true) { + @Override + public boolean isForumCell() { + return false; + } + }; + cell.setDialogCellDelegate(SharedMediaLayout.this); + cell.isSavedDialog = true; + cell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + return new RecyclerListView.Holder(cell); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position < 0) return; + if (!(holder.itemView instanceof DialogCell)) return; + DialogCell cell = (DialogCell) holder.itemView; + cell.useSeparator = position + 1 < getItemCount(); + if (position < dialogs.size()) { + final SavedMessagesController.SavedDialog d = dialogs.get(position); + cell.setDialog(d.dialogId, d.message, d.getDate(), false, false); + } else { + position -= dialogs.size(); + if (position < messages.size()) { + MessageObject msg = messages.get(position); + cell.setDialog(msg.getSavedDialogId(), msg, msg.messageOwner.date, false, false); + } + } + } + + @Override + public int getItemViewType(int position) { + return VIEW_TYPE_SEARCH_SAVED_DIALOG; + } + + @Override + public int getItemCount() { + return dialogs.size() + messages.size(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + } + private class ChannelRecommendationsAdapter extends RecyclerListView.SelectionAdapter { private final Context mContext; @@ -6866,14 +7697,14 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; - if (viewType == 1) { + if (viewType == VIEW_TYPE_SIMILAR_CHANNEL_BLOCK) { MoreRecommendationsCell cell = new MoreRecommendationsCell(profileActivity == null ? UserConfig.selectedAccount : profileActivity.getCurrentAccount(), mContext, resourcesProvider, () -> { if (profileActivity != null) { profileActivity.presentFragment(new PremiumPreviewFragment("similar_channels")); } }); view = cell; - } else { // 0 + } else { view = new ProfileSearchCell(mContext, resourcesProvider); } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); @@ -6929,9 +7760,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ProfileSearchCell cell = null; - if (holder.getItemViewType() == 0) { + if (holder.getItemViewType() == VIEW_TYPE_SIMILAR_CHANNEL) { + if (!(holder.itemView instanceof ProfileSearchCell)) return; cell = (ProfileSearchCell) holder.itemView; - } else if (holder.getItemViewType() == 1) { + } else if (holder.getItemViewType() == VIEW_TYPE_SIMILAR_CHANNEL_BLOCK) { + if (!(holder.itemView instanceof MoreRecommendationsCell)) return; cell = ((MoreRecommendationsCell) holder.itemView).channelCell; } if (cell != null) { @@ -6944,9 +7777,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int position) { if (more > 0 && position == getItemCount() - 1) { - return 1; + return VIEW_TYPE_SIMILAR_CHANNEL_BLOCK; } - return 0; + return VIEW_TYPE_SIMILAR_CHANNEL; } } @@ -7100,14 +7933,14 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_GROUP: view = new ProfileSearchCell(mContext, resourcesProvider); break; - case 2: + case VIEW_TYPE_GROUP_EMPTY: View emptyStubView = createEmptyStubView(mContext, 6, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); - case 1: + case VIEW_TYPE_GROUP_LOADING: default: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext, resourcesProvider); flickerLoadingView.setIsSingleCell(true); @@ -7122,7 +7955,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { + if (holder.getItemViewType() == VIEW_TYPE_GROUP) { + if (!(holder.itemView instanceof ProfileSearchCell)) return; ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; TLRPC.Chat chat = chats.get(position); cell.setData(chat, null, null, null, false, false); @@ -7133,12 +7967,12 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int i) { if (chats.isEmpty() && !loading) { - return 2; + return VIEW_TYPE_GROUP_EMPTY; } if (i < chats.size()) { - return 0; + return VIEW_TYPE_GROUP; } else { - return 1; + return VIEW_TYPE_GROUP_LOADING; } } } @@ -7317,7 +8151,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return; } int viewType = holder.getItemViewType(); - if (viewType == 0) { + if (viewType == VIEW_TYPE_STORY) { + if (!(holder.itemView instanceof SharedPhotoVideoCell2)) return; SharedPhotoVideoCell2 cell = (SharedPhotoVideoCell2) holder.itemView; cell.isStory = true; position -= getTopOffset(); @@ -7348,7 +8183,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int i) { - return 0; + return VIEW_TYPE_STORY; } @Override @@ -7398,7 +8233,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == 1) { + if (viewType == VIEW_TYPE_GROUPUSER_EMPTY) { View emptyStubView = createEmptyStubView(mContext, 7, dialog_id, resourcesProvider); emptyStubView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return new RecyclerListView.Holder(emptyStubView); @@ -7452,9 +8287,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int i) { if (chatInfo != null && chatInfo.participants.participants.isEmpty()) { - return 1; + return VIEW_TYPE_GROUPUSER_EMPTY; } - return 0; + return VIEW_TYPE_GROUPUSER; } } @@ -7634,7 +8469,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() != 1; + return true; } @Override @@ -7712,7 +8547,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter name.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_windowBackgroundWhiteBlueText4)), idx, idx + nameSearch.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } - + if (!(holder.itemView instanceof ManageChatUserCell)) return; ManageChatUserCell userCell = (ManageChatUserCell) holder.itemView; userCell.setTag(position); userCell.setData(user, name, null, false); @@ -7727,7 +8562,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter @Override public int getItemViewType(int i) { - return 0; + return VIEW_TYPE_SEARCH_GROUPUSER; } } 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 a49fb323f..2899f1788 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java @@ -150,6 +150,26 @@ public class StaticLayoutEx { .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE); layout = builder.build(); + + boolean realWidthLarger = false; + for (int l = 0; l < layout.getLineCount(); ++l) { + if (layout.getLineRight(l) > outerWidth) { + realWidthLarger = true; + break; + } + } + if (realWidthLarger) { + builder = StaticLayout.Builder.obtain(source, 0, source.length(), paint, outerWidth) + .setAlignment(align) + .setLineSpacing(spacingAdd, spacingMult) + .setIncludePad(includePad) + .setEllipsize(null) + .setEllipsizedWidth(ellipsisWidth) + .setMaxLines(maxLines) + .setBreakStrategy(StaticLayout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE); + layout = builder.build(); + } } else { layout = new StaticLayout(source, paint, outerWidth, align, spacingMult, spacingAdd, includePad); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java index 1db8830bd..c3c7917b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java @@ -16,7 +16,11 @@ public class StatusBadgeComponent { private Drawable verifiedDrawable; public StatusBadgeComponent(View parentView) { - statusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(parentView, AndroidUtilities.dp(18)); + this(parentView, 18); + } + + public StatusBadgeComponent(View parentView, int sizeDp) { + statusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(parentView, AndroidUtilities.dp(sizeDp)); } public Drawable updateDrawable(TLObject object, int colorFilter, boolean animated) { @@ -34,13 +38,13 @@ public class StatusBadgeComponent { statusDrawable.setColor(null); } else if (chat != null && DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { statusDrawable.set(DialogObject.getEmojiStatusDocumentId(chat.emoji_status), animated); - statusDrawable.setColor(null); + statusDrawable.setColor(colorFilter); } else if (user != null && user.verified) { statusDrawable.set(verifiedDrawable = (verifiedDrawable == null ? new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable) : verifiedDrawable), animated); statusDrawable.setColor(null); } else if (user != null && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) { statusDrawable.set(DialogObject.getEmojiStatusDocumentId(user.emoji_status), animated); - statusDrawable.setColor(null); + statusDrawable.setColor(colorFilter); } else if (user != null && user.premium) { statusDrawable.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); statusDrawable.setColor(colorFilter); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java index 929773470..a9a9afa9c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java @@ -82,6 +82,9 @@ public class ThanosEffect extends TextureView { public final Bitmap bitmap; public final Matrix matrix; + + public float durationMultiplier = 1f; + public ToSet(View view, Runnable callback) { this.view = view; this.views = null; @@ -129,7 +132,7 @@ public class ThanosEffect extends TextureView { } else if (toSetObj.views != null) { drawThread.animateGroup(toSetObj.views, toSetObj.doneCallback); } else { - drawThread.animate(toSetObj.view, toSetObj.doneCallback); + drawThread.animate(toSetObj.view, toSetObj.durationMultiplier, toSetObj.doneCallback); } } toSet.clear(); @@ -165,7 +168,9 @@ public class ThanosEffect extends TextureView { }); } + public boolean destroyed; private void destroy() { + destroyed = true; if (whenDone != null) { Runnable runnable = whenDone; whenDone = null; @@ -173,6 +178,19 @@ public class ThanosEffect extends TextureView { } } + public void kill() { + destroyed = true; + for (ToSet set : toSet) { + if (set.doneCallback != null) { + set.doneCallback.run(); + } + } + toSet.clear(); + if (drawThread != null) { + drawThread.kill(); + } + } + public void scroll(int dx, int dy) { if (drawThread != null && drawThread.running) { // post(() -> drawThread.scroll(dx, dy)); @@ -190,13 +208,42 @@ public class ThanosEffect extends TextureView { public void animate(View view, Runnable whenDone) { if (drawThread != null) { - drawThread.animate(view, whenDone); + drawThread.animate(view, 1f, whenDone); Choreographer.getInstance().postFrameCallback(frameCallback); } else { toSet.add(new ToSet(view, whenDone)); } } + public void animate(View view, float durationMultipier, Runnable whenDone) { + if (drawThread != null) { + drawThread.animate(view, durationMultipier, whenDone); + Choreographer.getInstance().postFrameCallback(frameCallback); + } else { + ToSet set = new ToSet(view, whenDone); + set.durationMultiplier = durationMultipier; + toSet.add(set); + } + } + + public void cancel(View view) { + boolean found = false; + for (int i = 0; i < toSet.size(); ++i) { + ToSet set = toSet.get(i); + if (set.view == view) { + if (set.doneCallback != null) { + set.doneCallback.run(); + } + toSet.remove(i); + i--; + found = true; + } + } + if (!found) { + drawThread.cancel(view); + } + } + public void animate(Matrix matrix, Bitmap bitmap, Runnable whenStarted, Runnable whenDone) { if (drawThread != null) { drawThread.animate(matrix, bitmap, whenStarted, whenDone); @@ -208,7 +255,7 @@ public class ThanosEffect extends TextureView { private static class DrawingThread extends DispatchQueue { - private boolean alive = true; + private volatile boolean alive = true; private final SurfaceTexture surfaceTexture; private final Runnable invalidate; private Runnable destroy; @@ -231,6 +278,7 @@ public class ThanosEffect extends TextureView { public final static int DO_KILL = 2; public final static int DO_ADD_ANIMATION = 3; public final static int DO_SCROLL = 4; + public final static int DO_CANCEL_ANIMATION = 5; @Override public void handleMessage(Message inputMessage) { @@ -252,6 +300,10 @@ public class ThanosEffect extends TextureView { addAnimationInternal((Animation) inputMessage.obj); return; } + case DO_CANCEL_ANIMATION: { + cancelAnimationInternal((View) inputMessage.obj); + return; + } case DO_SCROLL: { for (int i = 0; i < pendingAnimations.size(); ++i) { Animation anim = pendingAnimations.get(i); @@ -274,7 +326,7 @@ public class ThanosEffect extends TextureView { if (animation.startCallback != null) { AndroidUtilities.runOnUIThread(animation.startCallback); } - animation.done(false); + animation.done(true); } toAddAnimations.clear(); AndroidUtilities.runOnUIThread(() -> { @@ -294,21 +346,21 @@ public class ThanosEffect extends TextureView { public void requestDraw() { Handler handler = getHandler(); - if (handler != null) { + if (handler != null && alive) { handler.sendMessage(handler.obtainMessage(DO_DRAW)); } } public void resize(int width, int height) { Handler handler = getHandler(); - if (handler != null) { + if (handler != null && alive) { handler.sendMessage(handler.obtainMessage(DO_RESIZE, width, height)); } } public void scroll(int dx, int dy) { Handler handler = getHandler(); - if (handler != null) { + if (handler != null && alive) { handler.sendMessage(handler.obtainMessage(DO_SCROLL, dx, dy)); } } @@ -321,11 +373,16 @@ public class ThanosEffect extends TextureView { GLES31.glUniform2f(sizeHandle, width, height); } + private boolean killed; public void kill() { - Handler handler = getHandler(); - if (handler != null) { - handler.sendMessage(handler.obtainMessage(DO_KILL)); - } + if (killed) return; + try { + Handler handler = getHandler(); + if (handler != null) { + handler.sendMessage(handler.obtainMessage(DO_KILL)); + } + killed = true; + } catch (Exception e) {} } private void killInternal() { @@ -333,8 +390,9 @@ public class ThanosEffect extends TextureView { alive = false; for (int i = 0; i < pendingAnimations.size(); ++i) { Animation animation = pendingAnimations.get(i); - animation.done(false); + animation.done(true); } + pendingAnimations.clear(); if (surfaceTexture != null) { surfaceTexture.release(); } @@ -537,7 +595,7 @@ public class ThanosEffect extends TextureView { } toRunStartCallback.clear(); for (int i = 0; i < pendingAnimations.size(); ++i) { - pendingAnimations.get(i).done(false); + pendingAnimations.get(i).done(true); } pendingAnimations.clear(); AndroidUtilities.runOnUIThread(() -> { @@ -573,9 +631,9 @@ public class ThanosEffect extends TextureView { handler.sendMessage(handler.obtainMessage(DO_ADD_ANIMATION, animation)); } } - public void animate(View view, Runnable whenDone) { + public void animate(View view, float durationMultipier, Runnable whenDone) { if (!alive) return; - Animation animation = new Animation(view, whenDone); + Animation animation = new Animation(view, durationMultipier, whenDone); Handler handler = getHandler(); running = true; if (handler == null) { @@ -584,6 +642,35 @@ public class ThanosEffect extends TextureView { handler.sendMessage(handler.obtainMessage(DO_ADD_ANIMATION, animation)); } } + + public void cancel(View view) { + if (!alive) return; + Handler handler = getHandler(); + if (handler == null) { + for (int i = 0; i < toAddAnimations.size(); ++i) { + Animation animation = toAddAnimations.get(i); + if (animation.views.contains(view)) { + if (animation.doneCallback != null) { + animation.doneCallback.run(); + } + toAddAnimations.remove(i); + i--; + } + } + } else { + for (int i = 0; i < pendingAnimations.size(); ++i) { + Animation a = pendingAnimations.get(i); + if (a.views.contains(view)) { + if (a.doneCallback != null) { + a.doneCallback.run(); + } + break; + } + } + handler.sendMessage(handler.obtainMessage(DO_CANCEL_ANIMATION, view)); + } + } + public void animate(Matrix matrix, Bitmap bitmap, Runnable whenStart, Runnable whenDone) { if (!alive) return; Animation animation = new Animation(matrix, bitmap, whenStart, whenDone); @@ -596,6 +683,17 @@ public class ThanosEffect extends TextureView { } } + private void cancelAnimationInternal(View view) { + for (int i = 0; i < pendingAnimations.size(); ++i) { + Animation a = pendingAnimations.get(i); + if (a.views.contains(view)) { + a.done(true); + pendingAnimations.remove(i); + i--; + } + } + } + private void addAnimationInternal(Animation animation) { GLES31.glGenTextures(1, animation.texture, 0); GLES20.glBindTexture(GL10.GL_TEXTURE_2D, animation.texture[0]); @@ -629,7 +727,7 @@ public class ThanosEffect extends TextureView { public float top = 0; public final float density = AndroidUtilities.density; public float longevity = 1.5f; - public float timeScale = 1.12f; + public float timeScale = 1.15f; public boolean invalidateMatrix = true; public boolean customMatrix = false; public final float[] glMatrixValues = new float[9]; @@ -952,7 +1050,7 @@ public class ThanosEffect extends TextureView { } } - public Animation(View view, Runnable whenDone) { + public Animation(View view, float durationMultipier, Runnable whenDone) { this.views.add(view); viewWidth = view.getWidth(); viewHeight = view.getHeight(); @@ -972,6 +1070,8 @@ public class ThanosEffect extends TextureView { } } }; + longevity *= durationMultipier; + timeScale /= 1f + (durationMultipier - 1f) / 3f; // longevity = 1.5f * Utilities.clamp(viewWidth / (float) AndroidUtilities.displaySize.x, .6f, 0.2f); bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888); @@ -1087,7 +1187,7 @@ public class ThanosEffect extends TextureView { return time > longevity + .9f; } - public void done(boolean success) { + public void done(boolean runCallback) { try { GLES31.glDeleteBuffers(2, buffer, 0); } catch (Exception e) { FileLog.e(e); }; if (drawProgram != 0) { try { GLES31.glDeleteProgram(drawProgram); } catch (Exception e) { FileLog.e(e); }; @@ -1095,7 +1195,7 @@ public class ThanosEffect extends TextureView { } try { GLES31.glDeleteTextures(1, texture, 0); } catch (Exception e) { FileLog.e(e); }; - if (doneCallback != null) { + if (runCallback && doneCallback != null) { AndroidUtilities.runOnUIThread(() -> { if (doneCallback != null) { doneCallback.run(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerParticles.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerParticles.java index a4fdf4f25..92aeee78c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerParticles.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TimerParticles.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.lerp; + import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; @@ -14,6 +16,8 @@ public class TimerParticles { private long lastAnimationTime; + public boolean big; + private static class Particle { float x; float y; @@ -28,8 +32,15 @@ public class TimerParticles { private ArrayList particles = new ArrayList<>(); private ArrayList freeParticles = new ArrayList<>(); + private final int particlesCount; + public TimerParticles() { - for (int a = 0; a < 40; a++) { + this(40); + } + + public TimerParticles(int particlesCount) { + this.particlesCount = particlesCount; + for (int a = 0; a < particlesCount; a++) { freeParticles.add(new Particle()); } } @@ -39,7 +50,7 @@ public class TimerParticles { for (int a = 0; a < count; a++) { Particle particle = particles.get(a); if (particle.currentTime >= particle.lifeTime) { - if (freeParticles.size() < 40) { + if (freeParticles.size() < particlesCount) { freeParticles.add(particle); } particles.remove(a); @@ -48,12 +59,15 @@ public class TimerParticles { continue; } particle.alpha = 1.0f - AndroidUtilities.decelerateInterpolator.getInterpolation(particle.currentTime / particle.lifeTime); - particle.x += particle.vx * particle.velocity * dt / 500.0f; - particle.y += particle.vy * particle.velocity * dt / 500.0f; + particle.x += particle.vx * particle.velocity * dt / 200.0f; + particle.y += particle.vy * particle.velocity * dt / 200.0f; particle.currentTime += dt; } } + private boolean hasLast; + private float lastCx, lastCy; + public void draw(Canvas canvas, Paint particlePaint, RectF rect, float radProgress, float alpha) { int count = particles.size(); for (int a = 0; a < count; a++) { @@ -67,7 +81,8 @@ public class TimerParticles { float rad = rect.width() / 2; float cx = (float) (-vy * rad + rect.centerX()); float cy = (float) (vx * rad + rect.centerY()); - for (int a = 0; a < 1; a++) { + final int subcount = Utilities.clamp(freeParticles.size() / 12, 3, 1); + for (int a = 0; a < subcount; a++) { Particle newParticle; if (!freeParticles.isEmpty()) { newParticle = freeParticles.get(0); @@ -75,8 +90,14 @@ public class TimerParticles { } else { newParticle = new Particle(); } - newParticle.x = cx; - newParticle.y = cy; + + if (big && hasLast) { + newParticle.x = lerp(lastCx, cx, (a + 1) / (float) subcount); + newParticle.y = lerp(lastCy, cy, (a + 1) / (float) subcount); + } else { + newParticle.x = cx; + newParticle.y = cy; + } double angle = (Math.PI / 180.0) * (Utilities.random.nextInt(140) - 70); if (angle < 0) { @@ -88,10 +109,18 @@ public class TimerParticles { newParticle.alpha = 1.0f; newParticle.currentTime = 0; - newParticle.lifeTime = 400 + Utilities.random.nextInt(100); - newParticle.velocity = 20.0f + Utilities.random.nextFloat() * 4.0f; + if (big) { + newParticle.lifeTime = 600 + Utilities.random.nextInt(200); + newParticle.velocity = 30.0f + Utilities.random.nextFloat() * 20.0f; + } else { + newParticle.lifeTime = 400 + Utilities.random.nextInt(100); + newParticle.velocity = 20.0f + Utilities.random.nextFloat() * 4.0f; + } particles.add(newParticle); } + hasLast = true; + lastCx = cx; + lastCy = cy; long newTime = SystemClock.elapsedRealtime(); long dt = Math.min(20, (newTime - lastAnimationTime)); 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 edccc1ab0..dc37db13d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -48,6 +48,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; +import org.telegram.messenger.SavedMessagesController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; @@ -55,7 +56,9 @@ import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Premium.boosts.BoostRepository; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.PaymentFormActivity; import java.util.ArrayList; @@ -64,7 +67,7 @@ import java.util.ArrayList; @Deprecated // use Bulletin instead public class UndoView extends FrameLayout { - private TextView infoTextView; + private LinkSpanDrawable.LinksTextView infoTextView; private TextView subinfoTextView; private TextView undoTextView; private ImageView undoImageView; @@ -239,7 +242,7 @@ public class UndoView extends FrameLayout { parentFragment = parent; fromTop = top; - infoTextView = new TextView(context); + infoTextView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); infoTextView.setTextColor(getThemedColor(Theme.key_undo_infoColor)); infoTextView.setLinkTextColor(getThemedColor(Theme.key_undo_cancelColor)); @@ -1037,9 +1040,9 @@ public class UndoView extends FrameLayout { if (infoObject2 == null || infoObject2 instanceof TLRPC.TL_forumTopic) { if (did == UserConfig.getInstance(currentAccount).clientUserId) { if (count == 1) { - infoTextView.setText(AndroidUtilities.replaceTags(LocaleController.getString("FwdMessageToSavedMessages", R.string.FwdMessageToSavedMessages))); + infoTextView.setText(AndroidUtilities.replaceSingleTag(LocaleController.getString("FwdMessageToSavedMessages", R.string.FwdMessageToSavedMessages), SavedMessagesController::openSavedMessages)); } else { - infoTextView.setText(AndroidUtilities.replaceTags(LocaleController.getString("FwdMessagesToSavedMessages", R.string.FwdMessagesToSavedMessages))); + infoTextView.setText(AndroidUtilities.replaceSingleTag(LocaleController.getString("FwdMessagesToSavedMessages", R.string.FwdMessagesToSavedMessages), SavedMessagesController::openSavedMessages)); } leftImageView.setAnimation(R.raw.saved_messages, 30, 30); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelineView.java index 268b05169..874568531 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoTimelineView.java @@ -250,7 +250,7 @@ public class VideoTimelineView extends View { } public void setVideoPath(String path) { - destroy(); + destroy(false); mediaMetadataRetriever = new MediaMetadataRetriever(); progressLeft = 0.0f; progressRight = 1.0f; @@ -347,6 +347,10 @@ public class VideoTimelineView extends View { } public void destroy() { + destroy(true); + } + + public void destroy(boolean recycle) { synchronized (sync) { try { if (mediaMetadataRetriever != null) { @@ -357,18 +361,20 @@ public class VideoTimelineView extends View { FileLog.e(e); } } - if (!keyframes.isEmpty()) { - for (int a = 0; a < keyframes.size(); a++) { - Bitmap bitmap = keyframes.get(a); - if (bitmap != null) { - bitmap.recycle(); + if (recycle) { + if (!keyframes.isEmpty()) { + for (int a = 0; a < keyframes.size(); a++) { + Bitmap bitmap = keyframes.get(a); + if (bitmap != null) { + bitmap.recycle(); + } } - } - } else { - for (int a = 0; a < frames.size(); a++) { - Bitmap bitmap = frames.get(a); - if (bitmap != null) { - bitmap.recycle(); + } else { + for (int a = 0; a < frames.size(); a++) { + Bitmap bitmap = frames.get(a); + if (bitmap != null) { + bitmap.recycle(); + } } } } @@ -436,7 +442,7 @@ public class VideoTimelineView extends View { int offset = 0; for (int a = 0; a < frames.size(); a++) { Bitmap bitmap = frames.get(a); - if (bitmap != null) { + if (bitmap != null && !bitmap.isRecycled()) { int x = offset * (isRoundFrames ? frameWidth / 2 : frameWidth); if (isRoundFrames) { rect2.set(x, topOffset, x + AndroidUtilities.dp(28), topOffset + AndroidUtilities.dp(32)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java index 261be2988..84f96430f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java @@ -185,10 +185,6 @@ public class SpoilerEffect2 { if (index == null) { index = 0; } - if (w > ow || h > oh) { - final float scale = Math.max(w / (float) ow, h / (float) oh); - canvas.scale(scale, scale); - } if ((index % 4) == 1) { canvas.rotate(180, ow / 2f, oh / 2f); } @@ -198,6 +194,12 @@ public class SpoilerEffect2 { if ((index % 4) == 3) { canvas.scale(1, -1, ow / 2f, oh / 2f); } + canvas.translate(w / 2f, h / 2f); + if (w > ow || h > oh) { + final float scale = Math.max(w / (float) ow, h / (float) oh); + canvas.scale(scale, scale); + } + canvas.translate(-w / 2f, -h / 2f); if (toBitmap) { Bitmap bitmap = textureView.getBitmap(); if (bitmap != null) { @@ -494,15 +496,6 @@ public class SpoilerEffect2 { GLES31.glUniform1f(resetHandle, reset ? 1 : 0); GLES31.glUniform1f(radiusHandle, radius); GLES31.glUniform1f(seedHandle, Utilities.fastRandom.nextInt(256) / 256f); - - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "noiseScale"), 6); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "noiseSpeed"), 0.6f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "noiseMovement"), 4f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "longevity"), 1.4f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "dampingMult"), .9999f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "maxVelocity"), 6.f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "velocityMult"), 1.0f); - GLES31.glUniform1f(GLES31.glGetUniformLocation(drawProgram, "forceMult"), 0.6f); } private float t; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java index 3ededd5cd..5e23c511a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java @@ -156,7 +156,7 @@ public class AcceptDeclineView extends View { startX = event.getX(); startY = event.getY(); if (leftAnimator == null && declineRect.contains((int) event.getX(), (int) event.getY())) { - rippleDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(52), 0, retryMod ? Color.WHITE : 0xFFFF3846); + rippleDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(52), 0, retryMod ? Theme.getColor(Theme.key_listSelector) : 0xFFFF3846); captured = true; leftDrag = true; setPressed(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java index 4b177f694..2ee7e8109 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java @@ -25,6 +25,7 @@ public class HideEmojiTextView extends TextView { this.backgroundProvider = backgroundProvider; backgroundProvider.attach(this); setText(LocaleController.getString("VoipHideEmoji", R.string.VoipHideEmoji)); + setContentDescription(LocaleController.getString("VoipHideEmoji", R.string.VoipHideEmoji)); setTextColor(Color.WHITE); setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); setPadding(AndroidUtilities.dp(14), AndroidUtilities.dp(4), AndroidUtilities.dp(14), AndroidUtilities.dp(4)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/PrivateVideoPreviewDialogNew.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/PrivateVideoPreviewDialogNew.java index 02f6189fd..007fd3614 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/PrivateVideoPreviewDialogNew.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/PrivateVideoPreviewDialogNew.java @@ -238,6 +238,7 @@ public abstract class PrivateVideoPreviewDialogNew extends FrameLayout implement positiveButton.setGravity(Gravity.CENTER); positiveButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); positiveButton.getPaint().setTextAlign(Paint.Align.CENTER); + positiveButton.setContentDescription(LocaleController.getString("VoipShareVideo", R.string.VoipShareVideo)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { positiveButton.setForeground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_nameText), (int) (255 * 0.3f)))); @@ -302,6 +303,7 @@ public abstract class PrivateVideoPreviewDialogNew extends FrameLayout implement text = LocaleController.getString("VoipBackCamera", R.string.VoipBackCamera); } titles[i] = new VoIpBitmapTextView(context, text); + titles[i].setContentDescription(text); titles[i].setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(10), 0); titlesLayout.addView(titles[i], LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); final int num = i; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPBackgroundProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPBackgroundProvider.java index 5cf249533..e792a6656 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPBackgroundProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPBackgroundProvider.java @@ -9,8 +9,6 @@ import android.graphics.Paint; import android.view.View; import android.view.animation.LinearInterpolator; -import androidx.annotation.NonNull; - import org.telegram.ui.Components.BitmapShaderTools; import java.util.ArrayList; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPNotificationsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPNotificationsLayout.java index caee01690..a10d1d342 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPNotificationsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPNotificationsLayout.java @@ -224,12 +224,12 @@ public class VoIPNotificationsLayout extends LinearLayout { this.backgroundProvider = backgroundProvider; backgroundProvider.attach(this); iconView = new ImageView(context); - addView(iconView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL, 10, 2, 10, 2)); + addView(iconView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL, 8, 2, 8, 2)); textView = new TextView(context); textView.setTextColor(Color.WHITE); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, iconRes == 0 ? 14 : 42, 2, 14, 2)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, iconRes == 0 ? 14 : 36, 2, 14, 2)); } public void setText(CharSequence text) { @@ -249,7 +249,20 @@ public class VoIPNotificationsLayout extends LinearLayout { protected void dispatchDraw(Canvas canvas) { bgRect.set(0, 0, getWidth(), getHeight()); backgroundProvider.setDarkTranslation(getX() + ((View) getParent()).getX(), getY() + ((View) getParent()).getY()); + + int oldDarkAlpha = backgroundProvider.getDarkPaint(ignoreShader).getAlpha(); + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), oldDarkAlpha, Canvas.ALL_SAVE_FLAG); + backgroundProvider.getDarkPaint(ignoreShader).setAlpha(255); canvas.drawRoundRect(bgRect, dp(16), dp(16), backgroundProvider.getDarkPaint(ignoreShader)); + backgroundProvider.getDarkPaint(ignoreShader).setAlpha(oldDarkAlpha); + + if (backgroundProvider.isReveal()) { + int oldRevealDarkAlpha = backgroundProvider.getRevealDarkPaint().getAlpha(); + backgroundProvider.getRevealDarkPaint().setAlpha(255); + canvas.drawRoundRect(bgRect, dp(16), dp(16), backgroundProvider.getRevealDarkPaint()); + backgroundProvider.getRevealDarkPaint().setAlpha(oldRevealDarkAlpha); + } + canvas.restore(); super.dispatchDraw(canvas); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPStatusTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPStatusTextView.java index e7a2d062e..a023efd70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPStatusTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPStatusTextView.java @@ -52,7 +52,6 @@ public class VoIPStatusTextView extends FrameLayout { for (int i = 0; i < 2; i++) { textView[i] = new TextView(context); textView[i].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - textView[i].setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000); textView[i].setTextColor(Color.WHITE); textView[i].setGravity(Gravity.CENTER_HORIZONTAL); addView(textView[i]); @@ -88,7 +87,6 @@ public class VoIPStatusTextView extends FrameLayout { reconnectTextView = new TextView(context); reconnectTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - reconnectTextView.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000); reconnectTextView.setTextColor(Color.WHITE); reconnectTextView.setGravity(Gravity.CENTER_HORIZONTAL); addView(reconnectTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 22, 0, 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPTimerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPTimerView.java index 7b55ea576..04182343c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPTimerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPTimerView.java @@ -40,7 +40,6 @@ public class VoIPTimerView extends View { super(context); textPaint.setTextSize(AndroidUtilities.dp(15)); textPaint.setColor(Color.WHITE); - textPaint.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000); activePaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.9f))); inactivePaint.setColor(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.4f))); callsDeclineDrawable = ContextCompat.getDrawable(context, R.drawable.calls_decline); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpCoverView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpCoverView.java new file mode 100644 index 000000000..eb20f57c3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpCoverView.java @@ -0,0 +1,216 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LiteMode; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.CubicBezierInterpolator; + +@SuppressLint("ViewConstructor") +public class VoIpCoverView extends View { + + private VoipCoverEmoji[] voipCoverEmojiLeft; + private VoipCoverEmoji[] voipCoverEmojiRight; + private ValueAnimator positionAnimator; + private int diffX1; + private int diffX2; + private int diffX3; + private int diffX4; + private int diffX5; + private int diffY1; + private int diffY2; + private int diffY3; + private int diffY4; + private int diffY5; + private boolean isConnected; + private boolean isEmojiExpanded; + private int connectedDiffX; + private boolean isPaused; + private final VoIPBackgroundProvider backgroundProvider; + private final Paint saveLayerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Rect bgRect = new Rect(); + private final boolean allowAnimations; + + public VoIpCoverView(Context context, TLRPC.User callingUser, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.allowAnimations = LiteMode.isEnabled(LiteMode.FLAG_CALLS_ANIMATIONS); + this.backgroundProvider = backgroundProvider; + if (!allowAnimations) { + return; + } + voipCoverEmojiLeft = new VoipCoverEmoji[]{ + new VoipCoverEmoji(callingUser, this, dp(32)), + new VoipCoverEmoji(callingUser, this, dp(28)), + new VoipCoverEmoji(callingUser, this, dp(35)), + new VoipCoverEmoji(callingUser, this, dp(28)), + new VoipCoverEmoji(callingUser, this, dp(26)) + }; + voipCoverEmojiRight = new VoipCoverEmoji[]{ + new VoipCoverEmoji(callingUser, this, dp(32)), + new VoipCoverEmoji(callingUser, this, dp(28)), + new VoipCoverEmoji(callingUser, this, dp(35)), + new VoipCoverEmoji(callingUser, this, dp(28)), + new VoipCoverEmoji(callingUser, this, dp(26)) + }; + backgroundProvider.attach(this); + setLayerType(LAYER_TYPE_HARDWARE, null); + saveLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + } + + public void onConnected() { + if (!allowAnimations) { + return; + } + if (isConnected) { + return; + } + isConnected = true; + connectedDiffX = dp(12); + positionAnimator = ValueAnimator.ofInt(0, connectedDiffX); + positionAnimator.addUpdateListener(a -> { + diffX1 = (int) a.getAnimatedValue(); + diffX2 = diffX1; + diffX3 = diffX1; + diffX4 = diffX1; + diffX5 = diffX1; + invalidate(); + }); + positionAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + positionAnimator.setDuration(200); + positionAnimator.start(); + } + + public void onEmojiExpanded(boolean expanded) { + if (!allowAnimations) { + return; + } + if (expanded == isEmojiExpanded) { + return; + } + isEmojiExpanded = expanded; + positionAnimator = expanded ? ValueAnimator.ofFloat(0, 1f) : ValueAnimator.ofFloat(1f, 0f); + positionAnimator.addUpdateListener(a -> { + float percent = (float) a.getAnimatedValue(); + diffX1 = AndroidUtilities.lerp(connectedDiffX, dp(56), percent); + diffX2 = AndroidUtilities.lerp(connectedDiffX, dp(36), percent); + diffX3 = AndroidUtilities.lerp(connectedDiffX, dp(60), percent); + diffX4 = AndroidUtilities.lerp(connectedDiffX, dp(36), percent); + diffX5 = AndroidUtilities.lerp(connectedDiffX, dp(64), percent); + + diffY1 = AndroidUtilities.lerp(0, dp(50), percent); + diffY2 = AndroidUtilities.lerp(0, dp(20), percent); + diffY3 = AndroidUtilities.lerp(0, 0, percent); + diffY4 = AndroidUtilities.lerp(0, dp(-20), percent); + diffY5 = AndroidUtilities.lerp(0, dp(-40), percent); + invalidate(); + }); + positionAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + positionAnimator.setDuration(200); + positionAnimator.start(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (!allowAnimations) { + return; + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiLeft) { + voipCoverEmoji.onLayout(getMeasuredWidth(), getMeasuredHeight()); + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiRight) { + voipCoverEmoji.onLayout(getMeasuredWidth(), getMeasuredHeight()); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (!allowAnimations) { + return; + } + if (isPaused) { + return; + } + bgRect.set(0, 0, getWidth(), getHeight()); + backgroundProvider.setDarkTranslation(getX(), getY()); + int centerX = getMeasuredWidth() / 2; + voipCoverEmojiLeft[0].setPosition(centerX - dp(120) - diffX1, dp(120) - diffY1); + voipCoverEmojiLeft[1].setPosition(centerX - dp(180) - diffX2, dp(150) - diffY2); + voipCoverEmojiLeft[2].setPosition(centerX - dp(150) - diffX3, dp(185) - diffY3); + voipCoverEmojiLeft[3].setPosition(centerX - dp(176) - diffX4, dp(240) - diffY4); + voipCoverEmojiLeft[4].setPosition(centerX - dp(130) - diffX5, dp(265) - diffY5); + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiLeft) { + voipCoverEmoji.onDraw(canvas); + } + voipCoverEmojiRight[0].setPosition(centerX + dp(50) + diffX1, dp(120) - diffY1); + voipCoverEmojiRight[1].setPosition(centerX + dp(110) + diffX2, dp(150) - diffY2); + voipCoverEmojiRight[2].setPosition(centerX + dp(80) + diffX3, dp(185) - diffY3); + voipCoverEmojiRight[3].setPosition(centerX + dp(106) + diffX4, dp(240) - diffY4); + voipCoverEmojiRight[4].setPosition(centerX + dp(60) + diffX5, dp(265) - diffY5); + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiRight) { + voipCoverEmoji.onDraw(canvas); + } + + int oldDarkAlpha = backgroundProvider.getDarkPaint().getAlpha(); + saveLayerPaint.setAlpha(255); + canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), saveLayerPaint, Canvas.ALL_SAVE_FLAG); + backgroundProvider.getDarkPaint().setAlpha(255); + canvas.drawRect(bgRect, backgroundProvider.getDarkPaint()); + backgroundProvider.getDarkPaint().setAlpha(oldDarkAlpha); + + if (backgroundProvider.isReveal()) { + int oldRevealDarkAlpha = backgroundProvider.getRevealDarkPaint().getAlpha(); + backgroundProvider.getRevealDarkPaint().setAlpha(255); + canvas.drawRect(bgRect, backgroundProvider.getRevealDarkPaint()); + backgroundProvider.getRevealDarkPaint().setAlpha(oldRevealDarkAlpha); + } + canvas.restore(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (!allowAnimations) { + return; + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiLeft) { + voipCoverEmoji.onAttachedToWindow(); + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiRight) { + voipCoverEmoji.onAttachedToWindow(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (!allowAnimations) { + return; + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiLeft) { + voipCoverEmoji.onDetachedFromWindow(); + } + for (VoipCoverEmoji voipCoverEmoji : voipCoverEmojiRight) { + voipCoverEmoji.onDetachedFromWindow(); + } + if (positionAnimator != null) { + positionAnimator.cancel(); + } + } + + public void setState(boolean isPaused) { + this.isPaused = isPaused; + invalidate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSwitchLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSwitchLayout.java index 8f48d428d..40a786b53 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSwitchLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSwitchLayout.java @@ -102,6 +102,7 @@ public class VoIpSwitchLayout extends FrameLayout { default: newText = ""; } + setContentDescription(newText); if (currentTextView.getVisibility() == GONE && newTextView.getVisibility() == GONE) { currentTextView.setVisibility(VISIBLE); @@ -147,7 +148,7 @@ public class VoIpSwitchLayout extends FrameLayout { newVoIpButtonView.setSelectedState(isSelected, false, type); newVoIpButtonView.setAlpha(0f); newVoIpButtonView.setOnBtnClickedListener(voIpButtonView.onBtnClickedListener); - addView(newVoIpButtonView, LayoutHelper.createFrame(VoIpButtonView.ITEM_SIZE, VoIpButtonView.ITEM_SIZE, Gravity.CENTER_HORIZONTAL)); + addView(newVoIpButtonView, LayoutHelper.createFrame(VoIpButtonView.ITEM_SIZE + 1.5f, VoIpButtonView.ITEM_SIZE + 1.5f, Gravity.CENTER_HORIZONTAL)); final VoIpButtonView oldVoIpButton = voIpButtonView; voIpButtonView = newVoIpButtonView; newVoIpButtonView.animate().alpha(1f).setDuration(250).start(); @@ -369,8 +370,26 @@ public class VoIpSwitchLayout extends FrameLayout { darkPaint.setAlpha(VoIPBackgroundProvider.DARK_LIGHT_DEFAULT_ALPHA); } + private ValueAnimator pressedScaleAnimator; + private float pressedScale = 1.0f; + + private void setPressedBtn(boolean pressed) { + if (pressedScaleAnimator != null) { + pressedScaleAnimator.cancel(); + } + pressedScaleAnimator = ValueAnimator.ofFloat(pressedScale, pressed ? 0.8f : 1f); + pressedScaleAnimator.addUpdateListener(animation -> { + pressedScale = (float) animation.getAnimatedValue(); + invalidate(); + }); + pressedScaleAnimator.setDuration(150); + pressedScaleAnimator.start(); + } + @Override protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.scale(pressedScale, pressedScale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); float cx = getWidth() / 2f; float cy = getHeight() / 2f; @@ -435,6 +454,7 @@ public class VoIpSwitchLayout extends FrameLayout { selectedIcon.setAlpha((int) (255 * VoIPBackgroundProvider.DARK_LIGHT_PERCENT)); selectedIcon.draw(canvas); //dimming icons } + canvas.restore(); } private boolean isAnimating() { @@ -451,14 +471,12 @@ public class VoIpSwitchLayout extends FrameLayout { public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - animate().scaleX(0.8f).scaleY(0.8f).setDuration(150).start(); - animate().scaleX(0.8f).scaleY(0.8f).setDuration(150).start(); + setPressedBtn(true); startX = event.getX(); startY = event.getY(); break; case MotionEvent.ACTION_UP: - animate().scaleX(1.0f).scaleY(1.0f).setDuration(150).start(); - animate().scaleX(1.0f).scaleY(1.0f).setDuration(150).start(); + setPressedBtn(false); float endX = event.getX(); float endY = event.getY(); if (isClick(startX, endX, startY, endY) && !isAnimating()) { @@ -466,8 +484,7 @@ public class VoIpSwitchLayout extends FrameLayout { } break; case MotionEvent.ACTION_CANCEL: - animate().scaleX(1.0f).scaleY(1.0f).setDuration(150).start(); - animate().scaleX(1.0f).scaleY(1.0f).setDuration(150).start(); + setPressedBtn(false); break; } return true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipCoverEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipCoverEmoji.java new file mode 100644 index 000000000..ff0227f5b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipCoverEmoji.java @@ -0,0 +1,171 @@ +package org.telegram.ui.Components.voip; + +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.Color; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.LiteMode; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; + +public class VoipCoverEmoji { + + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji; + private ValueAnimator positionAnimator; + private final boolean allowAnimations; + private int toRandomX; + private int toRandomY; + private int fromRandomX; + private int fromRandomY; + private int randomX; + private int randomY; + private int posX; + private int posY; + private final View parent; + private final int size; + private int alpha = 0; + private float scale = 0f; + private int width; + private int height; + private int diffX; + private boolean isShown; + private ValueAnimator diffXAnimator; + + public VoipCoverEmoji(TLRPC.User user, View parent, int size) { + this.parent = parent; + this.size = size; + allowAnimations = LiteMode.isEnabled(LiteMode.FLAG_CALLS_ANIMATIONS); + long emojiId = UserObject.getProfileEmojiId(user); + if (allowAnimations && emojiId != 0) { + emoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(parent, false, size, AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + emoji.set(emojiId, false); + emoji.setColor(Color.BLACK); + emoji.setAlpha(alpha); + + positionAnimator = ValueAnimator.ofFloat(0f, 1f); + positionAnimator.addUpdateListener(a -> { + randomX = (int) (fromRandomX + (toRandomX - fromRandomX) * (float) a.getAnimatedValue()); + randomY = (int) (fromRandomY + (toRandomY - fromRandomY) * (float) a.getAnimatedValue()); + parent.invalidate(); + }); + fromRandomX = toRandomX + dp(12); + fromRandomY = toRandomY + dp(12); + toRandomX = Utilities.random.nextInt(dp(16)) + dp(12); + toRandomY = Utilities.random.nextInt(dp(16)) + dp(12); + positionAnimator.setInterpolator(new LinearInterpolator()); + positionAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { + fromRandomX = toRandomX; + fromRandomY = toRandomY; + toRandomX = Utilities.random.nextInt(dp(16)) + dp(12); + toRandomY = Utilities.random.nextInt(dp(16)) + dp(12); + if (positionAnimator != null) { + positionAnimator.start(); + } + } + }); + positionAnimator.setDuration(2000); + } + } + + private void show() { + if (isShown) return; + if (emoji.getDrawable() instanceof AnimatedEmojiDrawable) { + AnimatedEmojiDrawable emojiDrawable = ((AnimatedEmojiDrawable) emoji.getDrawable()); + if (emojiDrawable.getImageReceiver() == null || !emojiDrawable.getImageReceiver().hasImageLoaded()) { + return; + } + } + isShown = true; + int delay = 180; + int duration = 350; + int maxX = 12; + diffX = posX > getCenterX() ? dp(maxX) : -dp(maxX); + ValueAnimator scaleAnimator = ValueAnimator.ofFloat(0, 1f); + scaleAnimator.setInterpolator(new CubicBezierInterpolator(.34, 1.36, .64, 1)); + scaleAnimator.addUpdateListener(a -> { + scale = (float) a.getAnimatedValue(); + parent.invalidate(); + if (scale > 1.0f && diffXAnimator == null) { + diffXAnimator = ValueAnimator.ofInt(dp(maxX), 0); + diffXAnimator.addUpdateListener(a2 -> { + int val = (int) a2.getAnimatedValue(); + diffX = posX > getCenterX() ? val : -val; + parent.invalidate(); + }); + diffXAnimator.setDuration(duration - a.getCurrentPlayTime()); + diffXAnimator.start(); + } + }); + scaleAnimator.setDuration(duration); + scaleAnimator.setStartDelay(delay); + scaleAnimator.start(); + ValueAnimator alphaAnimator = ValueAnimator.ofInt(0, 255, 255); + alphaAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + alphaAnimator.addUpdateListener(a -> { + alpha = (int) a.getAnimatedValue(); + parent.invalidate(); + }); + alphaAnimator.setStartDelay(delay); + alphaAnimator.setDuration(duration); + alphaAnimator.start(); + } + + private int getCenterX() { + return width / 2; + } + + public void onLayout(int width, int height) { + this.width = width; + this.height = height; + parent.invalidate(); + } + + public void setPosition(int x, int y) { + if (emoji == null) return; + posX = x; + posY = y; + parent.invalidate(); + show(); + } + + public void onDraw(Canvas canvas) { + if (emoji == null) return; + canvas.save(); + canvas.scale(scale, scale, width / 2f, dp(300)); + canvas.translate(posX - diffX, posY); + emoji.setBounds(randomX, randomY, randomX + size, randomY + size); + emoji.setAlpha(alpha); + emoji.draw(canvas); + canvas.restore(); + } + + public void onAttachedToWindow() { + if (emoji == null) return; + emoji.attach(); + if (positionAnimator != null) { + positionAnimator.start(); + } + } + + public void onDetachedFromWindow() { + if (emoji == null) return; + if (positionAnimator != null) { + positionAnimator.cancel(); + positionAnimator = null; + } + emoji.detach(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index faafc5082..40809cecd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -202,7 +202,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter } getContactsController().checkInviteText(); - getContactsController().reloadContactsStatusesMaybe(); + getContactsController().reloadContactsStatusesMaybe(false); MessagesController.getInstance(currentAccount).getStoriesController().loadHiddenStories(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index dc946e519..1e379bf1d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -2932,6 +2932,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. searchWas = false; wasDrawn = false; pacmanAnimation = null; + filterTabsView = null; selectedDialogs.clear(); maximumVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity(); @@ -3857,6 +3858,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); viewPage.addView(viewPage.listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); viewPage.listView.setOnItemClickListener((view, position, x, y) -> { + if (view instanceof DialogCell && ((DialogCell) view).isBlocked()) { + showPremiumBlockedToast(view, ((DialogCell) view).getDialogId()); + return; + } if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER && view instanceof TextCell) { viewPage.dialogsAdapter.onCreateGroupForThisClick(); return; @@ -3919,6 +3924,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. viewPage.listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListenerExtended() { @Override public boolean onItemClick(View view, int position, float x, float y) { + if (view instanceof DialogCell && ((DialogCell) view).isBlocked()) { + showPremiumBlockedToast(view, ((DialogCell) view).getDialogId()); + return true; + } if (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE && filterTabsView.isEditing()) { return false; } @@ -4109,7 +4118,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public void onButtonClicked(DialogCell dialogCell) { if (dialogCell.getMessage() != null) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(-dialogCell.getDialogId(), MessageObject.getTopicId(dialogCell.getMessage().messageOwner, true)); + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(-dialogCell.getDialogId(), MessageObject.getTopicId(currentAccount, dialogCell.getMessage().messageOwner, true)); if (topic != null) { if (onlySelect) { didSelectResult(dialogCell.getDialogId(), topic.id, false, false); @@ -4241,6 +4250,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } + @Override + public void didPressedBlockedDialog(View view, long did) { + showPremiumBlockedToast(view, did); + } + @Override public void didPressedOnSubDialog(long did) { if (onlySelect) { @@ -4355,6 +4369,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }); searchViewPager.searchListView.setOnItemClickListener((view, position, x, y) -> { + if (view instanceof ProfileSearchCell && ((ProfileSearchCell) view).isBlocked()) { + showPremiumBlockedToast(view, ((ProfileSearchCell) view).getDialogId()); + return; + } if (initialDialogsType == DIALOGS_TYPE_WIDGET) { onItemLongClick(searchViewPager.searchListView, view, position, x, y, -1, searchViewPager.dialogsSearchAdapter); return; @@ -4364,6 +4382,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. searchViewPager.searchListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListenerExtended() { @Override public boolean onItemClick(View view, int position, float x, float y) { + if (view instanceof ProfileSearchCell && ((ProfileSearchCell) view).isBlocked()) { + showPremiumBlockedToast(view, ((ProfileSearchCell) view).getDialogId()); + return true; + } return onItemLongClick(searchViewPager.searchListView, view, position, x, y, -1, searchViewPager.dialogsSearchAdapter); } @@ -4721,6 +4743,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } + @Override + public void toggleVideoRecordingPause() { + + } + @Override public void needChangeVideoPreviewState(int state, float seekProgress) { @@ -5102,7 +5129,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. showSearch(true, false, false); actionBar.openSearchField(searchString, false); } else if (initialSearchString != null) { - showSearch(true, false, false); + showSearch(true, false, false, true); actionBar.openSearchField(initialSearchString, false); initialSearchString = null; if (filterTabsView != null) { @@ -5526,6 +5553,29 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. popup[0].dimBehind(); } + private int shiftDp = -4; + private void showPremiumBlockedToast(View view, long dialogId) { + AndroidUtilities.shakeViewSpring(view, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + String username = ""; + if (dialogId >= 0) { + username = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } + Bulletin bulletin; + if (getMessagesController().premiumFeaturesBlocked()) { + bulletin = BulletinFactory.of(this).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username))); + } else { + bulletin = BulletinFactory.of(this) + .createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username)), LocaleController.getString(R.string.UserBlockedNonPremiumButton), () -> { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment != null) { + presentFragment(new PremiumPreviewFragment("noncontacts")); + } + }); + } + bulletin.show(); + } + private int commentViewPreviousTop = -1; private ValueAnimator keyboardAnimator; private boolean commentViewIgnoreTopUpdate = false; @@ -7009,6 +7059,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } private void showSearch(boolean show, boolean startFromDownloads, boolean animated) { + showSearch(show, startFromDownloads, animated, false); + } + + private void showSearch(boolean show, boolean startFromDownloads, boolean animated, boolean forceNotOnlyDialogs) { if (!show) { updateSpeedItem(false); } @@ -7027,7 +7081,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ((SizeNotifierFrameLayout) fragmentView).invalidateBlur(); if (show) { boolean onlyDialogsAdapter; - if (searchFiltersWasShowed) { + if (searchFiltersWasShowed || forceNotOnlyDialogs) { onlyDialogsAdapter = false; } else { onlyDialogsAdapter = onlyDialogsAdapter(); @@ -7565,7 +7619,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. return; } long dialogId = 0; - int topicId = 0; + long topicId = 0; int message_id = 0; boolean isGlobalSearch = false; int folderId = 0; @@ -7659,7 +7713,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. message_id = messageObject.getId(); TLRPC.Chat chat = getMessagesController().getChat(-dialogId); if (ChatObject.isForum(chat)) { - topicId = MessageObject.getTopicId(messageObject.messageOwner, true); + topicId = MessageObject.getTopicId(messageObject.currentAccount, messageObject.messageOwner, true); } searchViewPager.dialogsSearchAdapter.addHashtagsFromMessage(searchViewPager.dialogsSearchAdapter.getLastSearchString()); } else if (obj instanceof String) { @@ -7839,7 +7893,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } - public void setOpenedDialogId(long dialogId, int topicId) { + public void setOpenedDialogId(long dialogId, long topicId) { openedDialogId.dialogId = dialogId; openedDialogId.topicId = topicId; @@ -10153,7 +10207,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (viewPages[a].isDefaultDialogType() && AndroidUtilities.isTablet()) { boolean close = (Boolean) args[2]; long dialog_id = (Long) args[0]; - int topicId = (int) args[1]; + long topicId = (Long) args[1]; if (close) { if (dialog_id == openedDialogId.dialogId && topicId == openedDialogId.topicId) { openedDialogId.dialogId = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java index b49e62909..2256116a4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java @@ -91,14 +91,14 @@ public class EmojiAnimationsOverlay implements NotificationCenter.NotificationCe FrameLayout contentLayout; RecyclerListView listView; long dialogId; - int threadMsgId; + long threadMsgId; public EmojiAnimationsOverlay(FrameLayout frameLayout, int currentAccount) { this.contentLayout = frameLayout; this.currentAccount = currentAccount; } - public EmojiAnimationsOverlay(ChatActivity chatActivity, FrameLayout frameLayout, RecyclerListView chatListView, int currentAccount, long dialogId, int threadMsgId) { + public EmojiAnimationsOverlay(ChatActivity chatActivity, FrameLayout frameLayout, RecyclerListView chatListView, int currentAccount, long dialogId, long threadMsgId) { this.chatActivity = chatActivity; this.contentLayout = frameLayout; this.listView = chatListView; @@ -854,7 +854,7 @@ public class EmojiAnimationsOverlay implements NotificationCenter.NotificationCe TLRPC.TL_messages_setTyping req = new TLRPC.TL_messages_setTyping(); if (threadMsgId != 0) { - req.top_msg_id = threadMsgId; + req.top_msg_id = (int) threadMsgId; req.flags |= 1; } req.action = interaction; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index 270c8942b..e4e322c92 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -31,7 +31,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ChatObject; -import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -432,7 +431,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente } public static CharSequence createFromInfoString(MessageObject messageObject, boolean includeChat, int arrowType, TextPaint textPaint) { - if (messageObject == null) { + if (messageObject == null || messageObject.messageOwner == null) { return ""; } if (arrowSpan[arrowType] == null) { @@ -456,23 +455,36 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente arrowSpan[arrowType].setSpan(span, 0, arrowSpan[arrowType].length(), 0); } CharSequence fromName = null; - TLRPC.User user = messageObject.messageOwner.from_id.user_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getUser(messageObject.messageOwner.from_id.user_id) : null; + TLRPC.User user = null; TLRPC.Chat chatFrom = null, chatTo = null; - chatFrom = messageObject.messageOwner.from_id.chat_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id) : null; - if (chatFrom == null) { - chatFrom = messageObject.messageOwner.from_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; - } - chatTo = messageObject.messageOwner.peer_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; - if (chatTo == null) { - chatTo = messageObject.messageOwner.peer_id.chat_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id) : null; - } - if (!ChatObject.isChannelAndNotMegaGroup(chatTo) && !includeChat) { - chatTo = null; + if (messageObject.messageOwner.saved_peer_id != null) { + if (messageObject.getSavedDialogId() >= 0) { + user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(messageObject.getSavedDialogId()); + } else if (messageObject.getSavedDialogId() < 0) { + chatFrom = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-messageObject.getSavedDialogId()); + } + } else { + if (messageObject.messageOwner.from_id.user_id != 0) { + user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(messageObject.messageOwner.from_id.user_id); + } + if (messageObject.messageOwner.from_id.chat_id != 0) { + chatFrom = MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id); + } + if (chatFrom == null) { + chatFrom = messageObject.messageOwner.from_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; + } + chatTo = messageObject.messageOwner.peer_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; + if (chatTo == null) { + chatTo = messageObject.messageOwner.peer_id.chat_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id) : null; + } + if (!ChatObject.isChannelAndNotMegaGroup(chatTo) && !includeChat) { + chatTo = null; + } } if (user != null && chatTo != null) { CharSequence chatTitle = chatTo.title; if (ChatObject.isForum(chatTo)) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(UserConfig.selectedAccount).getTopicsController().findTopic(chatTo.id, MessageObject.getTopicId(messageObject.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(UserConfig.selectedAccount).getTopicsController().findTopic(chatTo.id, MessageObject.getTopicId(messageObject.currentAccount, messageObject.messageOwner, true)); if (topic != null) { chatTitle = ForumUtilities.getTopicSpannedName(topic, null, false); } @@ -491,7 +503,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente } else if (chatFrom != null) { CharSequence chatTitle = chatFrom.title; if (ChatObject.isForum(chatFrom)) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(UserConfig.selectedAccount).getTopicsController().findTopic(chatFrom.id, MessageObject.getTopicId(messageObject.messageOwner, true)); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(UserConfig.selectedAccount).getTopicsController().findTopic(chatFrom.id, MessageObject.getTopicId(messageObject.currentAccount, messageObject.messageOwner, true)); if (topic != null) { chatTitle = ForumUtilities.getTopicSpannedName(topic, null, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 6cca46e84..e1f9f09f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -52,6 +52,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; @@ -75,6 +76,7 @@ import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.GroupCreateSectionCell; import org.telegram.ui.Cells.GroupCreateUserCell; import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.EditTextBoldCursor; @@ -700,6 +702,10 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen if (ignoreUsers != null && ignoreUsers.indexOfKey(id) >= 0) { return; } + if (cell.isBlocked()) { + showPremiumBlockedToast(cell, id); + return; + } boolean exists; if (exists = selectedContacts.indexOfKey(id) >= 0) { GroupCreateSpan span = selectedContacts.get(id); @@ -826,6 +832,25 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen return fragmentView; } + private int shiftDp = -4; + private void showPremiumBlockedToast(View view, long dialogId) { + AndroidUtilities.shakeViewSpring(view, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + String username = ""; + if (dialogId >= 0) { + username = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } + Bulletin bulletin; + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { + bulletin = BulletinFactory.of(this).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username))); + } else { + bulletin = BulletinFactory.of(this).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedNonPremium, username)), LocaleController.getString(R.string.UserBlockedNonPremiumButton), () -> { + presentFragment(new PremiumPreviewFragment("noncontacts")); + }); + } + bulletin.show(); + } + private void updateEditTextHint() { if (editText == null) { return; @@ -1298,7 +1323,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen view = new GroupCreateSectionCell(context); break; case 1: - view = new GroupCreateUserCell(context, 1, 0, false); + view = new GroupCreateUserCell(context, 1, 0, false).showPremiumBlocked(); break; case 3: StickerEmptyView stickerEmptyView = new StickerEmptyView(context, null, StickerEmptyView.STICKER_TYPE_NO_CONTACTS) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index d6c220e66..607442316 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -1614,7 +1614,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati PasscodeView.PasscodeViewDelegate delegate = view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { - handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true); + handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, null, false); passcodeSaveIntent = null; } drawerLayoutContainer.setAllowOpenDrawer(true, false); @@ -2040,7 +2040,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati String inputInvoiceSlug = null; Integer messageId = null; Long channelId = null; - Integer threadId = null; + Long threadId = null; boolean isBoost = false; Integer commentId = null; int videoTimestamp = -1; @@ -2214,18 +2214,18 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati messageId = null; channelId = null; } - threadId = Utilities.parseInt(data.getQueryParameter("thread")); + threadId = Utilities.parseLong(data.getQueryParameter("thread")); if (threadId == 0) { threadId = null; } if (threadId == null) { - threadId = Utilities.parseInt(data.getQueryParameter("topic")); + threadId = Utilities.parseLong(data.getQueryParameter("topic")); if (threadId == 0) { threadId = null; } } if (threadId == null && messageId != null && segments.size() >= 4) { - threadId = messageId; + threadId = (long) (int) messageId; messageId = Utilities.parseInt(segments.get(3)); } } @@ -2279,7 +2279,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati setAsAttachBot = data.getQueryParameter("startattach"); attachMenuBotChoose = data.getQueryParameter("choose"); attachMenuBotToOpen = data.getQueryParameter("attach"); - threadId = Utilities.parseInt(data.getQueryParameter("thread")); + threadId = Utilities.parseLong(data.getQueryParameter("thread")); if (data.getQuery() != null) { isBoost = data.getQuery().equals("boost"); } @@ -2288,13 +2288,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati threadId = null; } if (threadId == null) { - threadId = Utilities.parseInt(data.getQueryParameter("topic")); + threadId = Utilities.parseLong(data.getQueryParameter("topic")); if (threadId == 0) { threadId = null; } } if (threadId == null && messageId != null && segments.size() >= 3) { - threadId = messageId; + threadId = (long) (int) messageId; messageId = Utilities.parseInt(segments.get(2)); } commentId = Utilities.parseInt(data.getQueryParameter("comment")); @@ -2357,12 +2357,12 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (messageId == 0) { messageId = null; } - threadId = Utilities.parseInt(data.getQueryParameter("thread")); + threadId = Utilities.parseLong(data.getQueryParameter("thread")); if (threadId == 0) { threadId = null; } if (threadId == null) { - threadId = Utilities.parseInt(data.getQueryParameter("topic")); + threadId = Utilities.parseLong(data.getQueryParameter("topic")); if (threadId == 0) { threadId = null; } @@ -2389,12 +2389,12 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati messageId = null; channelId = null; } - threadId = Utilities.parseInt(data.getQueryParameter("thread")); + threadId = Utilities.parseLong(data.getQueryParameter("thread")); if (threadId == 0) { threadId = null; } if (threadId == null) { - threadId = Utilities.parseInt(data.getQueryParameter("topic")); + threadId = Utilities.parseLong(data.getQueryParameter("topic")); if (threadId == 0) { threadId = null; } @@ -2651,7 +2651,12 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati url = url.replace("tg:addcontact", "tg://telegram.org").replace("tg://addcontact", "tg://telegram.org"); data = Uri.parse(url); newContactName = data.getQueryParameter("name"); - newContactPhone = data.getQueryParameter("phone"); + + // use getQueryParameters to keep the "+" sign + List phoneParams = data.getQueryParameters("phone"); + if (phoneParams != null && phoneParams.size() > 0) { + newContactPhone = phoneParams.get(0); + } newContact = true; } else if (url.startsWith("tg:addlist") || url.startsWith("tg://addlist")) { url = url.replace("tg:addlist", "tg://telegram.org").replace("tg://addlist", "tg://telegram.org"); @@ -2797,7 +2802,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (lastFragment instanceof DialogsActivity) { final DialogsActivity dialogsActivity = (DialogsActivity) lastFragment; if (dialogsActivity.isMainDialogList()) { - if (dialogsActivity.getFragmentView() != null) { + if (dialogsActivity.getFragmentView() != null && isNew) { dialogsActivity.search(searchQuery, true); } else { dialogsActivity.setInitialSearchString(searchQuery); @@ -3255,17 +3260,17 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } } - private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Integer threadId, TLRPC.Chat chat) { + private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Long threadId, TLRPC.Chat chat) { 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, int quoteOffset) { + private int runCommentRequest(int intentAccount, Runnable dismissLoading, Integer messageId, Integer commentId, Long threadId, TLRPC.Chat chat, Runnable onOpened, String quote, int fromMessageId, int quoteOffset) { if (chat == null) { return 0; } TLRPC.TL_messages_getDiscussionMessage req = new TLRPC.TL_messages_getDiscussionMessage(); req.peer = MessagesController.getInputPeer(chat); - req.msg_id = commentId != null ? messageId : threadId; + req.msg_id = commentId != null ? messageId : (int) (long) threadId; return ConnectionsManager.getInstance(intentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { boolean chatOpened = false; if (response instanceof TLRPC.TL_messages_discussionMessage) { @@ -3278,7 +3283,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, quoteOffset); + openTopicRequest(intentAccount, (int) (long) threadId, chat, commentId != null ? commentId : messageId, null, onOpened, quote, fromMessageId, arrayList, quoteOffset); chatOpened = true; } else { Bundle args = new Bundle(); @@ -3619,7 +3624,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati final boolean hasUrl, final Integer messageId, final Long channelId, - final Integer threadId, + final Long threadId, final Integer commentId, final String game, final HashMap auth, @@ -4168,9 +4173,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialog_id); if (chat != null && chat.forum) { - Integer topicId = threadId; - if (topicId == null) { - topicId = messageId; + Long topicId = threadId; + if (topicId == null && messageId != null) { + topicId = (long) (int) messageId; } if (topicId != null && topicId != 0) { openForumFromLink(dialog_id, messageId, () -> { @@ -4837,7 +4842,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati final boolean hasUrl, final Integer messageId, final Long channelId, - final Integer threadId, + final Long threadId, final Integer commentId, final String game, final HashMap auth, @@ -5120,7 +5125,7 @@ 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, quoteOffset); + runCommentRequest(currentAccount, null, message.id, null, MessageObject.getTopicId(currentAccount, message, MessagesController.getInstance(currentAccount).isForum(message)), MessagesController.getInstance(currentAccount).getChat(-dialogId), onOpened, quote, fromMessageId, quoteOffset); return; } @@ -5450,7 +5455,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati AccountInstance accountInstance = AccountInstance.getInstance(UserConfig.selectedAccount); for (int i = 0; i < dids.size(); i++) { long did = dids.get(i).dialogId; - int topicId = dids.get(i).topicId; + long topicId = dids.get(i).topicId; MessageObject replyToMsg = null; if (topicId != 0) { TLRPC.TL_forumTopic topic = accountInstance.getMessagesController().getTopicsController().findTopic(-did, topicId); @@ -5471,7 +5476,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati String captionToSend = null; for (int i = 0; i < dids.size(); i++) { final long did = dids.get(i).dialogId; - final int topicId = dids.get(i).topicId; + final long topicId = dids.get(i).topicId; AccountInstance accountInstance = AccountInstance.getInstance(UserConfig.selectedAccount); MessageObject replyToMsg = null; @@ -5996,7 +6001,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati AndroidUtilities.resetWasTabletFlag(); if (wasTablet != AndroidUtilities.isTablet()) { long dialogId = 0; - int topicId = 0; + long topicId = 0; if (wasTablet) { mainFragmentsStack.addAll(rightFragmentsStack); mainFragmentsStack.addAll(layerFragmentsStack); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java index f098e8653..441004399 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -62,6 +62,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.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.EmptyCell; @@ -492,7 +493,7 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati if (message.length() > 150) { message = message.subSequence(0, 150); } - message = Emoji.replaceEmoji(message, avatarContainer.getSubtitleTextView().getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); + message = Emoji.replaceEmoji(message, avatarContainer.getSubtitlePaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); } else { message = messageObject.messageText; } @@ -528,7 +529,10 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati }); 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())); + View subtitleTextView = avatarContainer.getSubtitleTextView(); + if (subtitleTextView instanceof SimpleTextView) { + ((SimpleTextView) subtitleTextView).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())); @@ -1177,7 +1181,10 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati sharedUi.invalidate(); } - avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); + View subtitle = avatarContainer.getSubtitleTextView(); + if (subtitle instanceof SimpleTextView) { + ((SimpleTextView) subtitle).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)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java index 5a2b889ff..e1360ec51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java @@ -80,7 +80,6 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On private boolean ignoreOnTextChange; private boolean ignoreOnPhoneChange; private boolean ignoreOnPhoneChangePaste; - private int countryState; private boolean ignoreSelection; private boolean donePressed; private String initialPhoneNumber; @@ -88,13 +87,11 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On private String initialFirstName; private String initialLastName; - private final static int done_button = 1; BaseFragment parentFragment; int classGuid; private AnimatedPhoneNumberEditText codeField; private View codeDividerView; private AnimatedPhoneNumberEditText phoneField; - private CountrySelectActivity.Country currentCountry; private String countryCodeForHint; private int wasCountryHintIndex; private TextView countryFlag; @@ -134,7 +131,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On firstNameField.getEditText().setImeOptions(EditorInfo.IME_ACTION_NEXT); firstNameField.setHint(LocaleController.getString("FirstName", R.string.FirstName)); if (initialFirstName != null) { - firstNameField.setText(initialFirstName); + firstNameField.getEditText().setText(initialFirstName); initialFirstName = null; } frameLayout.addView(firstNameField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 58, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); @@ -153,7 +150,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On lastNameField.getEditText().setImeOptions(EditorInfo.IME_ACTION_NEXT); lastNameField.setHint(LocaleController.getString("LastName", R.string.LastName)); if (initialLastName != null) { - lastNameField.setText(initialLastName); + lastNameField.getEditText().setText(initialLastName); initialLastName = null; } frameLayout.addView(lastNameField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 58, Gravity.LEFT | Gravity.TOP, 0, 68, 0, 0)); @@ -260,7 +257,6 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On if (text.length() == 0) { setCountryButtonText(null); phoneField.setHintText(null); - countryState = LoginActivity.COUNTRY_STATE_EMPTY; } else { CountrySelectActivity.Country country; boolean ok = false; @@ -339,18 +335,15 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On if (country != null) { ignoreSelection = true; - currentCountry = country; setCountryHint(text, country); - countryState = LoginActivity.COUNTRY_STATE_NOT_SET_OR_VALID; } else { setCountryButtonText(null); phoneField.setHintText(null); - countryState = LoginActivity.COUNTRY_STATE_INVALID; } if (!ok) { codeField.setSelection(codeField.getText().length()); } - if (textToSet != null) { + if (textToSet != null && textToSet.length() != 0) { phoneField.requestFocus(); phoneField.setText(textToSet); phoneField.setSelection(phoneField.length()); @@ -594,13 +587,11 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On } if (country1 != null) { codeField.setText(country1.code); - countryState = 0; } } } if (codeField.length() == 0) { phoneField.setHintText(null); - countryState = 1; } } @@ -698,6 +689,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On public void show() { super.show(); firstNameField.getEditText().requestFocus(); + firstNameField.getEditText().setSelection(firstNameField.getEditText().length()); AndroidUtilities.runOnUIThread(() -> { AndroidUtilities.showKeyboard(firstNameField.getEditText()); }, 50); @@ -738,9 +730,9 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On } } - public void setInitialPhoneNumber(String value, boolean withCoutryCode) { + public void setInitialPhoneNumber(String value, boolean withCountryCode) { initialPhoneNumber = value; - initialPhoneNumberWithCountryCode = withCoutryCode; + initialPhoneNumberWithCountryCode = withCountryCode; if (!TextUtils.isEmpty(initialPhoneNumber)) { TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); @@ -765,8 +757,16 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On } public void setInitialName(String firstName, String lastName) { - initialFirstName = firstName; - initialLastName = lastName; + if (firstNameField != null) { + firstNameField.getEditText().setText(firstName); + } else { + initialFirstName = firstName; + } + if (lastNameField != null) { + lastNameField.getEditText().setText(lastName); + } else { + initialLastName = lastName; + } } private void setCountryHint(String code, CountrySelectActivity.Country country) { @@ -856,8 +856,6 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On String code = country.code; codeField.setText(code); setCountryHint(code, country); - currentCountry = country; - countryState = LoginActivity.COUNTRY_STATE_NOT_SET_OR_VALID; ignoreOnTextChange = false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java index ea7f9b03d..262dba1bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSoundActivity.java @@ -115,7 +115,7 @@ public class NotificationsSoundActivity extends BaseFragment implements ChatAtta private final int tonesStreamType = AudioManager.STREAM_ALARM; - int topicId = 0; + long topicId = 0; public NotificationsSoundActivity(Bundle args) { this(args, null); @@ -130,7 +130,7 @@ public class NotificationsSoundActivity extends BaseFragment implements ChatAtta public boolean onFragmentCreate() { if (getArguments() != null) { dialogId = getArguments().getLong("dialog_id", 0); - topicId = getArguments().getInt("topic_id", 0); + topicId = getArguments().getLong("topic_id", 0); currentType = getArguments().getInt("type", -1); } String prefPath; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 091747b1e..b71f6a9bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -1832,7 +1832,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean canEditAvatar; private boolean isEvent; private int sharedMediaType; - private int topicId; + private long topicId; private long currentDialogId; private long mergeDialogId; private int totalImagesCount; @@ -3918,7 +3918,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } else if (id == NotificationCenter.mediaCountDidLoad) { long uid = (Long) args[0]; - int topicId = (Integer) args[1]; + long topicId = (Long) args[1]; if (this.topicId == topicId && (uid == currentDialogId || uid == mergeDialogId)) { if (currentMessageObject == null || MediaDataController.getMediaType(currentMessageObject.messageOwner) == sharedMediaType) { if (uid == currentDialogId) { @@ -5418,7 +5418,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.addSubItem(gallery_menu_openin, R.drawable.msg_openin, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp)).setColors(0xfffafafa, 0xfffafafa); menuItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - allMediaItem = menuItem.addSubItem(gallery_menu_showall, R.drawable.msg_media, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia)); + allMediaItem = menuItem.addSubItem(gallery_menu_showall, R.drawable.msg_media, LocaleController.getString(R.string.ShowAllMedia)); allMediaItem.setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_savegif, R.drawable.msg_gif, LocaleController.getString("SaveToGIFs", R.string.SaveToGIFs)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_showinchat, R.drawable.msg_message, LocaleController.getString("ShowInChat", R.string.ShowInChat)).setColors(0xfffafafa, 0xfffafafa); @@ -11627,7 +11627,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (!messageObject.scheduled && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) && !(MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty)) { needSearchImageInArr = true; imagesByIds[0].put(messageObject.getId(), messageObject); - if (parentChatActivity == null || !parentChatActivity.isThreadChat()) { + if (parentChatActivity == null || !parentChatActivity.isThreadChat() && parentChatActivity.getChatMode() != ChatActivity.MODE_SAVED) { menuItem.showSubItem(gallery_menu_showinchat); menuItem.showSubItem(gallery_menu_showall); } @@ -12401,20 +12401,28 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } if (parentChatActivity != null) { - TLRPC.Chat chat = parentChatActivity.getCurrentChat(); - if (chat != null) { - title = null; - actionBarContainer.setTitle(chat.title); + TLRPC.Chat chat = null; + TLRPC.User user = null; + if (parentChatActivity.getChatMode() == ChatActivity.MODE_SAVED) { + long did = parentChatActivity.getSavedDialogId(); + if (did >= 0) { + user = parentChatActivity.getMessagesController().getUser(did); + } else { + chat = parentChatActivity.getMessagesController().getChat(-did); + } } else { - TLRPC.User user = parentChatActivity.getCurrentUser(); - if (user != null) { - if (user.self) { - title = null; - actionBarContainer.setTitle(LocaleController.getString("SavedMessages", R.string.SavedMessages)); - } else { - title = null; - actionBarContainer.setTitle(ContactsController.formatName(user.first_name, user.last_name)); - } + user = parentChatActivity.getCurrentUser(); + chat = parentChatActivity.getCurrentChat(); + } + if (chat != null) { + title = chat.title; + } else { + if (UserObject.isUserSelf(user)) { + title = LocaleController.getString(parentChatActivity.getChatMode() == ChatActivity.MODE_SAVED ? R.string.MyNotes : R.string.SavedMessages); + } else if (UserObject.isAnonymous(user)) { + title = LocaleController.getString(R.string.AnonymousForward); + } else { + title = UserObject.getUserName(user); } } } @@ -13964,15 +13972,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - public boolean openPhoto(final MessageObject messageObject, ChatActivity chatActivity, long dialogId, long mergeDialogId, int topicId, final PhotoViewerProvider provider) { + public boolean openPhoto(final MessageObject messageObject, ChatActivity chatActivity, long dialogId, long mergeDialogId, long topicId, final PhotoViewerProvider provider) { return openPhoto(messageObject, null, null, null, null, null, null, 0, provider, chatActivity, dialogId, mergeDialogId, topicId, true, null, null); } - public boolean openPhoto(final MessageObject messageObject, int embedSeekTime, ChatActivity chatActivity, long dialogId, long mergeDialogId, int topicId, final PhotoViewerProvider provider) { + public boolean openPhoto(final MessageObject messageObject, int embedSeekTime, ChatActivity chatActivity, long dialogId, long mergeDialogId, long topicId, final PhotoViewerProvider provider) { return openPhoto(messageObject, null, null, null, null, null, null, 0, provider, chatActivity, dialogId, mergeDialogId, topicId, true, null, embedSeekTime); } - public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, int topicId, final PhotoViewerProvider provider, boolean fullScreenVideo) { + public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, long topicId, final PhotoViewerProvider provider, boolean fullScreenVideo) { return openPhoto(messageObject, null, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, topicId, fullScreenVideo, null, null); } @@ -13988,7 +13996,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return openPhoto(null, fileLocation, imageLocation, null, null, null, null, 0, provider, null, 0, 0, 0, true, null, null); } - public boolean openPhoto(final ArrayList messages, final int index, long dialogId, long mergeDialogId, int topicId, final PhotoViewerProvider provider) { + public boolean openPhoto(final ArrayList messages, final int index, long dialogId, long mergeDialogId, long topicId, final PhotoViewerProvider provider) { return openPhoto(messages.get(index), null, null, null, messages, null, null, index, provider, null, dialogId, mergeDialogId, topicId, true, null, null); } @@ -14259,7 +14267,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat padImageForHorizontalInsets = true; } - public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final ImageLocation videoLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, int topicId, boolean fullScreenVideo, PageBlocksAdapter pageBlocksAdapter, Integer embedSeekTime) { + public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final ImageLocation videoLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, long topicId, boolean fullScreenVideo, PageBlocksAdapter pageBlocksAdapter, Integer embedSeekTime) { if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null && documents == null && imageLocation == null && pageBlocksAdapter == null) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index 6e2123e68..6373fdb6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -399,6 +399,11 @@ public class PopupNotificationActivity extends Activity implements NotificationC } + @Override + public void toggleVideoRecordingPause() { + + } + @Override public void needStartRecordAudio(int state) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index 5d8b4439a..613cbf72f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -8,6 +8,9 @@ package org.telegram.ui; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Canvas; @@ -36,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; @@ -62,11 +66,14 @@ import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.RadioCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.BotWebViewContainer; +import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -123,6 +130,10 @@ public class PrivacyControlActivity extends BaseFragment implements Notification private int p2pSectionRow; private int p2pRow; private int p2pDetailRow; + private int readRow; + private int readDetailRow; + private int readPremiumRow; + private int readPremiumDetailRow; private int rowCount; private final static int done_button = 1; @@ -137,6 +148,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification public final static int PRIVACY_RULES_TYPE_ADDED_BY_PHONE = 7; public final static int PRIVACY_RULES_TYPE_VOICE_MESSAGES = 8; public final static int PRIVACY_RULES_TYPE_BIO = 9; + public final static int PRIVACY_RULES_TYPE_MESSAGES = 10; public final static int TYPE_EVERYBODY = 0; public final static int TYPE_NOBODY = 1; @@ -149,6 +161,9 @@ public class PrivacyControlActivity extends BaseFragment implements Notification private TLRPC.PhotoSize avatarForRest; private TLRPC.Photo avatarForRestPhoto; + private boolean currentReadValue; + private boolean selectedReadValue; + @Override public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { @@ -431,6 +446,8 @@ public class PrivacyControlActivity extends BaseFragment implements Notification NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); } + private int shakeDp = 4; + @Override public View createView(Context context) { if (rulesType == PRIVACY_RULES_TYPE_FORWARDS) { @@ -455,8 +472,10 @@ public class PrivacyControlActivity extends BaseFragment implements Notification actionBar.setTitle(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels)); } else if (rulesType == PRIVACY_RULES_TYPE_VOICE_MESSAGES) { actionBar.setTitle(LocaleController.getString("PrivacyVoiceMessages", R.string.PrivacyVoiceMessages)); - } else { + } else if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN) { actionBar.setTitle(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen)); + } else if (rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + actionBar.setTitle(LocaleController.getString(R.string.PrivacyMessages)); } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -547,6 +566,18 @@ public class PrivacyControlActivity extends BaseFragment implements Notification cameraDrawable.setCustomEndFrame(43); setAvatarCell.imageView.playAnimation(); } + } else if (rulesType == PRIVACY_RULES_TYPE_MESSAGES && position == myContactsRow && !getUserConfig().isPremium()) { + BulletinFactory.of(this).createSimpleBulletin( + R.raw.star_premium_2, + LocaleController.getString(R.string.OptionPremiumRequiredTitle), + AndroidUtilities.replaceTags(LocaleController.getString(R.string.OptionPremiumRequiredMessage)), + LocaleController.getString(R.string.OptionPremiumRequiredButton), + () -> { + presentFragment(new PremiumPreviewFragment("noncontacts")); + } + ).show(); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(view, shakeDp = -shakeDp); } else if (position == nobodyRow || position == everybodyRow || position == myContactsRow) { int newType; if (position == nobodyRow) { @@ -560,6 +591,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification return; } currentType = newType; + Bulletin.hideVisible(); updateDoneButton(); updateRows(true); } else if (position == phoneContactsRow || position == phoneEverybodyRow) { @@ -628,6 +660,12 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } } else if (position == p2pRow) { presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_P2P)); + } else if (position == readRow) { + selectedReadValue = !selectedReadValue; + updateDoneButton(); + ((TextCheckCell) view).setChecked(selectedReadValue); + } else if (position == readPremiumRow) { + presentFragment(new PremiumPreviewFragment("lastseen")); } }); DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { @@ -667,6 +705,26 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } private void applyCurrentPrivacySettings() { + if (rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + TLRPC.TL_account_setGlobalPrivacySettings req2 = new TLRPC.TL_account_setGlobalPrivacySettings(); + req2.settings = new TLRPC.TL_globalPrivacySettings(); + TLRPC.TL_globalPrivacySettings settings = getContactsController().getGlobalPrivacySettings(); + req2.settings.archive_and_mute_new_noncontact_peers = settings.archive_and_mute_new_noncontact_peers; + req2.settings.keep_archived_folders = settings.keep_archived_folders; + req2.settings.keep_archived_unmuted = settings.keep_archived_unmuted; + req2.settings.new_noncontact_peers_require_premium = currentType == TYPE_CONTACTS; + req2.settings.hide_read_marks = settings.hide_read_marks; + getConnectionsManager().sendRequest(req2, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error != null) { + showErrorAlert(); + } else { + settings.new_noncontact_peers_require_premium = req2.settings.new_noncontact_peers_require_premium; + finishFragment(); + getNotificationCenter().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + })); + return; + } TLRPC.TL_account_setPrivacy req = new TLRPC.TL_account_setPrivacy(); if (rulesType == PRIVACY_RULES_TYPE_PHONE) { req.key = new TLRPC.TL_inputPrivacyKeyPhoneNumber(); @@ -774,6 +832,20 @@ public class PrivacyControlActivity extends BaseFragment implements Notification showErrorAlert(); } }), ConnectionsManager.RequestFlagFailOnServerErrors); + + if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN && selectedReadValue != currentReadValue) { + TLRPC.TL_account_setGlobalPrivacySettings req2 = new TLRPC.TL_account_setGlobalPrivacySettings(); + req2.settings = new TLRPC.TL_globalPrivacySettings(); + TLRPC.TL_globalPrivacySettings settings = getContactsController().getGlobalPrivacySettings(); + req2.settings.archive_and_mute_new_noncontact_peers = settings.archive_and_mute_new_noncontact_peers; + req2.settings.keep_archived_folders = settings.keep_archived_folders; + req2.settings.keep_archived_unmuted = settings.keep_archived_unmuted; + req2.settings.new_noncontact_peers_require_premium = settings.new_noncontact_peers_require_premium; + req2.settings.hide_read_marks = selectedReadValue; + getConnectionsManager().sendRequest(req2, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + settings.hide_read_marks = currentReadValue = req2.settings.hide_read_marks; + })); + } } private void showErrorAlert() { @@ -788,6 +860,13 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } private void checkPrivacy() { + if (rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + TLRPC.TL_globalPrivacySettings settings = ContactsController.getInstance(currentAccount).getGlobalPrivacySettings(); + initialRulesType = currentType = settings != null && settings.new_noncontact_peers_require_premium ? TYPE_CONTACTS : TYPE_EVERYBODY; + currentMinus = new ArrayList<>(); + currentPlus = new ArrayList<>(); + return; + } currentPlus = new ArrayList<>(); currentMinus = new ArrayList<>(); ArrayList privacyRules = ContactsController.getInstance(currentAccount).getPrivacyRules(rulesType); @@ -866,9 +945,16 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } updateRows(false); + if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN) { + TLRPC.TL_globalPrivacySettings privacySettings = getContactsController().getGlobalPrivacySettings(); + selectedReadValue = currentReadValue = privacySettings != null && privacySettings.hide_read_marks; + } } private boolean hasChanges() { + if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN && currentType != TYPE_EVERYBODY && currentReadValue != selectedReadValue) { + return true; + } if (initialRulesType != currentType) { return true; } @@ -904,11 +990,25 @@ public class PrivacyControlActivity extends BaseFragment implements Notification photoForRestRow = -1; currentPhotoForRestRow = -1; photoForRestDescriptionRow = -1; + messageRow = -1; + phoneDetailRow = -1; + phoneSectionRow = -1; + phoneEverybodyRow = -1; + phoneContactsRow = -1; + alwaysShareRow = -1; + neverShareRow = -1; + p2pSectionRow = -1; + p2pRow = -1; + p2pDetailRow = -1; + readRow = readDetailRow = -1; + nobodyRow = -1; + shareSectionRow = -1; + shareDetailRow = -1; + readPremiumRow = readPremiumDetailRow = -1; + rowCount = 0; if (rulesType == PRIVACY_RULES_TYPE_FORWARDS) { messageRow = rowCount++; - } else { - messageRow = -1; } sectionRow = rowCount++; everybodyRow = rowCount++; @@ -925,49 +1025,44 @@ public class PrivacyControlActivity extends BaseFragment implements Notification rulesType == PRIVACY_RULES_TYPE_INVITE ) { nobodyRow = rowCount++; - } else { - nobodyRow = -1; } if (rulesType == PRIVACY_RULES_TYPE_PHONE && currentType == TYPE_NOBODY) { phoneDetailRow = rowCount++; phoneSectionRow = rowCount++; phoneEverybodyRow = rowCount++; phoneContactsRow = rowCount++; - } else { - phoneDetailRow = -1; - phoneSectionRow = -1; - phoneEverybodyRow = -1; - phoneContactsRow = -1; } detailRow = rowCount++; - shareSectionRow = rowCount++; - if (currentType == TYPE_NOBODY || currentType == TYPE_CONTACTS) { - alwaysShareRow = rowCount++; - } else { - alwaysShareRow = -1; - } - if (currentType == TYPE_EVERYBODY || currentType == TYPE_CONTACTS) { - neverShareRow = rowCount++; - } else { - neverShareRow = -1; - } - shareDetailRow = rowCount++; - if (rulesType == PRIVACY_RULES_TYPE_CALLS) { - p2pSectionRow = rowCount++; - p2pRow = rowCount++; - p2pDetailRow = rowCount++; - } else { - p2pSectionRow = -1; - p2pRow = -1; - p2pDetailRow = -1; - } - - if (rulesType == PRIVACY_RULES_TYPE_PHOTO && (currentMinus.size() > 0 || currentType == TYPE_CONTACTS || currentType == TYPE_NOBODY)) { - photoForRestRow = rowCount++; - if (avatarForRest != null) { - currentPhotoForRestRow = rowCount++; + if (rulesType != PRIVACY_RULES_TYPE_MESSAGES) { + shareSectionRow = rowCount++; + if (currentType == TYPE_NOBODY || currentType == TYPE_CONTACTS) { + alwaysShareRow = rowCount++; + } + if (currentType == TYPE_EVERYBODY || currentType == TYPE_CONTACTS) { + neverShareRow = rowCount++; + } + shareDetailRow = rowCount++; + if (rulesType == PRIVACY_RULES_TYPE_CALLS) { + p2pSectionRow = rowCount++; + p2pRow = rowCount++; + p2pDetailRow = rowCount++; + } + + if (rulesType == PRIVACY_RULES_TYPE_PHOTO && (currentMinus.size() > 0 || currentType == TYPE_CONTACTS || currentType == TYPE_NOBODY)) { + photoForRestRow = rowCount++; + if (avatarForRest != null) { + currentPhotoForRestRow = rowCount++; + } + photoForRestDescriptionRow = rowCount++; + } + if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN && currentType != TYPE_EVERYBODY) { + readRow = rowCount++; + readDetailRow = rowCount++; + } + if (rulesType == PRIVACY_RULES_TYPE_LASTSEEN && !getUserConfig().isPremium() && !getMessagesController().premiumFeaturesBlocked()) { + readPremiumRow = rowCount++; + readPremiumDetailRow = rowCount++; } - photoForRestDescriptionRow = rowCount++; } setMessageText(); @@ -1114,7 +1209,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification int position = holder.getAdapterPosition(); return position == nobodyRow || position == everybodyRow || position == myContactsRow || position == neverShareRow || position == alwaysShareRow || position == p2pRow && !ContactsController.getInstance(currentAccount).getLoadingPrivacyInfo(ContactsController.PRIVACY_RULES_TYPE_P2P) || - position == currentPhotoForRestRow || position == photoForRestDescriptionRow || position == photoForRestRow; + position == currentPhotoForRestRow || position == photoForRestDescriptionRow || position == photoForRestRow || position == readRow || position == readPremiumRow; } @Override @@ -1201,6 +1296,11 @@ public class PrivacyControlActivity extends BaseFragment implements Notification oldPhotoCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); view = oldPhotoCell; break; + case 8: + TextCheckCell textCheckCell = new TextCheckCell(mContext, resourceProvider); + textCheckCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view = textCheckCell; + break; } return new RecyclerListView.Holder(view); } @@ -1226,6 +1326,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification switch (holder.getItemViewType()) { case 0: TextSettingsCell textCell = (TextSettingsCell) holder.itemView; + textCell.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); if (position == alwaysShareRow) { String value; if (currentPlus.size() != 0) { @@ -1259,12 +1360,20 @@ public class PrivacyControlActivity extends BaseFragment implements Notification value = PrivacySettingsActivity.formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_P2P); } textCell.setTextAndValue(LocaleController.getString("PrivacyP2P2", R.string.PrivacyP2P2), value, false); + } else if (position == readPremiumRow) { + textCell.setText(LocaleController.getString(R.string.PrivacyLastSeenPremium), false); + textCell.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText)); } break; case 1: TextInfoPrivacyCell privacyCell = (TextInfoPrivacyCell) holder.itemView; int backgroundResId = 0; - if (position == detailRow) { + if (position == detailRow && rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + privacyCell.setText(AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.PrivacyMessagesInfo), () -> { + presentFragment(new PremiumPreviewFragment("noncontacts")); + })); + backgroundResId = R.drawable.greydivider_bottom; + } else if (position == detailRow) { if (rulesType == PRIVACY_RULES_TYPE_PHONE) { if (prevSubtypeContacts = (currentType == TYPE_NOBODY && currentSubType == 1)) { privacyCell.setText(LocaleController.getString("PrivacyPhoneInfo3", R.string.PrivacyPhoneInfo3)); @@ -1303,7 +1412,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } else if (rulesType == PRIVACY_RULES_TYPE_INVITE) { privacyCell.setText(LocaleController.getString("WhoCanAddMeInfo", R.string.WhoCanAddMeInfo)); } else if (rulesType == PRIVACY_RULES_TYPE_VOICE_MESSAGES) { - privacyCell.setText(LocaleController.getString("PrivacyVoiceMessagesInfo", R.string.PrivacyVoiceMessagesInfo)); + privacyCell.setText(LocaleController.getString(R.string.PrivacyVoiceMessagesInfo)); } else { privacyCell.setText(LocaleController.getString("CustomHelp", R.string.CustomHelp)); } @@ -1334,7 +1443,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } else { privacyCell.setText(LocaleController.getString("CustomShareSettingsHelp", R.string.CustomShareSettingsHelp)); } - if (rulesType == PRIVACY_RULES_TYPE_CALLS) { + if (rulesType == PRIVACY_RULES_TYPE_CALLS || rulesType == PRIVACY_RULES_TYPE_LASTSEEN) { backgroundResId = R.drawable.greydivider; } else { backgroundResId = R.drawable.greydivider_bottom; @@ -1343,6 +1452,12 @@ public class PrivacyControlActivity extends BaseFragment implements Notification backgroundResId = R.drawable.greydivider_bottom; } else if (position == photoForRestDescriptionRow) { privacyCell.setText(LocaleController.getString("PhotoForRestDescription", R.string.PhotoForRestDescription)); + } else if (position == readDetailRow) { + privacyCell.setText(LocaleController.getString(R.string.HideReadTimeInfo)); + backgroundResId = readPremiumDetailRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider; + } else if (position == readPremiumDetailRow) { + privacyCell.setText(LocaleController.getString(R.string.PrivacyLastSeenPremiumInfo)); + backgroundResId = R.drawable.greydivider_bottom; } if (backgroundResId != 0) { Drawable drawable = Theme.getThemedDrawableByKey(mContext, backgroundResId, Theme.key_windowBackgroundGrayShadow); @@ -1370,6 +1485,8 @@ public class PrivacyControlActivity extends BaseFragment implements Notification headerCell.setText(LocaleController.getString("WhoCanAddMe", R.string.WhoCanAddMe)); } else if (rulesType == PRIVACY_RULES_TYPE_VOICE_MESSAGES) { headerCell.setText(LocaleController.getString("PrivacyVoiceMessagesTitle", R.string.PrivacyVoiceMessagesTitle)); + } else if (rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + headerCell.setText(LocaleController.getString(R.string.PrivacyMessagesTitle)); } else { headerCell.setText(LocaleController.getString("LastSeenTitle", R.string.LastSeenTitle)); } @@ -1383,6 +1500,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification break; case 3: RadioCell radioCell = (RadioCell) holder.itemView; + radioCell.setRadioIcon(null); if (position == everybodyRow || position == myContactsRow || position == nobodyRow) { if (position == everybodyRow) { if (rulesType == PRIVACY_RULES_TYPE_P2P) { @@ -1393,6 +1511,11 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } else if (position == myContactsRow) { if (rulesType == PRIVACY_RULES_TYPE_P2P) { radioCell.setText(LocaleController.getString("P2PContacts", R.string.P2PContacts), currentType == TYPE_CONTACTS, nobodyRow != -1); + } else if (rulesType == PRIVACY_RULES_TYPE_MESSAGES) { + if (!getUserConfig().isPremium()) { + radioCell.setRadioIcon(getContext().getResources().getDrawable(R.drawable.mini_switch_lock).mutate()); + } + radioCell.setText(LocaleController.getString(R.string.PrivacyMessagesContactsAndPremium), currentType == TYPE_CONTACTS, nobodyRow != -1); } else { radioCell.setText(LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), currentType == TYPE_CONTACTS, nobodyRow != -1); } @@ -1411,14 +1534,20 @@ public class PrivacyControlActivity extends BaseFragment implements Notification } } break; + case 8: + TextCheckCell checkCell = (TextCheckCell) holder.itemView; + if (position == readRow) { + checkCell.setTextAndCheck(LocaleController.getString(R.string.HideReadTime), selectedReadValue, false); + } + break; } } @Override public int getItemViewType(int position) { - if (position == alwaysShareRow || position == neverShareRow || position == p2pRow) { + if (position == alwaysShareRow || position == neverShareRow || position == p2pRow || position == readPremiumRow) { return 0; - } else if (position == shareDetailRow || position == detailRow || position == p2pDetailRow || position == photoForRestDescriptionRow) { + } else if (position == shareDetailRow || position == detailRow || position == p2pDetailRow || position == photoForRestDescriptionRow || position == readDetailRow || position == readPremiumDetailRow) { return 1; } else if (position == sectionRow || position == shareSectionRow || position == p2pSectionRow || position == phoneSectionRow) { return 2; @@ -1432,6 +1561,8 @@ public class PrivacyControlActivity extends BaseFragment implements Notification return 6; } else if (position == currentPhotoForRestRow) { return 7; + } else if (position == readRow) { + return 8; } return 0; } @@ -1489,6 +1620,10 @@ public class PrivacyControlActivity extends BaseFragment implements Notification put(++pointer, p2pSectionRow, sparseIntArray); put(++pointer, p2pRow, sparseIntArray); put(++pointer, p2pDetailRow, sparseIntArray); + put(++pointer, readRow, sparseIntArray); + put(++pointer, readDetailRow, sparseIntArray); + put(++pointer, readPremiumRow, sparseIntArray); + put(++pointer, readPremiumDetailRow, sparseIntArray); } private void put(int id, int position, SparseIntArray sparseIntArray) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index 405d743e6..515ca866b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -78,6 +78,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int forwardsRow; private int callsRow; private int voicesRow; + private int noncontactsRow; private int emailLoginRow; private int privacyShadowRow; private int groupsRow; @@ -118,6 +119,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private boolean currentSuggest; private boolean newSuggest; private boolean archiveChats; + private boolean noncontactsValue; private boolean[] clear = new boolean[2]; private SessionsActivity devicesActivityPreload; @@ -134,6 +136,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio TLRPC.TL_globalPrivacySettings privacySettings = getContactsController().getGlobalPrivacySettings(); if (privacySettings != null) { archiveChats = privacySettings.archive_and_mute_new_noncontact_peers; + noncontactsValue = privacySettings.new_noncontact_peers_require_premium; } updateRows(); @@ -203,8 +206,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio globalPrivacySettings.archive_and_mute_new_noncontact_peers = archiveChats; save = true; TLRPC.TL_account_setGlobalPrivacySettings req = new TLRPC.TL_account_setGlobalPrivacySettings(); - req.settings = new TLRPC.TL_globalPrivacySettings(); - req.settings.flags |= 1; + req.settings = getContactsController().getGlobalPrivacySettings(); + if (req.settings == null) { + req.settings = new TLRPC.TL_globalPrivacySettings(); + } req.settings.archive_and_mute_new_noncontact_peers = archiveChats; getConnectionsManager().sendRequest(req, (response, error) -> { @@ -360,6 +365,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_VOICE_MESSAGES)); + } else if (position == noncontactsRow) { + presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_MESSAGES)); } else if (position == emailLoginRow) { if (currentPassword == null || currentPassword.login_email_pattern == null) { return; @@ -587,6 +594,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio TLRPC.TL_globalPrivacySettings privacySettings = getContactsController().getGlobalPrivacySettings(); if (privacySettings != null) { archiveChats = privacySettings.archive_and_mute_new_noncontact_peers; + noncontactsValue = privacySettings.new_noncontact_peers_require_premium; } if (listAdapter != null) { listAdapter.notifyDataSetChanged(); @@ -649,8 +657,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio groupsDetailRow = -1; if (!getMessagesController().premiumFeaturesBlocked() || getUserConfig().isPremium()) { voicesRow = rowCount++; + noncontactsRow = rowCount++; } else { voicesRow = -1; + noncontactsRow = -1; } privacyShadowRow = rowCount++; @@ -882,6 +892,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio position == forwardsRow && !getContactsController().getLoadingPrivacyInfo(ContactsController.PRIVACY_RULES_TYPE_FORWARDS) || position == phoneNumberRow && !getContactsController().getLoadingPrivacyInfo(ContactsController.PRIVACY_RULES_TYPE_PHONE) || position == voicesRow && !getContactsController().getLoadingPrivacyInfo(ContactsController.PRIVACY_RULES_TYPE_VOICE_MESSAGES) || + position == noncontactsRow || position == deleteAccountRow && !getContactsController().getLoadingDeleteInfo() || position == newChatsRow && !getContactsController().getLoadingGlobalSettings() || position == emailLoginRow || position == paymentsClearRow || position == secretMapRow || @@ -1001,7 +1012,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { value = formatRulesString(getAccountInstance(), ContactsController.PRIVACY_RULES_TYPE_VOICE_MESSAGES); } - textCell.setTextAndValue(LocaleController.getString(R.string.PrivacyVoiceMessages), value, false); + textCell.setTextAndValue(LocaleController.getString(R.string.PrivacyVoiceMessages), value, noncontactsRow != -1); ImageView imageView = textCell.getValueImageView(); if (!getUserConfig().isPremium()) { imageView.setVisibility(View.VISIBLE); @@ -1011,6 +1022,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); } + } else if (position == noncontactsRow) { + value = LocaleController.getString(noncontactsValue ? R.string.ContactsAndPremium : R.string.P2PEverybody); + textCell.setTextAndValue(LocaleController.getString(R.string.PrivacyMessages), value, false); } else if (position == passportRow) { textCell.setText(LocaleController.getString("TelegramPassport", R.string.TelegramPassport), true); } else if (position == deleteAccountRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 7e8006925..d6380b3a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -36,10 +36,12 @@ import android.database.DataSetObserver; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -64,6 +66,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; +import android.text.style.ReplacementSpan; import android.util.Property; import android.util.SparseIntArray; import android.util.TypedValue; @@ -90,6 +93,7 @@ import android.widget.Toast; import androidx.annotation.Keep; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; @@ -106,6 +110,8 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.google.android.exoplayer2.util.Log; + import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -185,6 +191,7 @@ import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CanvasButton; import org.telegram.ui.Components.ChatActivityInterface; import org.telegram.ui.Components.ChatAvatarContainer; @@ -207,6 +214,7 @@ import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActivity; +import org.telegram.ui.Components.MessagePrivateSeenView; import org.telegram.ui.Components.Paint.PersistColorPalette; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; @@ -226,6 +234,7 @@ import org.telegram.ui.Components.ShareAlert; import org.telegram.ui.Components.SharedMediaLayout; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.StickerEmptyView; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.TimerDrawable; import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.TypefaceSpan; @@ -357,10 +366,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private ActionBarMenuSubItem autoDeleteItem; AutoDeletePopupWrapper autoDeletePopupWrapper; protected float headerShadowAlpha = 1.0f; + private int actionBarBackgroundColor; private TopView topView; private long userId; private long chatId; - private int topicId; + private long topicId; + public boolean saved; private long dialogId; private boolean creatingChat; private boolean userBlocked; @@ -672,7 +683,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return new ProfileActivity(bundle); } - public int getTopicId() { + public long getTopicId() { return topicId; } @@ -859,6 +870,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. currentColor = color; paint.setColor(color); invalidate(); + if (!hasColorById) { + actionBarBackgroundColor = currentColor; + } } } @@ -877,8 +891,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. hasColorById = true; color1 = peerColor.getBgColor1(Theme.isCurrentThemeDark()); color2 = peerColor.getBgColor2(Theme.isCurrentThemeDark()); + actionBarBackgroundColor = ColorUtils.blendARGB(color1, color2, 0.25f); emojiColor = PeerColorActivity.adaptProfileEmojiColor(color1); } else { + actionBarBackgroundColor = currentColor; hasColorById = false; if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { emojiColor = getThemedColor(Theme.key_windowBackgroundWhiteBlueText); @@ -1682,7 +1698,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. public boolean onFragmentCreate() { userId = arguments.getLong("user_id", 0); chatId = arguments.getLong("chat_id", 0); - topicId = arguments.getInt("topic_id", 0); + topicId = arguments.getLong("topic_id", 0); + saved = arguments.getBoolean("saved", false); openSimilar = arguments.getBoolean("similar", false); isTopic = topicId != 0; banFromGroup = arguments.getLong("ban_chat_id", 0); @@ -2109,7 +2126,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override public void onClick(DialogInterface dialog, int which) { ArrayList topicIds = new ArrayList<>(); - topicIds.add(topicId); + topicIds.add((int) topicId); getMessagesController().getTopicsController().deleteTopics(chatId, topicIds); playProfileAnimation = 0; if (parentLayout != null && parentLayout.getFragmentStack() != null) { @@ -2647,6 +2664,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. avatarContainer.setVisibility(View.GONE); avatarsViewPager.resetCurrentItem(); avatarsViewPager.setVisibility(View.VISIBLE); + if (showStatusButton != null) { + showStatusButton.setBackgroundColor(0x23ffffff); + } if (storyView != null) { storyView.setExpandProgress(1f); } @@ -2987,6 +3007,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return mediaHeaderVisible; } + @Override + protected boolean includeSavedDialogs() { + return dialogId == getUserConfig().getClientUserId() && !saved; + } + @Override protected void onSearchStateChanged(boolean expanded) { AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); @@ -3462,7 +3487,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (did != 0) { Bundle args = new Bundle(); args.putLong("dialog_id", did); - args.putInt("topic_id", topicId); + args.putLong("topic_id", topicId); presentFragment(new ProfileNotificationsActivity(args, resourcesProvider)); } } @@ -3696,7 +3721,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").remove("taptostorysoundhint").remove("nothanos").remove("voiceoncehint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").remove("viewoncehint").remove("taptostorysoundhint").remove("nothanos").remove("voiceoncehint").remove("savedhint").apply(); MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; @@ -4396,6 +4421,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. onlineTextView[2].setTextColor(color); onlineTextView[3].setTextColor(color); } + if (showStatusButton != null) { + showStatusButton.setTextColor(Theme.multAlpha(Theme.adaptHSV(color, -.02f, +.15f), 1.4f)); + } } }; } else { @@ -4950,6 +4978,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[1].setScaleX(AndroidUtilities.lerp(1.12f, 1.67f, value)); nameTextView[1].setScaleY(AndroidUtilities.lerp(1.12f, 1.67f, value)); } + if (showStatusButton != null) { + showStatusButton.setBackgroundColor(ColorUtils.blendARGB(Theme.multAlpha(Theme.adaptHSV(actionBarBackgroundColor, +0.18f, -0.1f), 0.5f), 0x23ffffff, currentExpandAnimatorValue)); + } needLayoutText(Math.min(1f, extraHeight / AndroidUtilities.dp(88f))); @@ -6215,6 +6246,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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)); + } else if (id == SharedMediaLayout.TAB_SAVED_MESSAGES) { + int messagesCount = getMessagesController().getSavedMessagesController().getMessagesCount(getDialogId()); + mediaCounterTextView.setText(LocaleController.formatPluralString("SavedMessagesCount", Math.max(1, messagesCount))); } } @@ -6530,6 +6564,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameY = (float) Math.floor(avatarY) + AndroidUtilities.dp(1.3f) + AndroidUtilities.dp(7) * diff + titleAnimationsYDiff * (1f - avatarAnimationProgress); onlineX = -21 * AndroidUtilities.density * diff; onlineY = (float) Math.floor(avatarY) + AndroidUtilities.dp(24) + (float) Math.floor(11 * AndroidUtilities.density) * diff; + if (showStatusButton != null) { + showStatusButton.setAlpha((int) (0xFF * diff)); + } for (int a = 0; a < nameTextView.length; a++) { if (nameTextView[a] == null) { continue; @@ -6692,7 +6729,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[1].requestLayout(); } - width2 = onlineTextView[1].getPaint().measureText(onlineTextView[1].getText().toString()); + width2 = onlineTextView[1].getPaint().measureText(onlineTextView[1].getText().toString()) + onlineTextView[1].getRightDrawableWidth(); layoutParams = (FrameLayout.LayoutParams) onlineTextView[1].getLayoutParams(); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) mediaCounterTextView.getLayoutParams(); prevWidth = layoutParams.width; @@ -7119,6 +7156,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (flagSecure != null) { flagSecure.detach(); } + if (sharedMediaLayout != null) { + sharedMediaLayout.onPause(); + } } @Override @@ -7409,6 +7449,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. nameTextView[1].setTextColor(Color.WHITE); onlineTextView[1].setTextColor(0xB3FFFFFF); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); + if (showStatusButton != null) { + showStatusButton.setBackgroundColor(0x23ffffff); + } overlaysView.setOverlaysVisible(); } for (int a = 0; a < 2; a++) { @@ -7459,7 +7502,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (previousTransitionFragment != null) { ChatAvatarContainer avatarContainer = previousTransitionFragment.getAvatarContainer(); - if (avatarContainer != null && avatarContainer.getSubtitleTextView().getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { + if (avatarContainer != null && avatarContainer.getSubtitleTextView() instanceof SimpleTextView && ((SimpleTextView) avatarContainer.getSubtitleTextView()).getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { transitionOnlineText = avatarContainer.getSubtitleTextView(); avatarContainer2.invalidate(); onlineTextCrosafade = true; @@ -7527,7 +7570,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. BaseFragment previousFragment = parentLayout.getFragmentStack().size() > 1 ? parentLayout.getFragmentStack().get(parentLayout.getFragmentStack().size() - 2) : null; if (previousFragment instanceof ChatActivity) { ChatAvatarContainer avatarContainer = ((ChatActivity) previousFragment).getAvatarContainer(); - if (avatarContainer.getSubtitleTextView().getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { + View subtitleTextView = avatarContainer.getSubtitleTextView(); + if (subtitleTextView instanceof SimpleTextView && ((SimpleTextView) subtitleTextView).getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { transitionOnlineText = avatarContainer.getSubtitleTextView(); avatarContainer2.invalidate(); crossfadeOnlineText = true; @@ -7811,6 +7855,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. break; } } + if (!hasMedia) { + hasMedia = sharedMediaPreloader.hasSavedMessages; + } } if (!hasMedia && userInfo != null) { hasMedia = userInfo.stories_pinned_available; @@ -8286,6 +8333,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. CharSequence newString = UserObject.getUserName(user); String newString2; + boolean hiddenStatusButton = false; if (user.id == getUserConfig().getClientUserId()) { if (UserObject.hasFallbackPhoto(getUserInfo())) { newString2 = ""; @@ -8306,6 +8354,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else { isOnline[0] = false; newString2 = LocaleController.formatUserStatus(currentAccount, user, isOnline, shortStatus ? new boolean[1] : null); + hiddenStatusButton = user != null && !getUserConfig().isPremium() && user.status != null && user.status.by_me; if (onlineTextView[1] != null && !mediaHeaderVisible) { int key = isOnline[0] && peerColor == null ? Theme.key_profile_status : Theme.key_avatar_subtitleInProfileBlue; onlineTextView[1].setTag(key); @@ -8335,6 +8384,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else { onlineTextView[a].setText(newString2); } + onlineTextView[a].setDrawablePadding(dp(9)); + onlineTextView[a].setRightDrawableInside(true); + onlineTextView[a].setRightDrawable(a == 1 && hiddenStatusButton ? getShowStatusButton() : null); + onlineTextView[a].setRightDrawableOnClick(a == 1 && hiddenStatusButton ? v -> { + MessagePrivateSeenView.showSheet(getContext(), currentAccount, dialogId, true, null, () -> { + getMessagesController().reloadUser(dialogId); + }, resourcesProvider); + } : null); Drawable leftIcon = currentEncryptedChat != null ? getLockIconDrawable() : null; boolean rightIconIsPremium = false, rightIconIsStatus = false; nameTextView[a].setRightDrawableOutside(a == 0); @@ -8753,6 +8810,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } onlineTextView[1].setTextColor(ColorUtils.blendARGB(applyPeerColor(statusColor, true, isOnline[0]), 0xB3FFFFFF, currentExpandAnimatorValue)); } + if (showStatusButton != null) { + showStatusButton.setBackgroundColor(ColorUtils.blendARGB(Theme.multAlpha(Theme.adaptHSV(actionBarBackgroundColor, +0.18f, -0.1f), 0.5f), 0x23ffffff, currentExpandAnimatorValue)); + } if (actionBar != null) { actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); @@ -11830,7 +11890,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (playProfileAnimation == 1 && (!fragmentOpened || openAnimationInProgress)) { photoDescriptionProgress = 0; } else if (playProfileAnimation == 2 && (!fragmentOpened || openAnimationInProgress)) { - photoDescriptionProgress = onlineTextView[1].getAlpha(); + photoDescriptionProgress = onlineTextView[1] == null ? 0 : onlineTextView[1].getAlpha(); } else { if (userId == UserConfig.getInstance(currentAccount).clientUserId) { photoDescriptionProgress = currentExpandAnimatorValue * (1f - customAvatarProgress); @@ -12015,4 +12075,99 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. blurredView.setVisibility(View.VISIBLE); } + private ShowDrawable showStatusButton; + public ShowDrawable getShowStatusButton() { + if (showStatusButton == null) { + showStatusButton = new ShowDrawable(); + showStatusButton.setAlpha((int) (0xFF * Math.min(1f, extraHeight / AndroidUtilities.dp(88f)))); + showStatusButton.setBackgroundColor(ColorUtils.blendARGB(Theme.multAlpha(Theme.adaptHSV(actionBarBackgroundColor, +0.18f, -0.1f), 0.5f), 0x23ffffff, currentExpandAnimatorValue)); + } + return showStatusButton; + } + + private static class ShowDrawable extends Drawable implements SimpleTextView.PressableDrawable { + + private final Text text; + public final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public ShowDrawable() { + text = new Text(LocaleController.getString(R.string.StatusHiddenShow), 11); + backgroundPaint.setColor(0x1f000000); + } + + private int textColor; + public void setBackgroundColor(int backgroundColor) { + if (backgroundPaint.getColor() != backgroundColor) { + backgroundPaint.setColor(backgroundColor); + invalidateSelf(); + } + } + public void setTextColor(int textColor) { + if (this.textColor != textColor) { + this.textColor = textColor; + invalidateSelf(); + } + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (alpha <= 0) return; + AndroidUtilities.rectTmp.set(getBounds()); + canvas.save(); + final float s = bounce.getScale(0.1f); + canvas.scale(s, s, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); + final int wasAlpha = backgroundPaint.getAlpha(); + backgroundPaint.setAlpha((int) (wasAlpha * alpha)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(20), dp(20), backgroundPaint); + backgroundPaint.setAlpha(wasAlpha); + text.draw(canvas, AndroidUtilities.rectTmp.left + dp(5.5f), AndroidUtilities.rectTmp.centerY(), textColor, alpha); + canvas.restore(); + } + + private float alpha = 1f; + @Override + public void setAlpha(int alpha) { + this.alpha = alpha / 255f; + invalidateSelf(); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getIntrinsicWidth() { + return (int) (text.getCurrentWidth() + dp(11)); + } + + @Override + public int getIntrinsicHeight() { + return dp(17.33f); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + private boolean pressed; + private final ButtonBounce bounce = new ButtonBounce(null) { + @Override + public void invalidate() { + invalidateSelf(); + } + }; + + @Override + public void setPressed(boolean pressed) { + bounce.setPressed(pressed); + this.pressed = pressed; + } + + @Override + public boolean isPressed() { + return pressed; + } + } + } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index f4f6f2752..07429a045 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -77,7 +77,7 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi private Theme.ResourcesProvider resourcesProvider; private long dialogId; - private int topicId; + private long topicId; private boolean addingException; @@ -132,7 +132,7 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi super(args); this.resourcesProvider = resourcesProvider; dialogId = args.getLong("dialog_id"); - topicId = args.getInt("topic_id"); + topicId = args.getLong("topic_id"); addingException = args.getBoolean("exception", false); } @@ -404,7 +404,7 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi } else if (position == soundRow) { Bundle bundle = new Bundle(); bundle.putLong("dialog_id", dialogId); - bundle.putInt("topic_id", topicId); + bundle.putLong("topic_id", topicId); presentFragment(new NotificationsSoundActivity(bundle, resourcesProvider)); } else if (position == ringtoneRow) { try { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java index 31b0ec364..1a0b32886 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java @@ -17,7 +17,11 @@ import android.graphics.ColorMatrixColorFilter; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -25,29 +29,36 @@ import android.graphics.SurfaceTexture; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.text.Layout; +import android.util.AndroidRuntimeException; import android.view.Gravity; import android.view.KeyEvent; +import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.view.WindowInsetsCompat; +import androidx.recyclerview.widget.ChatListItemAnimator; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.util.Log; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; 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; @@ -58,12 +69,14 @@ import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AudioVisualizerDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EarListener; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SeekBar; import org.telegram.ui.Components.SeekBarWaveform; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.ThanosEffect; +import org.telegram.ui.Components.TimerParticles; import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.Stories.recorder.HintView2; import org.telegram.ui.Stories.recorder.StoryRecorder; @@ -74,8 +87,6 @@ public class SecretVoicePlayer extends Dialog { public final Context context; -// WindowManager windowManager; -// private final WindowManager.LayoutParams windowLayoutParams; private FrameLayout windowView; private FrameLayout containerView; @@ -89,13 +100,15 @@ public class SecretVoicePlayer extends Dialog { private boolean open; private float openProgress; - private float openProgressLinear; + private float openProgress2; private VideoPlayer player; private HintView2 hintView; private TextView closeButton; + private EarListener earListener; + public SecretVoicePlayer(Context context) { super(context, R.style.TransparentDialog); this.context = context; @@ -140,6 +153,7 @@ public class SecretVoicePlayer extends Dialog { } }); containerView = new FrameLayout(context) { + private final Path clipPath = new Path(); @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == myCell || child == hintView) { @@ -149,9 +163,35 @@ public class SecretVoicePlayer extends Dialog { canvas.restore(); return r; } + if (child == textureView) { + canvas.save(); + + clipPath.rewind(); + clipPath.addCircle(myCell.getX() + rect.centerX(), myCell.getY() + rect.centerY(), rect.width() / 2f, Path.Direction.CW); + canvas.clipPath(clipPath); + canvas.clipRect(0, AndroidUtilities.lerp(clipTop, 0, openProgress), getWidth(), AndroidUtilities.lerp(clipBottom, getHeight(), openProgress)); + canvas.translate( + - textureView.getX(), + - textureView.getY() + ); + canvas.translate( + myCell.getX() + rect.left, + myCell.getY() + rect.top + ); + canvas.scale( + rect.width() / textureView.getMeasuredWidth(), + rect.height() / textureView.getMeasuredHeight(), + textureView.getX(), + textureView.getY() + ); + boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } return super.drawChild(canvas, child, drawingTime); } }; + containerView.setClipToPadding(false); windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); if (Build.VERSION.SDK_INT >= 21) { @@ -177,6 +217,9 @@ public class SecretVoicePlayer extends Dialog { }); } + if (SharedConfig.raiseToListen) { + earListener = new EarListener(context); + } } private void prepareBlur(View withoutView) { @@ -221,7 +264,9 @@ public class SecretVoicePlayer extends Dialog { WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; } - params.flags |= WindowManager.LayoutParams.FLAG_SECURE; + if (!BuildVars.DEBUG_PRIVATE_VERSION) { + params.flags |= WindowManager.LayoutParams.FLAG_SECURE; + } params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; if (Build.VERSION.SDK_INT >= 28) { @@ -233,28 +278,28 @@ public class SecretVoicePlayer extends Dialog { AndroidUtilities.setLightNavigationBar(windowView, !Theme.isCurrentThemeDark()); } - private Theme.ResourcesProvider resourcesProvider; - private MessageObject messageObject; - private ChatMessageCell myCell; - private ChatMessageCell cell; - private float tx, ty; private boolean hasTranslation; private float dtx, dty; private boolean hasDestTranslation; + private float heightdiff; private void setupTranslation() { if (hasTranslation || windowView.getWidth() <= 0) return; if (cell != null) { int[] loc = new int[2]; cell.getLocationOnScreen(loc); tx = loc[0] - insets.left - (windowView.getWidth() - insets.left - insets.right - cell.getWidth()) / 2f; - ty = loc[1] - insets.top - (windowView.getHeight() - insets.top - insets.bottom - cell.getHeight()) / 2f; + ty = loc[1] - insets.top - (windowView.getHeight() - insets.top - insets.bottom - cell.getHeight() - heightdiff) / 2f; if (!hasDestTranslation) { hasDestTranslation = true; dtx = 0; float cy = Utilities.clamp(loc[1] + cell.getHeight() / 2f, windowView.getHeight() * .7f, windowView.getHeight() * .3f); dty = cy - cell.getHeight() / 2f - (windowView.getHeight() - cell.getHeight()) / 2f; - dty = AndroidUtilities.lerp(0, dty, .78f); + if (isRound) { + dty = 0; + } else { + dty = AndroidUtilities.lerp(0, dty, .78f); + } } updateTranslation(); } else { @@ -272,11 +317,21 @@ public class SecretVoicePlayer extends Dialog { } } + private Theme.ResourcesProvider resourcesProvider; + private MessageObject messageObject; + private ChatMessageCell myCell; + private ChatMessageCell cell; + private TextureView textureView; + private boolean renderedFirstFrame; + private final RectF rect = new RectF(); + private boolean isRound; + private float clipTop = 0, clipBottom = 0; private AudioVisualizerDrawable audioVisualizerDrawable; private boolean setCellInvisible; private Runnable openAction, closeAction; + public void setCell(ChatMessageCell messageCell, Runnable openAction, Runnable closeAction) { this.openAction = openAction; this.closeAction = closeAction; @@ -286,7 +341,9 @@ public class SecretVoicePlayer extends Dialog { } cell = messageCell; messageObject = cell != null ? cell.getMessageObject() : null; + isRound = messageObject != null && messageObject.isRoundVideo(); resourcesProvider = cell != null ? cell.getResourcesProvider() : null; + int videoDp = 360; if (cell != null) { clipTop = messageCell.parentBoundsTop; @@ -297,10 +354,181 @@ public class SecretVoicePlayer extends Dialog { clipBottom += parent.getY(); } + int width = cell.getWidth(); + int height = cell.getHeight(); + if (isRound) { + height = (int) Math.min(dp(360), Math.min(width, AndroidUtilities.displaySize.y)); + } + heightdiff = height - cell.getHeight(); + final int finalWidth = width; + final int finalHeight = height; + videoDp = (int) Math.ceil(Math.min(width, height) * .92f / AndroidUtilities.density); + myCell = new ChatMessageCell(getContext(), false, null, cell.getResourcesProvider()) { + + @Override + public int getBoundsLeft() { + return 0; + } + + @Override + public int getBoundsRight() { + return getWidth(); + } + @Override public void setPressed(boolean pressed) {} + + private boolean setRect = false; + final RectF fromRect = new RectF(); + final RectF toRect = new RectF(); + + private RadialGradient radialGradient; + private Paint radialPaint; + private Matrix radialMatrix; + + @Override + protected void onDraw(Canvas canvas) { + if (isRound) { + if (!setRect) { + fromRect.set(getPhotoImage().getImageX(), getPhotoImage().getImageY(), getPhotoImage().getImageX2(), getPhotoImage().getImageY2()); + final float sz = Math.min(getMeasuredWidth(), getMeasuredHeight()) * .92f; + toRect.set((getMeasuredWidth() - sz) / 2f, (getMeasuredHeight() - sz) / 2f, (getMeasuredWidth() + sz) / 2f, (getMeasuredHeight() + sz) / 2f); + setRect = true; + + radialGradient = new RadialGradient(0, 0, 48, new int[] { 0xffffffff, 0xffffffff, 0 }, new float[] { 0, 0.8f, 1 }, Shader.TileMode.CLAMP); + radialPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + radialPaint.setShader(radialGradient); + radialPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + radialMatrix = new Matrix(); + } + + AndroidUtilities.lerp(fromRect, toRect, openProgress, rect); + setImageCoords(rect.left, rect.top, rect.width(), rect.height()); + getPhotoImage().setRoundRadius((int) rect.width()); + + if (openProgress > 0 && renderedFirstFrame) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + } + + radialProgressAlpha = 1f - openProgress; + } + super.onDraw(canvas); + if (isRound && openProgress > 0 && renderedFirstFrame) { + canvas.restore(); + } + } + + @Override + public void drawTime(Canvas canvas, float alpha, boolean fromParent) { + canvas.save(); + if (isRound) { + final float timeWidth = this.timeWidth + AndroidUtilities.dp(8 + (messageObject != null && messageObject.isOutOwner() ? 20 + (messageObject != null && messageObject.type == MessageObject.TYPE_EMOJIS ? 4 : 0) : 0)); + canvas.translate((toRect.right - timeWidth - timeX) * openProgress, 0); + } + super.drawTime(canvas, alpha, fromParent); + canvas.restore(); + } + + @Override + protected void drawRadialProgress(Canvas canvas) { + super.drawRadialProgress(canvas); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (textureView != null && visibility == View.GONE) { + textureView.setVisibility(visibility); + } + } + + private Path clipPath = new Path(); + private Paint clipPaint; + private Paint progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private TimerParticles timerParticles; + private AnimatedFloat renderedFirstFrameT = new AnimatedFloat(0, this, 0, 120, new LinearInterpolator()); + + private Paint getClipPaint() { + if (clipPaint == null) { + clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + return clipPaint; + } + + @Override + public void drawBlurredPhoto(Canvas canvas) { + if (radialPaint != null) { + if (openProgress > 0) { + if (renderedFirstFrame) { + if (drawingToBitmap) { + Bitmap bitmap = textureView.getBitmap(); + if (bitmap != null) { + canvas.save(); + clipPath.rewind(); + clipPath.addCircle(rect.centerX(), rect.centerY(), rect.width() / 2f, Path.Direction.CW); + canvas.clipPath(clipPath); + canvas.scale(rect.width() / bitmap.getWidth(), rect.height() / bitmap.getHeight()); + canvas.translate(rect.left, rect.top); + canvas.drawBitmap(bitmap, 0, 0, null); + canvas.restore(); + bitmap.recycle(); + } + } else { + canvas.drawCircle(rect.centerX(), rect.centerY(), rect.width() / 2f, getClipPaint()); + } + getPhotoImage().setAlpha(Math.max(1f - renderedFirstFrameT.set(renderedFirstFrame), 1f - openProgress)); + getPhotoImage().draw(canvas); + } else { + getPhotoImage().draw(canvas); + } + } + radialMatrix.reset(); + final float s = rect.width() / (96f * 0.8f) * openProgress2; + radialMatrix.postScale(s, s); + radialMatrix.postTranslate(rect.centerX(), rect.centerY()); + radialGradient.setLocalMatrix(radialMatrix); + canvas.saveLayerAlpha(rect, 0xFF, Canvas.ALL_SAVE_FLAG); + super.drawBlurredPhoto(canvas); + canvas.save(); + canvas.drawRect(rect, radialPaint); + canvas.restore(); + canvas.restore(); + } else { + super.drawBlurredPhoto(canvas); + } + canvas.saveLayerAlpha(rect, (int) (0xB2 * openProgress2), Canvas.ALL_SAVE_FLAG); + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setStrokeWidth(dp(3.33f)); + progressPaint.setColor(0xffffffff); + progressPaint.setStrokeCap(Paint.Cap.ROUND); + AndroidUtilities.rectTmp.set(rect); + AndroidUtilities.rectTmp.inset(dp(7), dp(7)); + canvas.drawArc(AndroidUtilities.rectTmp, -90, -360 * (1f - progress), false, progressPaint); + if (timerParticles == null) { + timerParticles = new TimerParticles(120); + timerParticles.big = true; + } + progressPaint.setStrokeWidth(dp(2.8f)); + timerParticles.draw(canvas, progressPaint, AndroidUtilities.rectTmp, (1f - progress) * -360, 1f); + canvas.restore(); + } + + @Override + public void drawBlurredPhotoParticles(Canvas canvas) { + final float s = AndroidUtilities.lerp(1, 1.5f, openProgress2); +// canvas.scale(s, s, rect.centerX(), rect.centerY()); + super.drawBlurredPhotoParticles(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(finalWidth, finalHeight); + } }; + cell.copyVisiblePartTo(myCell); + myCell.copySpoilerEffect2AttachIndexFrom(cell); myCell.setDelegate(new ChatMessageCell.ChatMessageCellDelegate() { @Override public boolean canPerformActions() { @@ -308,14 +536,26 @@ public class SecretVoicePlayer extends Dialog { } }); myCell.setMessageObject(messageObject, cell.getCurrentMessagesGroup(), cell.pinnedBottom, cell.pinnedTop); - audioVisualizerDrawable = new AudioVisualizerDrawable(); - audioVisualizerDrawable.setParentView(myCell); - myCell.overrideAudioVisualizer(audioVisualizerDrawable); - if (myCell.getSeekBarWaveform() != null) { - myCell.getSeekBarWaveform().setExplosionRate(openProgressLinear); + if (!isRound) { + audioVisualizerDrawable = new AudioVisualizerDrawable(); + audioVisualizerDrawable.setParentView(myCell); + myCell.overrideAudioVisualizer(audioVisualizerDrawable); + if (myCell.getSeekBarWaveform() != null) { + myCell.getSeekBarWaveform().setExplosionRate(openProgress); + } } hasTranslation = false; - containerView.addView(myCell, new FrameLayout.LayoutParams(cell.getWidth(), cell.getHeight(), Gravity.CENTER)); + containerView.addView(myCell, new FrameLayout.LayoutParams(cell.getWidth(), height, Gravity.CENTER)); + } + + if (textureView != null) { + containerView.removeView(textureView); + textureView = null; + } + if (isRound) { + renderedFirstFrame = false; + textureView = new TextureView(context); + containerView.addView(textureView, 0, LayoutHelper.createFrame(videoDp, videoDp)); } MediaController.getInstance().pauseByRewind(); @@ -327,13 +567,19 @@ public class SecretVoicePlayer extends Dialog { } if (cell != null && cell.getMessageObject() != null) { File file = FileLoader.getInstance(cell.getMessageObject().currentAccount).getPathToAttach(cell.getMessageObject().getDocument()); + if (file != null && !file.exists()) { + file = new File(file.getPath() + ".enc"); + } if (file == null || !file.exists()) { file = FileLoader.getInstance(cell.getMessageObject().currentAccount).getPathToMessage(cell.getMessageObject().messageOwner); + if (file != null && !file.exists()) { + file = new File(file.getPath() + ".enc"); + } } if ((file == null || !file.exists()) && (cell.getMessageObject().messageOwner.attachPath != null)) { file = new File(cell.getMessageObject().messageOwner.attachPath); } - if (file == null) { + if (file == null || !file.exists()) { return; } player = new VideoPlayer(); @@ -360,7 +606,10 @@ public class SecretVoicePlayer extends Dialog { @Override public void onRenderedFirstFrame() { - + AndroidUtilities.runOnUIThread(() -> { + renderedFirstFrame = true; + myCell.invalidate(); + }); } @Override @@ -373,19 +622,27 @@ public class SecretVoicePlayer extends Dialog { return false; } }); - player.setAudioVisualizerDelegate(new VideoPlayer.AudioVisualizerDelegate() { - @Override - public void onVisualizerUpdate(boolean playing, boolean animate, float[] values) { - audioVisualizerDrawable.setWaveform(playing, animate, values); - } + if (audioVisualizerDrawable != null) { + player.setAudioVisualizerDelegate(new VideoPlayer.AudioVisualizerDelegate() { + @Override + public void onVisualizerUpdate(boolean playing, boolean animate, float[] values) { + audioVisualizerDrawable.setWaveform(playing, animate, values); + } - @Override - public boolean needUpdate() { - return audioVisualizerDrawable.getParentView() != null; - } - }); + @Override + public boolean needUpdate() { + return audioVisualizerDrawable.getParentView() != null; + } + }); + } + if (isRound) { + player.setTextureView(textureView); + } player.preparePlayer(Uri.fromFile(file), "other"); player.play(); + if (earListener != null) { + earListener.attachPlayer(player); + } } if (hintView != null) { @@ -410,16 +667,26 @@ public class SecretVoicePlayer extends Dialog { name = chat.title; } } - hintView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.VoiceOnceOutHint, name))); + hintView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(isRound ? R.string.VideoOnceOutHint : R.string.VoiceOnceOutHint, name))); } else { - hintView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.VoiceOnceHint))); + hintView.setText(AndroidUtilities.replaceTags(LocaleController.getString(isRound ? R.string.VideoOnceHint : R.string.VoiceOnceHint))); } hintView.setRounding(12); hintView.setPadding(dp(!isOut && !cell.pinnedBottom ? 6 : 0), 0, 0, 0); - hintView.setJointPx(0, dp(34)); + if (isRound) { + hintView.setJointPx(0.5f, 0); + hintView.setTextAlign(Layout.Alignment.ALIGN_CENTER); + } else { + hintView.setJointPx(0, dp(34)); + hintView.setTextAlign(Layout.Alignment.ALIGN_NORMAL); + } hintView.setTextSize(14); hintView.setMaxWidthPx(HintView2.cutInFancyHalf(hintView.getText(), hintView.getTextPaint())); - containerView.addView(hintView, LayoutHelper.createFrame((int) (cell.getWidth() / AndroidUtilities.density * .6f), 150, Gravity.CENTER, (cell.getWidth() * -(1f - .6f) / 2f + cell.getBoundsLeft()) / AndroidUtilities.density + 1, -75 - (cell.getHeight() / AndroidUtilities.density) / 2f - 8, 0, 0)); + if (isRound) { + containerView.addView(hintView, LayoutHelper.createFrame((int) (cell.getWidth() / AndroidUtilities.density * .6f), 150, Gravity.CENTER, 0, -75 - ((cell.getHeight() + heightdiff) / AndroidUtilities.density) / 2f, 0, 0)); + } else { + containerView.addView(hintView, LayoutHelper.createFrame((int) (cell.getWidth() / AndroidUtilities.density * .6f), 150, Gravity.CENTER, (cell.getWidth() * -(1f - .6f) / 2f + cell.getBoundsLeft()) / AndroidUtilities.density + 1, -75 - (cell.getHeight() / AndroidUtilities.density) / 2f - 8, 0, 0)); + } hintView.show(); } @@ -461,14 +728,20 @@ public class SecretVoicePlayer extends Dialog { AndroidUtilities.runOnUIThread(this.openAction); this.openAction = null; } + + if (earListener != null) { + earListener.attach(); + } } private Runnable checkTimeRunnable = this::checkTime; + private float progress = 0; + private void checkTime() { if (player == null) { return; } - float progress = player.getCurrentPosition() / (float) player.getDuration(); + progress = player.getCurrentPosition() / (float) player.getDuration(); if (myCell != null) { myCell.overrideDuration((player.getDuration() - player.getCurrentPosition()) / 1000L); myCell.updatePlayingMessageProgress(); @@ -500,8 +773,8 @@ public class SecretVoicePlayer extends Dialog { } if (!dismissing && messageObject != null && !messageObject.isOutOwner()) { backDialog = new AlertDialog.Builder(getContext(), resourcesProvider) - .setTitle(LocaleController.getString(R.string.VoiceOnceCloseTitle)) - .setMessage(LocaleController.getString(R.string.VoiceOnceCloseMessage)) + .setTitle(LocaleController.getString(isRound ? R.string.VideoOnceCloseTitle : R.string.VoiceOnceCloseTitle)) + .setMessage(LocaleController.getString(isRound ? R.string.VideoOnceCloseMessage : R.string.VoiceOnceCloseMessage)) .setPositiveButton(LocaleController.getString(R.string.Continue), (di, w) -> { if (backDialog != null) { backDialog.dismiss(); @@ -541,8 +814,8 @@ public class SecretVoicePlayer extends Dialog { player.releasePlayer(true); player = null; } - if (myCell != null && myCell.getSeekBarWaveform() != null) { - myCell.getSeekBarWaveform().setExplosionRate(openProgressLinear); + if (!isRound && myCell != null && myCell.getSeekBarWaveform() != null) { + myCell.getSeekBarWaveform().setExplosionRate(openProgress); } hasTranslation = false; setupTranslation(); @@ -550,8 +823,8 @@ public class SecretVoicePlayer extends Dialog { if (thanosEffect == null) { AndroidUtilities.runOnUIThread(super::dismiss); if (cell != null) { - cell.invalidate(); cell.setVisibility(View.VISIBLE); + cell.invalidate(); } } @@ -560,64 +833,103 @@ public class SecretVoicePlayer extends Dialog { windowView.invalidate(); if (this.closeAction != null) { + if (cell != null) { + cell.makeVisibleAfterChange = true; +// AndroidUtilities.runOnUIThread(() -> { +// cell.makeVisibleAfterChange = false; +// cell.setVisibility(View.VISIBLE); +// cell.invalidate(); +// }, ChatListItemAnimator.DEFAULT_DURATION); + } + AndroidUtilities.runOnUIThread(this.closeAction); this.closeAction = null; + myCell.setInvalidateCallback(() -> {}); thanosEffect = new ThanosEffect(context, null); windowView.addView(thanosEffect, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); - thanosEffect.animate(myCell, () -> { - super.dismiss(); - if (cell != null) { - cell.setVisibility(View.VISIBLE); - cell.invalidate(); - } - }); + thanosEffect.animate(myCell, 1.5f, super::dismiss); WindowManager.LayoutParams params = getWindow().getAttributes(); params.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; getWindow().setAttributes(params); } + + if (earListener != null) { + earListener.detach(); + } } private ValueAnimator openAnimator; + private ValueAnimator open2Animator; private void animateOpenTo(boolean open, Runnable after) { if (openAnimator != null) { openAnimator.cancel(); } + if (open2Animator != null) { + open2Animator.cancel(); + } setupTranslation(); - openAnimator = ValueAnimator.ofFloat(openProgressLinear, open ? 1 : 0); + openAnimator = ValueAnimator.ofFloat(openProgress, open ? 1 : 0); openAnimator.addUpdateListener(anm -> { - openProgressLinear = (float) anm.getAnimatedValue(); - openProgress = open ? CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(openProgressLinear) : 1f - CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(1f - openProgressLinear); + openProgress = (float) anm.getAnimatedValue(); windowView.invalidate(); containerView.invalidate(); + if (isRound) { + myCell.invalidate(); + } updateTranslation(); if (closeButton != null) { closeButton.setAlpha(openProgress); } - if (myCell != null && myCell.getSeekBarWaveform() != null) { - myCell.getSeekBarWaveform().setExplosionRate((open ? CubicBezierInterpolator.EASE_OUT : CubicBezierInterpolator.EASE_IN).getInterpolation(Utilities.clamp(openProgressLinear * 1.25f, 1f, 0f))); + if (!isRound && myCell != null && myCell.getSeekBarWaveform() != null) { + myCell.getSeekBarWaveform().setExplosionRate((open ? CubicBezierInterpolator.EASE_OUT : CubicBezierInterpolator.EASE_IN).getInterpolation(Utilities.clamp(openProgress * 1.25f, 1f, 0f))); } }); openAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - openProgress = openProgressLinear = open ? 1 : 0; + openProgress = open ? 1 : 0; windowView.invalidate(); containerView.invalidate(); updateTranslation(); if (closeButton != null) { closeButton.setAlpha(openProgress); } - if (myCell != null && myCell.getSeekBarWaveform() != null) { - myCell.getSeekBarWaveform().setExplosionRate(openProgressLinear); + if (isRound) { + myCell.invalidate(); + } + if (!isRound && myCell != null && myCell.getSeekBarWaveform() != null) { + myCell.getSeekBarWaveform().setExplosionRate(openProgress); } if (after != null) { after.run(); } } }); - openAnimator.setDuration(!open && closeAction == null ? 330 : 520); + final long duration = !open && closeAction == null ? 330 : 520; + openAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + openAnimator.setDuration(duration); openAnimator.start(); + + open2Animator = ValueAnimator.ofFloat(openProgress2, open ? 1 : 0); + open2Animator.addUpdateListener(anm -> { + openProgress2 = (float) anm.getAnimatedValue(); + if (isRound) { + myCell.invalidate(); + } + }); + open2Animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + openProgress2 = open ? 1 : 0; + if (isRound) { + myCell.invalidate(); + } + } + }); + open2Animator.setDuration((long) (1.5f * duration)); + open2Animator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + open2Animator.start(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 536b08afc..04c665a52 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -286,7 +286,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente if (recentPostsAll.size() > 0) { 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); + getMessagesStorage().getMessages(-chatId, 0, false, count, lastPostId, 0, 0, classGuid, 0, 0, 0, 0, true, false, null); } AndroidUtilities.runOnUIThread(() -> { @@ -2212,7 +2212,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente for (int i = 0; i < messages.size(); i++) { messageObjects.add(new MessageObject(currentAccount, messages.get(i), false, true)); } - getMessagesStorage().putMessages(messages, false, true, true, 0, false, 0); + getMessagesStorage().putMessages(messages, false, true, true, 0, 0, 0); } AndroidUtilities.runOnUIThread(() -> { 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 1aa07b023..b84e451e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -35,6 +35,7 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.URLSpan; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -122,6 +123,7 @@ import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatActivityEnterView; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; +import org.telegram.ui.Components.ChatGreetingsView; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -132,6 +134,7 @@ import org.telegram.ui.Components.EmojiPacksAlert; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.InstantCameraView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.MentionsContainerView; @@ -260,6 +263,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private long dialogId; boolean isSelf; boolean isChannel; + boolean isPremiumBlocked; private float alpha = 1f; private int previousSelectedPotision = -1; @@ -280,6 +284,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica ChatActivityEnterView chatActivityEnterView; private ValueAnimator changeBoundAnimator; ReactionsContainerLayout reactionsContainerLayout; + private LinearLayout premiumBlockedText; + private TextView premiumBlockedText1; + private TextView premiumBlockedText2; private StoryFailView failView; private ViewPropertyAnimator failViewAnimator; @@ -2027,6 +2034,75 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica addView(failView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 0)); } + private void createPremiumBlockedText() { + if (premiumBlockedText != null) { + return; + } + if (chatActivityEnterView == null) { + createEnterView(); + } + premiumBlockedText = new LinearLayout(getContext()); + premiumBlockedText.setOrientation(LinearLayout.HORIZONTAL); + + ImageView imageView = new ImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setScaleX(1.35f); + imageView.setScaleY(1.35f); + imageView.setImageResource(R.drawable.mini_switch_lock); + imageView.setColorFilter(new PorterDuffColorFilter(0xFF858585, PorterDuff.Mode.SRC_IN)); + + premiumBlockedText1 = new TextView(getContext()); + premiumBlockedText1.setTextColor(0xFF858585); + premiumBlockedText1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + premiumBlockedText1.setText(LocaleController.getString(R.string.StoryRepliesLocked)); + + premiumBlockedText2 = new TextView(getContext()); + premiumBlockedText2.setTextColor(0xFFFFFFFF); + premiumBlockedText2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + premiumBlockedText2.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(40), 0x1affffff, 0x32ffffff)); + premiumBlockedText2.setGravity(Gravity.CENTER); + ScaleStateListAnimator.apply(premiumBlockedText2); + premiumBlockedText2.setText(LocaleController.getString(R.string.StoryRepliesLockedButton)); + premiumBlockedText2.setPadding(dp(7), 0, dp(7), 0); + + premiumBlockedText.addView(imageView, LayoutHelper.createLinear(22, 22, Gravity.CENTER_VERTICAL, 12, 1, 4, 0)); + premiumBlockedText.addView(premiumBlockedText1, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + premiumBlockedText.addView(premiumBlockedText2, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 19, Gravity.CENTER_VERTICAL, 5, 0, 0, 0)); + + chatActivityEnterView.addView(premiumBlockedText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + private void updatePremiumBlockedText() { + if (premiumBlockedText1 != null) { + premiumBlockedText1.setText(LocaleController.getString(R.string.StoryRepliesLocked)); + } + if (premiumBlockedText2 != null) { + premiumBlockedText2.setText(LocaleController.getString(R.string.StoryRepliesLockedButton)); + } + } + + private void showPremiumBlockedToast() { + AndroidUtilities.shakeViewSpring(chatActivityEnterView, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + String username = ""; + if (dialogId >= 0) { + username = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(dialogId)); + } + Bulletin bulletin; + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { + bulletin = BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedRepliesNonPremium, username))); + } else { + bulletin = BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.replaceTags(LocaleController.formatString(R.string.UserBlockedRepliesNonPremium, username)), LocaleController.getString(R.string.UserBlockedNonPremiumButton), () -> { + if (storyViewer != null) { + storyViewer.presentFragment(new PremiumPreviewFragment("noncontacts")); + } + }); + } + bulletin.show(); + } + private void createEnterView() { Theme.ResourcesProvider emojiResourceProvider = new WrappedResourceProvider(resourcesProvider) { @Override @@ -2036,6 +2112,41 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }; chatActivityEnterView = new ChatActivityEnterView(AndroidUtilities.findActivity(getContext()), this, null, true, emojiResourceProvider) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (!isEnabled()) { + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + boolean hit = AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY()); + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (hit && premiumBlockedText2 != null) { + premiumBlockedText2.setPressed(true); + } + } else if (ev.getAction() == MotionEvent.ACTION_UP) { + if (premiumBlockedText2 != null) { + if (hit && premiumBlockedText2.isPressed()) { + showPremiumBlockedToast(); + } + premiumBlockedText2.setPressed(false); + } + } else if (ev.getAction() == MotionEvent.ACTION_CANCEL) { + if (premiumBlockedText2 != null) { + premiumBlockedText2.setPressed(false); + } + } + return premiumBlockedText2 != null && premiumBlockedText2.isPressed(); + } + return super.dispatchTouchEvent(ev); + } + + @Override + public void setHorizontalPadding(float padding, float progress, boolean allowShare) { + float leftPadding = -padding * (1f - progress); + if (premiumBlockedText != null) { + premiumBlockedText.setTranslationX(-leftPadding); + } + super.setHorizontalPadding(padding, progress, allowShare); + } + private Animator messageEditTextAnimator; private int chatActivityEnterViewAnimateFromTop; int lastContentViewHeight; @@ -2136,12 +2247,15 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } private void checkRecording() { - isRecording = chatActivityEnterView.isRecordingAudioVideo() || (recordedAudioPanel != null && recordedAudioPanel.getVisibility() == View.VISIBLE); - if (isActive) { - delegate.setIsRecording(isRecording); + final boolean wasRecording = isRecording; + isRecording = chatActivityEnterView.isRecordingAudioVideo() || chatActivityEnterView.seekbarVisible() || (recordedAudioPanel != null && recordedAudioPanel.getVisibility() == View.VISIBLE); + if (wasRecording != isRecording) { + if (isActive) { + delegate.setIsRecording(isRecording); + } + invalidate(); + storyContainer.invalidate(); } - invalidate(); - storyContainer.invalidate(); } @Override @@ -2227,7 +2341,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica checkInstantCameraView(); if (instantCameraView != null) { if (state == 0) { - instantCameraView.showCamera(); + instantCameraView.showCamera(false); } else if (state == 1 || state == 3 || state == 4) { instantCameraView.send(state, notify, scheduleDate, ttl); } else if (state == 2 || state == 5) { @@ -2236,6 +2350,13 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } + @Override + public void toggleVideoRecordingPause() { + if (instantCameraView != null) { + instantCameraView.togglePause(); + } + } + @Override public void needChangeVideoPreviewState(int state, float seekProgress) { if (instantCameraView != null) { @@ -2294,6 +2415,16 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica return currentStory.storyItem; } + @Override + public boolean onceVoiceAvailable() { + TLRPC.User user = null; + if (dialogId >= 0) { + user = MessagesController.getInstance(currentAccount).getUser(dialogId); + } else { + return false; + } + return user != null && !UserObject.isUserSelf(user) && !user.bot; + } }); setDelegate(chatActivityEnterView); chatActivityEnterView.shouldDrawBackground = false; @@ -2827,6 +2958,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); + isPremiumBlocked = !UserConfig.getInstance(currentAccount).isPremium() && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(dialogId); avatarDrawable.setInfo(currentAccount, user); headerView.backupImageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); if (isSelf) { @@ -2854,6 +2986,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else { isSelf = false; isChannel = true; + isPremiumBlocked = false; if (storiesController.canEditStories(dialogId) || BuildVars.DEBUG_PRIVATE_VERSION) { userCanSeeViews = true; @@ -2949,6 +3082,15 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (chatActivityEnterView == null) { createEnterView(); } + if (isPremiumBlocked && premiumBlockedText == null) { + createPremiumBlockedText(); + } + if (premiumBlockedText != null) { + if (isPremiumBlocked) { + updatePremiumBlockedText(); + } + premiumBlockedText.setVisibility(isPremiumBlocked ? View.VISIBLE : View.GONE); + } if (failView != null) { failView.setVisibility(View.GONE); } @@ -3310,6 +3452,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesListUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.stealthModeChanged); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesLimitUpdate); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); } @@ -3341,6 +3484,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesListUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.stealthModeChanged); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesLimitUpdate); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.userIsPremiumBlockedUpadted); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); } @@ -3419,6 +3563,12 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } }, activity, storyLimit.getLimitReachedType(), currentAccount, null); delegate.showDialog(sheet); + } else if (id == NotificationCenter.userIsPremiumBlockedUpadted) { + boolean wasPremiumBlocked = isPremiumBlocked; + isPremiumBlocked = dialogId >= 0 && !UserConfig.getInstance(currentAccount).isPremium() && MessagesController.getInstance(currentAccount).isUserPremiumBlocked(dialogId); + if (isPremiumBlocked != wasPremiumBlocked) { + updatePosition(); + } } } @@ -3430,13 +3580,18 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } AndroidUtilities.cancelRunOnUIThread(updateStealthModeTimer); TL_stories.TL_storiesStealthMode stealthMode = storiesController.getStealthMode(); - if (stealthMode != null && ConnectionsManager.getInstance(currentAccount).getCurrentTime() < stealthMode.active_until_date) { + if (isPremiumBlocked) { + stealthModeIsActive = false; + chatActivityEnterView.setEnabled(false); + chatActivityEnterView.setOverrideHint(" ", animated); + } else if (stealthMode != null && ConnectionsManager.getInstance(currentAccount).getCurrentTime() < stealthMode.active_until_date) { stealthModeIsActive = true; int time = stealthMode.active_until_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); int minutes = time / 60; int seconds = time % 60; String textToMeasure = LocaleController.formatString("StealthModeActiveHint", R.string.StealthModeActiveHintShort, String.format(Locale.US, "%02d:%02d", 99, 99)); int w = (int) chatActivityEnterView.getEditField().getPaint().measureText(textToMeasure); + chatActivityEnterView.setEnabled(true); if (w * 1.2f >= chatActivityEnterView.getEditField().getMeasuredWidth()) { chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHintShort", R.string.StealthModeActiveHintShort, ""), String.format(Locale.US, "%02d:%02d", minutes, seconds), animated); } else { @@ -3445,6 +3600,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica AndroidUtilities.runOnUIThread(updateStealthModeTimer, 1000); } else { stealthModeIsActive = false; + chatActivityEnterView.setEnabled(true); chatActivityEnterView.setOverrideHint(LocaleController.getString("ReplyPrivately", R.string.ReplyPrivately), animated); } } @@ -3764,24 +3920,42 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (selfView != null) { selfView.setVisibility(View.GONE); } + if (bottomActionsLinearLayout != null) { + bottomActionsLinearLayout.setVisibility(View.VISIBLE); + } } else { if (UserObject.isService(dialogId) && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); } else if (!isSelf && !isChannel && chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); } + if (isPremiumBlocked && premiumBlockedText == null) { + createPremiumBlockedText(); + } + if (premiumBlockedText != null) { + if (isPremiumBlocked) { + updatePremiumBlockedText(); + } + premiumBlockedText.setVisibility(isPremiumBlocked ? View.VISIBLE : View.GONE); + } + if (chatActivityEnterView != null) { + chatActivityEnterView.setEnabled(!isPremiumBlocked); + } if (isSelf && selfView != null) { selfView.setVisibility(View.VISIBLE); } if (unsupportedContainer != null) { unsupportedContainer.setVisibility(View.GONE); } - if (UserObject.isService(dialogId)){ + if (UserObject.isService(dialogId)) { createReplyDisabledView(); replyDisabledTextView.setVisibility(View.VISIBLE); } else if (replyDisabledTextView != null) { replyDisabledTextView.setVisibility(View.GONE); } + if (bottomActionsLinearLayout != null) { + bottomActionsLinearLayout.setVisibility(View.VISIBLE); + } } if ((currentStory.caption != null || currentStory.getReply() != null) && !unsupported) { @@ -5638,7 +5812,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica child.setScaleY(s); } else { child.setTranslationY(translationY); - child.setAlpha(alpha); + if (chatActivityEnterView == null || child != chatActivityEnterView.controlsView) { + child.setAlpha(alpha); + } } } } @@ -5801,7 +5977,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }, resourcesProvider); instantCameraView.drawBlur = false; - int i = indexOfChild(chatActivityEnterView.getRecordCircle()); + int i = Math.min(indexOfChild(chatActivityEnterView.getRecordCircle()), indexOfChild(chatActivityEnterView.controlsView)); addView(instantCameraView, i, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); } 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 7852c3a55..14523dd6e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -1342,7 +1342,7 @@ public class StoryCaptionView extends NestedScrollView { verticalPadding = dp(8); if (sizeCached != size) { sizeCached = size; - int width = MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding * 2; + int width = Math.max(0, MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding * 2); state[0].measure(width); if (state[1] != null) { state[1].measure(width); 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 d1a9c3d8e..22092b5e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -862,7 +862,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat override = true; } } - if (peerStoriesView != null && selfStoriesViewsOffset == 0 && !inSwipeToDissmissMode && !isCaption && storiesViewPager.currentState != ViewPager.SCROLL_STATE_DRAGGING) { + if (peerStoriesView != null && selfStoriesViewsOffset == 0 && !inSwipeToDissmissMode && !isCaption && !isRecording && storiesViewPager.currentState != ViewPager.SCROLL_STATE_DRAGGING) { AndroidUtilities.getViewPositionInParent(peerStoriesView.storyContainer, this, pointPosition); ev.offsetLocation(-pointPosition[0], -pointPosition[1]); storiesViewPager.getCurrentPeerView().checkPinchToZoom(ev); @@ -900,14 +900,14 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat startX = lastTouchX = ev.getX(); startY = ev.getY(); verticalScrollDetected = false; - allowIntercept = !findClickableView(windowView, ev.getX(), ev.getY(), false); - allowSwipeToDissmiss = !findClickableView(windowView, ev.getX(), ev.getY(), true); + allowIntercept = !isRecording && !findClickableView(windowView, ev.getX(), ev.getY(), false); + allowSwipeToDissmiss = !isRecording && !findClickableView(windowView, ev.getX(), ev.getY(), true); setInTouchMode(allowIntercept && !isCaptionPartVisible); - if (allowIntercept && isCaptionPartVisible) { + if (allowIntercept && !isRecording && isCaptionPartVisible) { delayedTapRunnable = () -> setInTouchMode(true); AndroidUtilities.runOnUIThread(delayedTapRunnable, 150); } - if (allowIntercept && !keyboardVisible && !isInTextSelectionMode) { + if (allowIntercept && !keyboardVisible && !isRecording && !isInTextSelectionMode) { AndroidUtilities.runOnUIThread(longPressRunnable, 400); } } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { @@ -946,7 +946,7 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat peerView.cancelTextSelection(); } boolean viewsAllowed = peerView != null && peerView.viewsAllowed(); - allowSwipeToReply = !viewsAllowed && peerView != null && !peerView.isChannel && storiesIntro == null; + allowSwipeToReply = !viewsAllowed && peerView != null && !peerView.isChannel && !peerView.isPremiumBlocked && storiesIntro == null; allowSelfStoriesView = viewsAllowed && !peerView.unsupported && peerView.currentStory.storyItem != null && storiesIntro == null; if (allowSelfStoriesView && keyboardHeight != 0) { allowSelfStoriesView = false; 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 c07b4bedf..5240f0860 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 @@ -809,7 +809,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai bottomLayout.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int [] {0x00000000, 0x80000000} )); addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44 + 60, Gravity.BOTTOM)); - paintToolsView = new PaintToolsView(context, !entry.isRepostMessage && blurManager != null); + paintToolsView = new PaintToolsView(context, entry != null && !entry.isRepostMessage && blurManager != null); paintToolsView.setPadding(dp(16), 0, dp(16), 0); paintToolsView.setDelegate(this); // paintToolsView.setSelectedIndex(MathUtils.clamp(palette.getCurrentBrush(), 0, Brush.BRUSHES_LIST.size()) + 1); 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 55bbf5ee9..0de5175dd 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 @@ -3687,7 +3687,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg return super.dispatchTouchEvent(ev); } }; - galleryListView.allowSearch(forAddingPart); +// galleryListView.allowSearch(forAddingPart); galleryListView.setOnBackClickListener(() -> { animateGalleryListView(false); lastGallerySelectedAlbum = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicCreateFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicCreateFragment.java index 0150e223c..98f562c69 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicCreateFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicCreateFragment.java @@ -79,10 +79,10 @@ public class TopicCreateFragment extends BaseFragment { int iconColor; - public static TopicCreateFragment create(long chatId, int topicId) { + public static TopicCreateFragment create(long chatId, long topicId) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", chatId); - bundle.putInt("topic_id", topicId); + bundle.putLong("topic_id", topicId); return new TopicCreateFragment(bundle); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 892f20b1e..2518147d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -258,7 +258,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N NotificationCenter.topicsDidLoaded }); private View blurredView; - private int selectedTopicForTablet; + private long selectedTopicForTablet; private boolean joinRequested; private ChatActivityMemberRequestsDelegate pendingRequestsDelegate; @@ -1855,7 +1855,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N AndroidUtilities.runOnUIThread(() -> { Bundle args = new Bundle(); args.putLong("dialog_id", -chatId); - args.putInt("topic_id", topic.id); + args.putLong("topic_id", topic.id); presentFragment(new ProfileNotificationsActivity(args, themeDelegate)); }, 500); } @@ -2694,7 +2694,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } boolean close = (Boolean) args[2]; long dialog_id = (Long) args[0]; - int topicId = (int) args[1]; + long topicId = (Long) args[1]; if (dialog_id == -chatId && !close) { if (selectedTopicForTablet != topicId) { selectedTopicForTablet = topicId; @@ -3653,7 +3653,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N MessageObject message = searchResultMessages.get(position - messagesStartRow); TopicDialogCell dialogCell = (TopicDialogCell) holder.itemView; dialogCell.drawDivider = position != messagesEndRow - 1; - int topicId = MessageObject.getTopicId(message.messageOwner, true); + long topicId = MessageObject.getTopicId(currentAccount, message.messageOwner, true); if (topicId == 0) { topicId = 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java index 08a3b8d3e..b9247f16c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java @@ -86,7 +86,7 @@ public class TopicsNotifySettingsFragments extends BaseFragment { topicsFragment.setOnTopicSelectedListener((topic) -> { Bundle bundle2 = new Bundle(); bundle2.putLong("dialog_id", dialogId); - bundle2.putInt("topic_id", topic.id); + bundle2.putLong("topic_id", topic.id); bundle2.putBoolean("exception", true); ProfileNotificationsActivity fragment = new ProfileNotificationsActivity(bundle2); fragment.setDelegate(exception -> { @@ -102,7 +102,7 @@ public class TopicsNotifySettingsFragments extends BaseFragment { TLRPC.TL_forumTopic topic = (TLRPC.TL_forumTopic) items.get(position).topic; Bundle bundle = new Bundle(); bundle.putLong("dialog_id", dialogId); - bundle.putInt("topic_id", topic.id); + bundle.putLong("topic_id", topic.id); bundle.putBoolean("exception", false); ProfileNotificationsActivity topicsFragment = new ProfileNotificationsActivity(bundle); topicsFragment.setDelegate(new ProfileNotificationsActivity.ProfileNotificationsActivityDelegate() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index 3fc5498e1..e73083120 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -111,6 +111,7 @@ import org.telegram.ui.Components.voip.VoIPToggleButton; import org.telegram.ui.Components.voip.VoIPWindowView; import org.telegram.ui.Components.voip.VoIpGradientLayout; import org.telegram.ui.Components.voip.VoIpHintView; +import org.telegram.ui.Components.voip.VoIpCoverView; import org.telegram.ui.Components.voip.VoIpSnowView; import org.telegram.ui.Components.voip.VoIpSwitchLayout; import org.telegram.ui.Stories.recorder.HintView2; @@ -145,6 +146,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent private ViewGroup fragmentView; private VoIpGradientLayout gradientLayout; + private VoIpCoverView voIpCoverView; private VoIpSnowView voIpSnowView; private ImageWithWavesView callingUserPhotoViewMini; @@ -784,6 +786,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent // callingUserTextureView.attachBackgroundRenderer(); frameLayout.addView(gradientLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + frameLayout.addView(voIpCoverView = new VoIpCoverView(context, callingUser, backgroundProvider) , LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); frameLayout.addView(voIpSnowView = new VoIpSnowView(context), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 220)); frameLayout.addView(callingUserTextureView); @@ -866,7 +869,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent emojiLayout.setOrientation(LinearLayout.HORIZONTAL); emojiLayout.setPadding(0, 0, 0, AndroidUtilities.dp(30)); emojiLayout.setClipToPadding(false); - + emojiLayout.setContentDescription(LocaleController.getString("VoipHintEncryptionKey", R.string.VoipHintEncryptionKey)); emojiLayout.setOnClickListener(view -> { if (System.currentTimeMillis() - lastContentTapTime < 500) { return; @@ -970,7 +973,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserTitle.setText(name); callingUserTitle.setMaxLines(2); callingUserTitle.setEllipsize(TextUtils.TruncateAt.END); - callingUserTitle.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000); callingUserTitle.setTextColor(Color.WHITE); callingUserTitle.setGravity(Gravity.CENTER_HORIZONTAL); callingUserTitle.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); @@ -1587,6 +1589,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent return; } emojiExpanded = expanded; + voIpCoverView.onEmojiExpanded(expanded); if (expanded) { if (SharedConfig.callEncryptionHintDisplayedCount < 2) { SharedConfig.incrementCallEncryptionHintDisplayed(2); @@ -2124,6 +2127,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent updateSpeakerPhoneIcon(); if (currentState == VoIPService.STATE_ESTABLISHED) { + voIpCoverView.onConnected(); callingUserPhotoViewMini.onConnected(); if (!gradientLayout.isConnectedCalled()) { int[] loc = new int[2]; @@ -2134,6 +2138,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } boolean isVideoMode = currentUserIsVideo || callingUserIsVideo; voIpSnowView.setState(isVideoMode); + voIpCoverView.setState(isVideoMode); backgroundProvider.setHasVideo(isVideoMode); if (callingUserIsVideo && !wasVideo && isNearEar) { diff --git a/TMessagesProj/src/main/res/drawable-hdpi/filled_open_message.png b/TMessagesProj/src/main/res/drawable-hdpi/filled_open_message.png new file mode 100644 index 000000000..5dcd28d63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/filled_open_message.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_hidden.png b/TMessagesProj/src/main/res/drawable-hdpi/large_hidden.png new file mode 100644 index 000000000..21b72c8ca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_hidden.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_message_lock.png b/TMessagesProj/src/main/res/drawable-hdpi/large_message_lock.png new file mode 100644 index 000000000..96c517778 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_message_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_notes.png b/TMessagesProj/src/main/res/drawable-hdpi/large_notes.png new file mode 100644 index 000000000..223a0f123 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_notes.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_external_link.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_external_link.png new file mode 100644 index 000000000..0a896857c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_external_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/filled_open_message.png b/TMessagesProj/src/main/res/drawable-mdpi/filled_open_message.png new file mode 100644 index 000000000..92c7fd550 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/filled_open_message.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_hidden.png b/TMessagesProj/src/main/res/drawable-mdpi/large_hidden.png new file mode 100644 index 000000000..37acae5ab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_hidden.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_message_lock.png b/TMessagesProj/src/main/res/drawable-mdpi/large_message_lock.png new file mode 100644 index 000000000..67cdc9a61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_message_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_notes.png b/TMessagesProj/src/main/res/drawable-mdpi/large_notes.png new file mode 100644 index 000000000..d0adc95fd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_notes.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_external_link.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_external_link.png new file mode 100644 index 000000000..40a565a7a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_external_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/filled_open_message.png b/TMessagesProj/src/main/res/drawable-xhdpi/filled_open_message.png new file mode 100644 index 000000000..e88a9db71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/filled_open_message.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_hidden.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_hidden.png new file mode 100644 index 000000000..31c29045e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_hidden.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_message_lock.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_message_lock.png new file mode 100644 index 000000000..b27f95b57 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_message_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_notes.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_notes.png new file mode 100644 index 000000000..7e80be4b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_notes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_external_link.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_external_link.png new file mode 100644 index 000000000..51f1e7c33 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_external_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/filled_open_message.png b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_open_message.png new file mode 100644 index 000000000..88bc7b077 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/filled_open_message.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_hidden.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_hidden.png new file mode 100644 index 000000000..b60d52b54 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_hidden.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_message_lock.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_message_lock.png new file mode 100644 index 000000000..76a8fe5e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_message_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_notes.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_notes.png new file mode 100644 index 000000000..b169750c5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_notes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_external_link.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_external_link.png new file mode 100644 index 000000000..6ca36dbce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_external_link.png differ diff --git a/TMessagesProj/src/main/res/raw/large_lastseen.json b/TMessagesProj/src/main/res/raw/large_lastseen.json new file mode 100644 index 000000000..09948f7dc --- /dev/null +++ b/TMessagesProj/src/main/res/raw/large_lastseen.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"LastSeen","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"lastSeen Outlines 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.4,"y":1},"o":{"x":0.6,"y":0},"t":-30,"s":[346,90,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[256,256,0]}],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":0,"k":[150,150,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.855,-0.381],[-1.743,-3.977],[9.899,8.512],[-0.936,5.33]],"o":[[4.608,0.615],[1.743,3.977],[-3.764,-3.237],[1.526,-8.686]],"v":[[9.589,5.443],[31.861,20.789],[3.193,35.28],[-1.014,21.383]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,1.615],[-9.94,-3.24],[2.23,-10.199],[4.767,1.649]],"o":[[6.515,-33.233],[5.081,1.656],[-3.743,17.119],[-9.337,-3.23]],"v":[[15.978,-4.891],[55.938,-46.243],[64.891,-23.259],[38.868,9.309]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[135,135],"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":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[0]},{"t":50,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.913,1.812],[-2.733,-2.251],[14.502,3.094]],"o":[[3.913,-1.812],[2.733,2.251],[-14.502,-3.094]],"v":[[-53.1,25.872],[-26.044,32.041],[-43.992,53.907]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[3.913,-1.812],[2.733,2.251],[-4.651,12.962],[-8.081,-1.636]],"o":[[-3.913,1.812],[-1.349,-1.111],[4.77,-13.295],[25.546,5.171]],"v":[[-22.377,20.405],[-49.892,13.012],[-47.681,-14.514],[-19.039,-36.308]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[135,135],"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":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[0]},{"t":30,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow","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":[327]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[327]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[327]},{"i":{"x":[0.833],"y":[1.194]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[327]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":4,"s":[327]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.095]},"t":5,"s":[324.669]},{"i":{"x":[0.833],"y":[0.709]},"o":{"x":[0.167],"y":[0.19]},"t":6,"s":[308.104]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.117]},"t":7,"s":[295.176]},{"i":{"x":[0.833],"y":[0.74]},"o":{"x":[0.167],"y":[0.23]},"t":8,"s":[262.935]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":9,"s":[244.64]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":10,"s":[205.869]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.254]},"t":11,"s":[166.529]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":12,"s":[147.352]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":13,"s":[111.033]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.268]},"t":14,"s":[78.4]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":15,"s":[63.711]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.185]},"t":16,"s":[37.839]},{"i":{"x":[0.833],"y":[0.781]},"o":{"x":[0.167],"y":[0.283]},"t":17,"s":[16.72]},{"i":{"x":[0.833],"y":[0.857]},"o":{"x":[0.167],"y":[0.135]},"t":18,"s":[7.908]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.199]},"t":19,"s":[-6.413]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.31]},"t":20,"s":[-16.692]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.144]},"t":21,"s":[-20.474]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.255]},"t":22,"s":[-25.676]},{"i":{"x":[0.833],"y":[0.999]},"o":{"x":[0.167],"y":[0.563]},"t":23,"s":[-28.205]},{"i":{"x":[0.833],"y":[0.577]},"o":{"x":[0.167],"y":[-0.001]},"t":24,"s":[-28.645]},{"i":{"x":[0.833],"y":[0.858]},"o":{"x":[0.167],"y":[0.104]},"t":25,"s":[-28.208]},{"i":{"x":[0.833],"y":[0.718]},"o":{"x":[0.167],"y":[0.202]},"t":26,"s":[-26.43]},{"i":{"x":[0.833],"y":[0.823]},"o":{"x":[0.167],"y":[0.118]},"t":27,"s":[-25.178]},{"i":{"x":[0.833],"y":[0.874]},"o":{"x":[0.167],"y":[0.157]},"t":28,"s":[-22.19]},{"i":{"x":[0.833],"y":[0.752]},"o":{"x":[0.167],"y":[0.245]},"t":29,"s":[-18.833]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":30,"s":[-17.101]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.171]},"t":31,"s":[-13.673]},{"i":{"x":[0.833],"y":[0.765]},"o":{"x":[0.167],"y":[0.262]},"t":32,"s":[-10.427]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.129]},"t":33,"s":[-8.913]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.181]},"t":34,"s":[-6.152]},{"i":{"x":[0.833],"y":[0.775]},"o":{"x":[0.167],"y":[0.275]},"t":35,"s":[-3.79]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.132]},"t":36,"s":[-2.765]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.191]},"t":37,"s":[-1.026]},{"i":{"x":[0.833],"y":[0.789]},"o":{"x":[0.167],"y":[0.294]},"t":38,"s":[0.315]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.138]},"t":39,"s":[0.846]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.214]},"t":40,"s":[1.657]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.348]},"t":41,"s":[2.173]},{"i":{"x":[0.833],"y":[0.92]},"o":{"x":[0.167],"y":[0.165]},"t":42,"s":[2.335]},{"i":{"x":[0.833],"y":[0.197]},"o":{"x":[0.167],"y":[-2.153]},"t":43,"s":[2.501]},{"i":{"x":[0.833],"y":[0.633]},"o":{"x":[0.167],"y":[0.093]},"t":44,"s":[2.495]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.108]},"t":45,"s":[2.442]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.144]},"t":46,"s":[2.26]},{"i":{"x":[0.833],"y":[0.741]},"o":{"x":[0.167],"y":[0.231]},"t":47,"s":[2.009]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":48,"s":[1.867]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.166]},"t":49,"s":[1.568]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.255]},"t":50,"s":[1.266]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":51,"s":[1.119]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":52,"s":[0.84]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.269]},"t":53,"s":[0.591]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":54,"s":[0.479]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.186]},"t":55,"s":[0.282]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.283]},"t":56,"s":[0.121]},{"i":{"x":[0.833],"y":[0.857]},"o":{"x":[0.167],"y":[0.135]},"t":57,"s":[0.054]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.2]},"t":58,"s":[-0.054]},{"t":59,"s":[-0.132]}],"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.701,0.701,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.861,0.861,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.115,0.115,0]},"t":1,"s":[5.135,5.135,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.724,0.724,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.209,0.209,0]},"t":2,"s":[18.455,18.455,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.825,0.825,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.119,0.119,0]},"t":3,"s":[27.289,27.289,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.159,0.159,0]},"t":4,"s":[47.761,47.761,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":5,"s":[70.245,70.245,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.759,0.759,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.254,0.254,0]},"t":6,"s":[93.058,93.058,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.127,0.127,0]},"t":7,"s":[104.179,104.179,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.263,0.263,0]},"t":8,"s":[125.241,125.241,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":9,"s":[135.003,135.003,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.182,0.182,0]},"t":10,"s":[152.683,152.683,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.277,0.277,0]},"t":11,"s":[167.687,167.687,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.133,0.133,0]},"t":12,"s":[174.153,174.153,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.193,0.193,0]},"t":13,"s":[185.044,185.044,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.791,0.791,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.296,0.296,0]},"t":14,"s":[193.349,193.349,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.865,0.865,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":15,"s":[196.604,196.604,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.219,0.219,0]},"t":16,"s":[201.503,201.503,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.361,0.361,0]},"t":17,"s":[204.519,204.519,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.943,0.943,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.176,0.176,0]},"t":18,"s":[205.426,205.426,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.185,-0.185,0]},"t":19,"s":[206.241,206.241,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.663,0.663,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":20,"s":[205.988,205.988,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.807,0.807,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.111,0.111,0]},"t":21,"s":[205.553,205.553,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.147,0.147,0]},"t":22,"s":[204.231,204.231,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.234,0.234,0]},"t":23,"s":[202.498,202.498,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.834,0.834,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.123,0.123,0]},"t":24,"s":[201.541,201.541,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.167,0.167,0]},"t":25,"s":[199.547,199.547,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.76,0.76,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":26,"s":[197.558,197.558,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.843,0.843,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":27,"s":[196.599,196.599,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.177,0.177,0]},"t":28,"s":[194.798,194.798,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.771,0.771,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.27,0.27,0]},"t":29,"s":[193.197,193.197,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.131,0.131,0]},"t":30,"s":[192.482,192.482,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.187,0.187,0]},"t":31,"s":[191.233,191.233,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.783,0.783,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.285,0.285,0]},"t":32,"s":[190.225,190.225,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":33,"s":[189.808,189.808,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":34,"s":[189.139,189.139,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.806,0.806,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.315,0.315,0]},"t":35,"s":[188.669,188.669,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.146,0.146,0]},"t":36,"s":[188.499,188.499,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.909,0.909,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.278,0.278,0]},"t":37,"s":[188.275,188.275,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.32,1.32,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.975,0.975,0]},"t":38,"s":[188.179,188.179,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.715,0.715,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.066,0.066,0]},"t":39,"s":[188.17,188.17,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.118,0.118,0]},"t":40,"s":[188.214,188.214,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.725,0.725,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.211,0.211,0]},"t":41,"s":[188.319,188.319,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.12,0.12,0]},"t":42,"s":[188.388,188.388,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.16,0.16,0]},"t":43,"s":[188.547,188.547,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.753,0.753,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.247,0.247,0]},"t":44,"s":[188.72,188.72,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":45,"s":[188.808,188.808,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":46,"s":[188.981,188.981,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.263,0.263,0]},"t":47,"s":[189.142,189.142,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":48,"s":[189.217,189.217,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.182,0.182,0]},"t":49,"s":[189.352,189.352,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.277,0.277,0]},"t":50,"s":[189.466,189.466,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.133,0.133,0]},"t":51,"s":[189.516,189.516,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.193,0.193,0]},"t":52,"s":[189.598,189.598,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.297,0.297,0]},"t":53,"s":[189.661,189.661,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.866,0.866,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":54,"s":[189.686,189.686,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.22,0.22,0]},"t":55,"s":[189.723,189.723,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.364,0.364,0]},"t":56,"s":[189.745,189.745,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.95,0.95,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":57,"s":[189.752,189.752,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.124,-0.124,0]},"t":58,"s":[189.758,189.758,100]},{"t":59,"s":[189.755,189.755,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[53.848,0],[0,-53.848],[-53.848,0],[-17.881,21.788]],"o":[[0,-53.848],[-53.848,0],[0,53.848],[30.385,0],[0,0]],"v":[[97.5,0],[0,-97.5],[-97.5,0],[0,97.5],[75.405,61.813]],"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":15,"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.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[100]},{"i":{"x":[0.833],"y":[1.059]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[100]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":4,"s":[100]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.095]},"t":5,"s":[99.287]},{"i":{"x":[0.833],"y":[0.709]},"o":{"x":[0.167],"y":[0.19]},"t":6,"s":[94.222]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.117]},"t":7,"s":[90.268]},{"i":{"x":[0.833],"y":[0.74]},"o":{"x":[0.167],"y":[0.23]},"t":8,"s":[80.408]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":9,"s":[74.813]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":10,"s":[62.957]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.254]},"t":11,"s":[50.926]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":12,"s":[45.062]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":13,"s":[33.955]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.268]},"t":14,"s":[23.976]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":15,"s":[19.483]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.185]},"t":16,"s":[11.571]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.283]},"t":17,"s":[5.113]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[0.176]},"t":18,"s":[2.418]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[-0.202]},"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":[0.992]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[0]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.083]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.789]},"o":{"x":[0.167],"y":[0.133]},"t":38,"s":[0.096]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.138]},"t":39,"s":[0.259]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.214]},"t":40,"s":[0.507]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.348]},"t":41,"s":[0.664]},{"i":{"x":[0.833],"y":[0.92]},"o":{"x":[0.167],"y":[0.165]},"t":42,"s":[0.714]},{"i":{"x":[0.833],"y":[0.197]},"o":{"x":[0.167],"y":[-2.153]},"t":43,"s":[0.765]},{"i":{"x":[0.833],"y":[0.633]},"o":{"x":[0.167],"y":[0.093]},"t":44,"s":[0.763]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.108]},"t":45,"s":[0.747]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.144]},"t":46,"s":[0.691]},{"i":{"x":[0.833],"y":[0.741]},"o":{"x":[0.167],"y":[0.231]},"t":47,"s":[0.614]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":48,"s":[0.571]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.166]},"t":49,"s":[0.48]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.255]},"t":50,"s":[0.387]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":51,"s":[0.342]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":52,"s":[0.257]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.269]},"t":53,"s":[0.181]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":54,"s":[0.146]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.186]},"t":55,"s":[0.086]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.283]},"t":56,"s":[0.037]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[0.186]},"t":57,"s":[0.017]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":58,"s":[0]},{"t":59,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[135,135],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.286,-0.003],[0,0],[-0.031,-2.772],[-0.715,-0.88],[0,0],[-1.434,1.166],[-0.175,0.703],[0,0],[1.793,0.448]],"o":[[0,0],[-2.772,0.031],[0.013,1.134],[0,0],[1.166,1.434],[0.562,-0.457],[0,0],[0.448,-1.793],[-0.277,-0.069]],"v":[[17.771,-21.479],[-16.509,-21.096],[-21.472,-16.021],[-20.348,-12.911],[6.261,19.83],[10.969,20.317],[12.105,18.53],[21.055,-17.323],[18.619,-21.38]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"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":[0,0]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.941,0.941]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.325,0.325]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":4,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":5,"s":[0.713,0.713]},{"i":{"x":[0.833,0.833],"y":[0.709,0.709]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":6,"s":[5.778,5.778]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":7,"s":[9.732,9.732]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.23,0.23]},"t":8,"s":[19.592,19.592]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":9,"s":[25.187,25.187]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":10,"s":[37.043,37.043]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":11,"s":[49.074,49.074]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":12,"s":[54.938,54.938]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":13,"s":[66.045,66.045]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.268,0.268]},"t":14,"s":[76.024,76.024]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":15,"s":[80.517,80.517]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.185,0.185]},"t":16,"s":[88.429,88.429]},{"i":{"x":[0.833,0.833],"y":[0.781,0.781]},"o":{"x":[0.167,0.167],"y":[0.283,0.283]},"t":17,"s":[94.887,94.887]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":18,"s":[97.582,97.582]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":19,"s":[101.961,101.961]},{"i":{"x":[0.833,0.833],"y":[0.802,0.802]},"o":{"x":[0.167,0.167],"y":[0.31,0.31]},"t":20,"s":[105.104,105.104]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":21,"s":[106.261,106.261]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":22,"s":[107.852,107.852]},{"i":{"x":[0.833,0.833],"y":[0.999,0.999]},"o":{"x":[0.167,0.167],"y":[0.563,0.563]},"t":23,"s":[108.625,108.625]},{"i":{"x":[0.833,0.833],"y":[0.577,0.577]},"o":{"x":[0.167,0.167],"y":[-0.001,-0.001]},"t":24,"s":[108.76,108.76]},{"i":{"x":[0.833,0.833],"y":[0.858,0.858]},"o":{"x":[0.167,0.167],"y":[0.104,0.104]},"t":25,"s":[108.626,108.626]},{"i":{"x":[0.833,0.833],"y":[0.718,0.718]},"o":{"x":[0.167,0.167],"y":[0.202,0.202]},"t":26,"s":[108.083,108.083]},{"i":{"x":[0.833,0.833],"y":[0.823,0.823]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":27,"s":[107.7,107.7]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":28,"s":[106.786,106.786]},{"i":{"x":[0.833,0.833],"y":[0.752,0.752]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":29,"s":[105.759,105.759]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":30,"s":[105.23,105.23]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.171,0.171]},"t":31,"s":[104.181,104.181]},{"i":{"x":[0.833,0.833],"y":[0.765,0.765]},"o":{"x":[0.167,0.167],"y":[0.262,0.262]},"t":32,"s":[103.189,103.189]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":33,"s":[102.726,102.726]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.181,0.181]},"t":34,"s":[101.881,101.881]},{"i":{"x":[0.833,0.833],"y":[0.775,0.775]},"o":{"x":[0.167,0.167],"y":[0.275,0.275]},"t":35,"s":[101.159,101.159]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":36,"s":[100.846,100.846]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.191,0.191]},"t":37,"s":[100.314,100.314]},{"i":{"x":[0.833,0.833],"y":[0.789,0.789]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":38,"s":[99.904,99.904]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.138,0.138]},"t":39,"s":[99.741,99.741]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.214,0.214]},"t":40,"s":[99.493,99.493]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.348,0.348]},"t":41,"s":[99.336,99.336]},{"i":{"x":[0.833,0.833],"y":[0.92,0.92]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":42,"s":[99.286,99.286]},{"i":{"x":[0.833,0.833],"y":[0.197,0.197]},"o":{"x":[0.167,0.167],"y":[-2.153,-2.153]},"t":43,"s":[99.235,99.235]},{"i":{"x":[0.833,0.833],"y":[0.633,0.633]},"o":{"x":[0.167,0.167],"y":[0.093,0.093]},"t":44,"s":[99.237,99.237]},{"i":{"x":[0.833,0.833],"y":[0.801,0.801]},"o":{"x":[0.167,0.167],"y":[0.108,0.108]},"t":45,"s":[99.253,99.253]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":46,"s":[99.309,99.309]},{"i":{"x":[0.833,0.833],"y":[0.741,0.741]},"o":{"x":[0.167,0.167],"y":[0.231,0.231]},"t":47,"s":[99.386,99.386]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":48,"s":[99.429,99.429]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":49,"s":[99.52,99.52]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":50,"s":[99.613,99.613]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":51,"s":[99.658,99.658]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":52,"s":[99.743,99.743]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":53,"s":[99.819,99.819]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":54,"s":[99.854,99.854]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.186,0.186]},"t":55,"s":[99.914,99.914]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.283,0.283]},"t":56,"s":[99.963,99.963]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":57,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.2,0.2]},"t":58,"s":[100.017,100.017]},{"t":59,"s":[100.04,100.04]}],"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":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[209.718,203.384],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/large_message_lock.json b/TMessagesProj/src/main/res/raw/large_message_lock.json new file mode 100644 index 000000000..bf1d6a1fb --- /dev/null +++ b/TMessagesProj/src/main/res/raw/large_message_lock.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Comp 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Subtract 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,266.667,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"s","pt":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,-16.609],[0,0],[16.411,0],[0,0],[0,16.609],[0,0],[-16.411,0],[0,0]],"o":[[0,0],[0,16.609],[0,0],[-16.411,0],[0,0],[0,-16.609],[0,0],[16.411,0]],"v":[[52.5,-3.231],[52.5,26.843],[22.786,56.917],[-21.786,56.917],[-51.5,26.843],[-51.5,-3.231],[-21.786,-33.306],[22.786,-33.306]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[-4.82,-18.053],[0,0],[17.837,-4.762],[0,0],[4.82,18.053],[0,0],[-17.837,4.762],[0,0]],"o":[[0,0],[4.82,18.053],[0,0],[-17.837,4.762],[0,0],[-4.82,-18.053],[0,0],[17.837,-4.762]],"v":[[58.157,-2.351],[66.884,30.338],[43.314,71.649],[-5.132,84.583],[-46.157,60.517],[-54.884,27.829],[-31.314,-13.482],[17.132,-26.416]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[-2.167,-18.56],[0,0],[18.337,-2.141],[0,0],[2.167,18.56],[0,0],[-18.337,2.141],[0,0]],"o":[[0,0],[2.167,18.56],[0,0],[-18.337,2.141],[0,0],[-2.167,-18.56],[0,0],[18.337,-2.141]],"v":[[60.643,0.495],[64.567,34.1],[35.289,71.583],[-14.516,77.399],[-51.643,47.671],[-55.567,14.066],[-26.289,-23.416],[23.516,-29.232]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":30,"s":[{"i":[[-4.82,-18.053],[0,0],[17.837,-4.762],[0,0],[4.82,18.053],[0,0],[-17.837,4.762],[0,0]],"o":[[0,0],[4.82,18.053],[0,0],[-17.837,4.762],[0,0],[-4.82,-18.053],[0,0],[17.837,-4.762]],"v":[[58.157,-2.351],[66.884,30.338],[43.314,71.649],[-5.132,84.583],[-46.157,60.517],[-54.884,27.829],[-31.314,-13.482],[17.132,-26.416]],"c":true}]},{"t":40,"s":[{"i":[[0,-16.609],[0,0],[16.411,0],[0,0],[0,16.609],[0,0],[-16.411,0],[0,0]],"o":[[0,0],[0,16.609],[0,0],[-16.411,0],[0,0],[0,-16.609],[0,0],[16.411,0]],"v":[[52.5,-3.231],[52.5,26.843],[22.786,56.917],[-21.786,56.917],[-51.5,26.843],[-51.5,-3.231],[-21.786,-33.306],[22.786,-33.306]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"},{"inv":false,"mode":"s","pt":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[-12.444,0],[0,-12.354],[0,0],[-4.148,0],[0,4.118],[0,0],[20.74,0],[0,-20.59],[0,0],[-4.148,0],[0,4.118]],"o":[[0,-12.354],[12.444,0],[0,0],[0,4.118],[4.148,0],[0,0],[0,-20.59],[-20.74,0],[0,0],[0,4.118],[4.148,0],[0,0]],"v":[[-21.811,-48.466],[0.722,-70.836],[23.256,-48.466],[23.256,41.015],[30.767,48.472],[38.278,41.015],[38.278,-48.466],[0.722,-85.75],[-36.833,-48.466],[-36.833,-26.096],[-29.322,-18.639],[-21.811,-26.096]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":10,"s":[{"i":[[0,0],[-13.505,-3.686],[3.66,-13.408],[0,0],[-4.502,-1.229],[-1.22,4.47],[0,0],[22.509,6.144],[6.1,-22.347],[0,0],[-4.502,-1.229],[-1.22,4.47]],"o":[[3.66,-13.408],[13.505,3.686],[0,0],[-1.22,4.47],[4.502,1.229],[0,0],[6.1,-22.347],[-22.509,-6.144],[0,0],[-1.22,4.47],[4.502,1.229],[0,0]],"v":[[-13.369,-74.213],[17.713,-91.816],[35.541,-60.863],[9.033,36.251],[14.976,46.569],[25.337,40.701],[51.845,-56.413],[22.131,-108.002],[-29.673,-78.663],[-36.3,-54.385],[-30.357,-44.067],[-19.996,-49.935]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[0,0],[-13.898,-1.681],[1.669,-13.798],[0,0],[-4.633,-0.56],[-0.556,4.6],[0,0],[23.164,2.801],[2.781,-22.997],[0,0],[-4.633,-0.56],[-0.556,4.6]],"o":[[1.669,-13.798],[13.898,1.681],[0,0],[-0.556,4.6],[4.633,0.56],[0,0],[2.781,-22.997],[-23.164,-2.801],[0,0],[-0.556,4.6],[4.633,0.56],[0,0]],"v":[[-20.093,-64.843],[8.095,-86.784],[30.24,-58.755],[18.154,41.183],[25.535,50.526],[34.931,43.212],[47.018,-56.726],[10.11,-103.44],[-36.871,-66.872],[-39.892,-41.887],[-32.511,-32.544],[-23.115,-39.858]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":30,"s":[{"i":[[0,0],[-13.505,-3.686],[3.66,-13.408],[0,0],[-4.502,-1.229],[-1.22,4.47],[0,0],[22.509,6.144],[6.1,-22.347],[0,0],[-4.502,-1.229],[-1.22,4.47]],"o":[[3.66,-13.408],[13.505,3.686],[0,0],[-1.22,4.47],[4.502,1.229],[0,0],[6.1,-22.347],[-22.509,-6.144],[0,0],[-1.22,4.47],[4.502,1.229],[0,0]],"v":[[-13.369,-74.213],[17.713,-91.816],[35.541,-60.863],[9.033,36.251],[14.976,46.569],[25.337,40.701],[51.845,-56.413],[22.131,-108.002],[-29.673,-78.663],[-36.3,-54.385],[-30.357,-44.067],[-19.996,-49.935]],"c":true}]},{"t":40,"s":[{"i":[[0,0],[-12.444,0],[0,-12.354],[0,0],[-4.148,0],[0,4.118],[0,0],[20.74,0],[0,-20.59],[0,0],[-4.148,0],[0,4.118]],"o":[[0,-12.354],[12.444,0],[0,0],[0,4.118],[4.148,0],[0,0],[0,-20.59],[-20.74,0],[0,0],[0,4.118],[4.148,0],[0,0]],"v":[[-21.811,-48.466],[0.722,-70.836],[23.256,-48.466],[23.256,41.015],[30.767,48.472],[38.278,41.015],[38.278,-48.466],[0.722,-85.75],[-36.833,-48.466],[-36.833,-26.096],[-29.322,-18.639],[-21.811,-26.096]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.774,5.473],[9.285,0],[0,-16.783],[-7.511,-5.57],[2.141,-3.324],[0.742,-0.814],[-0.791,-0.336],[-3.52,1.999],[-1.124,1.051],[-0.49,-0.114],[-1.857,-0.137],[0,0],[-0.873,0],[0,16.783]],"o":[[-5.996,-5.683],[-18.225,0],[0,9.572],[0.961,0.712],[-0.876,1.359],[-1.073,1.177],[0.825,0.351],[2.755,-1.565],[0.929,-0.869],[1.757,0.408],[0,0],[0.856,0.061],[18.225,0],[0,-8.233]],"v":[[23.671,-24.286],[0,-33.5],[-33,-3.112],[-21.075,19.875],[-21.371,27.87],[-23.952,31.101],[-24.842,33.282],[-15.621,31.807],[-10.074,27.63],[-8.099,26.354],[-2.671,27.177],[-2.595,27.183],[0,27.275],[33,-3.112]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[426.667,426.667],"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":"Subtract","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":183,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/large_readtime.json b/TMessagesProj/src/main/res/raw/large_readtime.json new file mode 100644 index 000000000..aef5be7b8 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/large_readtime.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"ReadTime","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Checks 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":0,"k":[189.63,189.63,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-10.525,-14.232],[10.525,14.232]],"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":13.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nfunction sd(o) {\n var d = '9pYt1hxZN2SDCwaPVt3Jrd2IL7LAjQ';\n var l = '';\n var j = $bm_div(o.length, 2);\n var g = d.length;\n var e = 0;\n var f = 0;\n for (var h = 0; h + f < j; h++) {\n var m;\n var n;\n var k = o.substr($bm_mul(2, $bm_sum(h, f)), 2);\n if (k == '##') {\n k = o.substr($bm_mul(2, $bm_sum($bm_sum(h, f), 1)), 4);\n f = $bm_sum(f, 2);\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 65536);\n while (m < 0) {\n m = $bm_sum(m, 65536);\n }\n } else {\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 256);\n while (m < 0) {\n m = $bm_sum(m, 256);\n }\n }\n l = $bm_sum(l, String.fromCharCode(m));\n e = n;\n }\n return l;\n}\neval([sd('af804bdf7d4631fe89ec7a34d8c14205cfac45f5d59e43ff88f071e2874ee8ca431bad826a2de9821287ffb1883901951bc4ac7513cb7a1ada943be750ec7515763bee')][0]);\nfunction A(D, B) {\n var i = nearestKey(D).index;\n var G = key(i).time < D && i < numKeys ? $bm_sum(i, 1) : i;\n var E = key(i).time >= D && i > 1 ? $bm_sub(i, 1) : i;\n var H = key(G).value;\n var C = key(E).value;\n var F = {\n to: H,\n from_: C,\n toTime: key(G).time\n };\n if (B != null) {\n F.to = F.to[B];\n F.from_ = F.from_[B];\n }\n return F;\n}\nfunction y(L, D, G, B, N, I, H) {\n var R = Math.sqrt(I);\n var F;\n var O;\n var M;\n var Q = L;\n var i = D;\n var C = G;\n if (H > 1) {\n F = $bm_sum($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n O = $bm_sub($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n } else {\n if (H >= 0 && H < 1) {\n M = $bm_mul(R, Math.sqrt($bm_sub(1, $bm_mul(H, H))));\n }\n }\n var E = 0.01;\n while (Q < B) {\n Q = $bm_sum(Q, E);\n var P = A(Q, N);\n var K = J(C, i, E, P.to);\n i = K.mVelocity;\n C = K.mValue;\n }\n return C;\n function J(ab, ae, T, Y) {\n var Z = T;\n var ac = $bm_sub(ab, Y);\n var aa;\n var X;\n if (H > 1) {\n var U = $bm_sub(ac, $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F)));\n var S = $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F));\n aa = $bm_sum($bm_mul(U, Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul(S, Math.pow(Math.E, $bm_mul(F, Z))));\n X = $bm_sum($bm_mul($bm_mul(U, O), Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul($bm_mul(S, F), Math.pow(Math.E, $bm_mul(F, Z))));\n } else {\n if (H == 1) {\n U = ac;\n S = $bm_sum(ae, $bm_mul(R, ac));\n aa = $bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z)));\n X = $bm_sum($bm_mul($bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z))), $bm_neg(R)), $bm_mul(S, Math.pow(Math.E, $bm_mul($bm_neg(R), Z))));\n } else {\n var ad = ac;\n var W = $bm_mul($bm_div(1, M), $bm_sum($bm_mul($bm_mul(H, R), ac), ae));\n aa = $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul(ad, Math.cos($bm_mul(M, Z))), $bm_mul(W, Math.sin($bm_mul(M, Z)))));\n X = $bm_sum($bm_mul($bm_mul(aa, $bm_neg(R)), H), $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul($bm_mul($bm_neg(M), ad), Math.sin($bm_mul(M, Z))), $bm_mul($bm_mul(M, W), Math.cos($bm_mul(M, Z))))));\n }\n }\n var V = {};\n V.mValue = $bm_sum(aa, Y);\n V.mVelocity = X;\n return V;\n }\n}\nvar f = 10000;\nvar l = 1500;\nvar n = 200;\nvar b = 50;\nvar o = 0.2;\nvar k = 0.5;\nvar x = 0.75;\nvar q = 1;\nfunction m(D, i) {\n var C = 1;\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, C)));\n var B = $bm_div($bm_mul($bm_mul($bm_mul(4, Math.PI), D), C), E);\n return {\n mass: C,\n stiffness: i,\n damping: B\n };\n}\nfunction s(D, i, B) {\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, D)));\n var C = $bm_div($bm_mul(B, E), $bm_mul($bm_mul(4, Math.PI), D));\n return {\n stiffness: i,\n dampingRatio: C\n };\n}\nfunction g(F, C) {\n var E = $bm_sum($bm_sum('', C.dampingRatio), j(C.dampingRatio));\n var D = $bm_sum($bm_sum('', C.stiffness), z(C.stiffness));\n var B = F.mass != 1 ? m(C.dampingRatio, C.stiffness) : F;\n var i = $bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum('Android (SpringForce)\\r' + '- dampingRatio: ', E), '\\r'), '- stiffness: '), D), '\\r'), '\\r'), 'Apple\\rUIKit (UISpringTimingParameters) or SwiftUI (interpolatingSpring)\\r'), '- mass: '), F.mass), '\\r'), '- stiffness: '), F.stiffness), '\\r'), '- damping: '), F.damping), '\\r\\r'), 'React Spring 8\\r'), '- mass: '), B.mass), '\\r'), '- tension: '), B.stiffness), '\\r'), '- friction: '), B.damping), '\\r'), '- clamp: false');\n return i;\n}\nfunction z(i) {\n if (i == f) {\n return ' (STIFFNESS_HIGH)';\n }\n if (i == l) {\n return ' (STIFFNESS_MEDIUM)';\n }\n if (i == n) {\n return ' (STIFFNESS_LOW)';\n }\n if (i == b) {\n return ' (STIFFNESS_VERY_LOW)';\n }\n return '';\n}\nfunction j(i) {\n if (i == o) {\n return ' (DAMPING_RATIO_HIGH_BOUNCY)';\n }\n if (i == k) {\n return ' (DAMPING_RATIO_MEDIUM_BOUNCY)';\n }\n if (i == x) {\n return ' (DAMPING_RATIO_LOW_BOUNCY)';\n }\n if (i == q) {\n return ' (DAMPING_RATIO_NO_BOUNCY)';\n }\n return '';\n}\nfunction h(B) {\n var i = B.propertyGroup() === position.propertyGroup() && B.propertyIndex === $bm_transform.position.propertyIndex;\n return i;\n}\nfunction c(B) {\n var i = B.propertyGroup() === scale.propertyGroup() && B.propertyIndex === $bm_transform.scale.propertyIndex;\n return i;\n}\nfunction a() {\n return Object.prototype.toString.call(value) == '[object Path Object]';\n}\nfunction e() {\n return Object.prototype.toString.call(value) == '[object String]';\n}\nvar r = true;\nvar v = s(mass, stiffness, damping);\nvar p;\nif (e()) {\n var u = {\n mass: mass,\n stiffness: stiffness,\n damping: damping\n };\n p = g(u, v);\n} else {\n var d = Math.max(0, thisLayer.inPoint);\n if (numKeys == 0 || d > time || time > thisLayer.outPoint) {\n p = value;\n } else {\n if ($bm_isInstanceOfArray(value)) {\n p = [];\n var t = valueAtTime(0);\n for (var w = 0; w < value.length; w++) {\n p[w] = y(d, S_velocity[w], t[w], time, w, v.stiffness, v.dampingRatio);\n }\n } else {\n p = y(d, S_velocity[0], valueAtTime(0), time, null, v.stiffness, v.dampingRatio);\n }\n }\n}\np = r || Number(timeToFrames()) % 2 == 0 ? p : value;\n$bm_rt = p;"},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[99.176,154.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-35.271,-1.188],[-13.247,29.034],[35.271,-29.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nfunction sd(o) {\n var d = '9pYt1hxZN2SDCwaPVt3Jrd2IL7LAjQ';\n var l = '';\n var j = $bm_div(o.length, 2);\n var g = d.length;\n var e = 0;\n var f = 0;\n for (var h = 0; h + f < j; h++) {\n var m;\n var n;\n var k = o.substr($bm_mul(2, $bm_sum(h, f)), 2);\n if (k == '##') {\n k = o.substr($bm_mul(2, $bm_sum($bm_sum(h, f), 1)), 4);\n f = $bm_sum(f, 2);\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 65536);\n while (m < 0) {\n m = $bm_sum(m, 65536);\n }\n } else {\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 256);\n while (m < 0) {\n m = $bm_sum(m, 256);\n }\n }\n l = $bm_sum(l, String.fromCharCode(m));\n e = n;\n }\n return l;\n}\neval([sd('af804bdf7d4631fe89ec7a34d8c14205cfac45f5d59e43ff88f071e2874ee8ca431bad826a2de9821287ffb1883901951bc4ac7513cb7a1ada943be750ec7515763bee')][0]);\nfunction A(D, B) {\n var i = nearestKey(D).index;\n var G = key(i).time < D && i < numKeys ? $bm_sum(i, 1) : i;\n var E = key(i).time >= D && i > 1 ? $bm_sub(i, 1) : i;\n var H = key(G).value;\n var C = key(E).value;\n var F = {\n to: H,\n from_: C,\n toTime: key(G).time\n };\n if (B != null) {\n F.to = F.to[B];\n F.from_ = F.from_[B];\n }\n return F;\n}\nfunction y(L, D, G, B, N, I, H) {\n var R = Math.sqrt(I);\n var F;\n var O;\n var M;\n var Q = L;\n var i = D;\n var C = G;\n if (H > 1) {\n F = $bm_sum($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n O = $bm_sub($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n } else {\n if (H >= 0 && H < 1) {\n M = $bm_mul(R, Math.sqrt($bm_sub(1, $bm_mul(H, H))));\n }\n }\n var E = 0.01;\n while (Q < B) {\n Q = $bm_sum(Q, E);\n var P = A(Q, N);\n var K = J(C, i, E, P.to);\n i = K.mVelocity;\n C = K.mValue;\n }\n return C;\n function J(ab, ae, T, Y) {\n var Z = T;\n var ac = $bm_sub(ab, Y);\n var aa;\n var X;\n if (H > 1) {\n var U = $bm_sub(ac, $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F)));\n var S = $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F));\n aa = $bm_sum($bm_mul(U, Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul(S, Math.pow(Math.E, $bm_mul(F, Z))));\n X = $bm_sum($bm_mul($bm_mul(U, O), Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul($bm_mul(S, F), Math.pow(Math.E, $bm_mul(F, Z))));\n } else {\n if (H == 1) {\n U = ac;\n S = $bm_sum(ae, $bm_mul(R, ac));\n aa = $bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z)));\n X = $bm_sum($bm_mul($bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z))), $bm_neg(R)), $bm_mul(S, Math.pow(Math.E, $bm_mul($bm_neg(R), Z))));\n } else {\n var ad = ac;\n var W = $bm_mul($bm_div(1, M), $bm_sum($bm_mul($bm_mul(H, R), ac), ae));\n aa = $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul(ad, Math.cos($bm_mul(M, Z))), $bm_mul(W, Math.sin($bm_mul(M, Z)))));\n X = $bm_sum($bm_mul($bm_mul(aa, $bm_neg(R)), H), $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul($bm_mul($bm_neg(M), ad), Math.sin($bm_mul(M, Z))), $bm_mul($bm_mul(M, W), Math.cos($bm_mul(M, Z))))));\n }\n }\n var V = {};\n V.mValue = $bm_sum(aa, Y);\n V.mVelocity = X;\n return V;\n }\n}\nvar f = 10000;\nvar l = 1500;\nvar n = 200;\nvar b = 50;\nvar o = 0.2;\nvar k = 0.5;\nvar x = 0.75;\nvar q = 1;\nfunction m(D, i) {\n var C = 1;\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, C)));\n var B = $bm_div($bm_mul($bm_mul($bm_mul(4, Math.PI), D), C), E);\n return {\n mass: C,\n stiffness: i,\n damping: B\n };\n}\nfunction s(D, i, B) {\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, D)));\n var C = $bm_div($bm_mul(B, E), $bm_mul($bm_mul(4, Math.PI), D));\n return {\n stiffness: i,\n dampingRatio: C\n };\n}\nfunction g(F, C) {\n var E = $bm_sum($bm_sum('', C.dampingRatio), j(C.dampingRatio));\n var D = $bm_sum($bm_sum('', C.stiffness), z(C.stiffness));\n var B = F.mass != 1 ? m(C.dampingRatio, C.stiffness) : F;\n var i = $bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum('Android (SpringForce)\\r' + '- dampingRatio: ', E), '\\r'), '- stiffness: '), D), '\\r'), '\\r'), 'Apple\\rUIKit (UISpringTimingParameters) or SwiftUI (interpolatingSpring)\\r'), '- mass: '), F.mass), '\\r'), '- stiffness: '), F.stiffness), '\\r'), '- damping: '), F.damping), '\\r\\r'), 'React Spring 8\\r'), '- mass: '), B.mass), '\\r'), '- tension: '), B.stiffness), '\\r'), '- friction: '), B.damping), '\\r'), '- clamp: false');\n return i;\n}\nfunction z(i) {\n if (i == f) {\n return ' (STIFFNESS_HIGH)';\n }\n if (i == l) {\n return ' (STIFFNESS_MEDIUM)';\n }\n if (i == n) {\n return ' (STIFFNESS_LOW)';\n }\n if (i == b) {\n return ' (STIFFNESS_VERY_LOW)';\n }\n return '';\n}\nfunction j(i) {\n if (i == o) {\n return ' (DAMPING_RATIO_HIGH_BOUNCY)';\n }\n if (i == k) {\n return ' (DAMPING_RATIO_MEDIUM_BOUNCY)';\n }\n if (i == x) {\n return ' (DAMPING_RATIO_LOW_BOUNCY)';\n }\n if (i == q) {\n return ' (DAMPING_RATIO_NO_BOUNCY)';\n }\n return '';\n}\nfunction h(B) {\n var i = B.propertyGroup() === position.propertyGroup() && B.propertyIndex === $bm_transform.position.propertyIndex;\n return i;\n}\nfunction c(B) {\n var i = B.propertyGroup() === scale.propertyGroup() && B.propertyIndex === $bm_transform.scale.propertyIndex;\n return i;\n}\nfunction a() {\n return Object.prototype.toString.call(value) == '[object Path Object]';\n}\nfunction e() {\n return Object.prototype.toString.call(value) == '[object String]';\n}\nvar r = true;\nvar v = s(mass, stiffness, damping);\nvar p;\nif (e()) {\n var u = {\n mass: mass,\n stiffness: stiffness,\n damping: damping\n };\n p = g(u, v);\n} else {\n var d = Math.max(0, thisLayer.inPoint);\n if (numKeys == 0 || d > time || time > thisLayer.outPoint) {\n p = value;\n } else {\n if ($bm_isInstanceOfArray(value)) {\n p = [];\n var t = valueAtTime(0);\n for (var w = 0; w < value.length; w++) {\n p[w] = y(d, S_velocity[w], t[w], time, w, v.stiffness, v.dampingRatio);\n }\n } else {\n p = y(d, S_velocity[0], valueAtTime(0), time, null, v.stiffness, v.dampingRatio);\n }\n }\n}\np = r || Number(timeToFrames()) % 2 == 0 ? p : value;\n$bm_rt = p;"},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[148.571,137.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":180,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":0,"k":[189.63,189.63,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,49.706],[49.709,0],[0,-49.706],[-25.828,-15.819]],"o":[[49.709,0],[0,-49.706],[-49.709,0],[0,32.504],[0,0]],"v":[[0,90],[90.006,0],[0,-90],[-90.006,0],[-46.946,76.803]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"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":[135.006,135],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.033,0.284],[0,0],[2.754,-0.321],[0.8,-0.803],[0,0],[-1.309,-1.305],[-0.717,-0.101],[0,0],[-0.258,1.83]],"o":[[0,0],[-0.321,-2.754],[-1.126,0.131],[0,0],[-1.305,1.309],[0.513,0.511],[0,0],[1.83,0.258],[0.04,-0.283]],"v":[[-28.017,93.543],[-31.981,59.492],[-37.547,55.086],[-40.522,56.529],[-70.303,86.415],[-70.294,91.147],[-68.399,92.09],[-31.807,97.244],[-28.027,94.397]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[88.125,213.428],"ix":2},"a":{"a":0,"k":[-46.875,78.428],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":180,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Checks","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,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":[0,0,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":[0,0,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":[0,0,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":[0,0,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":[0,0,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":[0,0,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":[0,0,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":[0,0,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,0,0]},"t":8,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.325,0.325,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.083,0.083,0]},"t":9,"s":[0,0,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.095,0.095,0]},"t":10,"s":[1.352,1.352,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.709,0.709,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.19,0.19,0]},"t":11,"s":[10.958,10.958,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.82,0.82,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.117,0.117,0]},"t":12,"s":[18.455,18.455,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.155,0.155,0]},"t":13,"s":[37.152,37.152,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.242,0.242,0]},"t":14,"s":[58.867,58.867,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.837,0.837,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":15,"s":[70.245,70.245,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.17,0.17,0]},"t":16,"s":[93.058,93.058,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.764,0.764,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.26,0.26,0]},"t":17,"s":[114.94,114.94,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.129,0.129,0]},"t":18,"s":[125.241,125.241,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.18,0.18,0]},"t":19,"s":[144.165,144.165,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.274,0.274,0]},"t":20,"s":[160.529,160.529,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":21,"s":[167.687,167.687,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.19,0.19,0]},"t":22,"s":[179.933,179.933,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.787,0.787,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.291,0.291,0]},"t":23,"s":[189.506,189.506,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":24,"s":[193.349,193.349,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.889,0.889,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.21,0.21,0]},"t":25,"s":[199.309,199.309,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.822,0.822,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.336,0.336,0]},"t":26,"s":[203.226,203.226,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.903,0.903,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.157,0.157,0]},"t":27,"s":[204.519,204.519,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.999,0.999,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.586,0.586,0]},"t":28,"s":[205.986,205.986,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.56,0.56,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.001,-0.001,0]},"t":29,"s":[206.229,206.229,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.791,0.791,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.103,0.103,0]},"t":30,"s":[205.988,205.988,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.868,0.868,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":31,"s":[204.957,204.957,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.737,0.737,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.227,0.227,0]},"t":32,"s":[203.402,203.402,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.122,0.122,0]},"t":33,"s":[202.498,202.498,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.164,0.164,0]},"t":34,"s":[200.551,200.551,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.758,0.758,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.253,0.253,0]},"t":35,"s":[198.545,198.545,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.127,0.127,0]},"t":36,"s":[197.558,197.558,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":37,"s":[195.676,195.676,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.267,0.267,0]},"t":38,"s":[193.97,193.97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.848,0.848,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.13,0.13,0]},"t":39,"s":[193.197,193.197,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.185,0.185,0]},"t":40,"s":[191.827,191.827,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.78,0.78,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.282,0.282,0]},"t":41,"s":[190.699,190.699,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.856,0.856,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.134,0.134,0]},"t":42,"s":[190.225,190.225,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.198,0.198,0]},"t":43,"s":[189.447,189.447,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.306,0.306,0]},"t":44,"s":[188.881,188.881,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.142,0.142,0]},"t":45,"s":[188.669,188.669,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.899,0.899,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.243,0.243,0]},"t":46,"s":[188.37,188.37,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.925,0.925,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.468,0.468,0]},"t":47,"s":[188.213,188.213,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.705,-0.705,0]},"t":48,"s":[188.179,188.179,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.087,0.087,0]},"t":49,"s":[188.183,188.183,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.711,0.711,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.193,0.193,0]},"t":50,"s":[188.26,188.26,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.821,0.821,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.117,0.117,0]},"t":51,"s":[188.319,188.319,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.156,0.156,0]},"t":52,"s":[188.465,188.465,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.243,0.243,0]},"t":53,"s":[188.632,188.632,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.837,0.837,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":54,"s":[188.72,188.72,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.17,0.17,0]},"t":55,"s":[188.896,188.896,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.764,0.764,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":56,"s":[189.063,189.063,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.129,0.129,0]},"t":57,"s":[189.142,189.142,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.18,0.18,0]},"t":58,"s":[189.287,189.287,100]},{"t":59,"s":[189.412,189.412,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-10.525,-14.232],[10.525,14.232]],"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":13.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nfunction sd(o) {\n var d = '9pYt1hxZN2SDCwaPVt3Jrd2IL7LAjQ';\n var l = '';\n var j = $bm_div(o.length, 2);\n var g = d.length;\n var e = 0;\n var f = 0;\n for (var h = 0; h + f < j; h++) {\n var m;\n var n;\n var k = o.substr($bm_mul(2, $bm_sum(h, f)), 2);\n if (k == '##') {\n k = o.substr($bm_mul(2, $bm_sum($bm_sum(h, f), 1)), 4);\n f = $bm_sum(f, 2);\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 65536);\n while (m < 0) {\n m = $bm_sum(m, 65536);\n }\n } else {\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 256);\n while (m < 0) {\n m = $bm_sum(m, 256);\n }\n }\n l = $bm_sum(l, String.fromCharCode(m));\n e = n;\n }\n return l;\n}\neval([sd('af804bdf7d4631fe89ec7a34d8c14205cfac45f5d59e43ff88f071e2874ee8ca431bad826a2de9821287ffb1883901951bc4ac7513cb7a1ada943be750ec7515763bee')][0]);\nfunction A(D, B) {\n var i = nearestKey(D).index;\n var G = key(i).time < D && i < numKeys ? $bm_sum(i, 1) : i;\n var E = key(i).time >= D && i > 1 ? $bm_sub(i, 1) : i;\n var H = key(G).value;\n var C = key(E).value;\n var F = {\n to: H,\n from_: C,\n toTime: key(G).time\n };\n if (B != null) {\n F.to = F.to[B];\n F.from_ = F.from_[B];\n }\n return F;\n}\nfunction y(L, D, G, B, N, I, H) {\n var R = Math.sqrt(I);\n var F;\n var O;\n var M;\n var Q = L;\n var i = D;\n var C = G;\n if (H > 1) {\n F = $bm_sum($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n O = $bm_sub($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n } else {\n if (H >= 0 && H < 1) {\n M = $bm_mul(R, Math.sqrt($bm_sub(1, $bm_mul(H, H))));\n }\n }\n var E = 0.01;\n while (Q < B) {\n Q = $bm_sum(Q, E);\n var P = A(Q, N);\n var K = J(C, i, E, P.to);\n i = K.mVelocity;\n C = K.mValue;\n }\n return C;\n function J(ab, ae, T, Y) {\n var Z = T;\n var ac = $bm_sub(ab, Y);\n var aa;\n var X;\n if (H > 1) {\n var U = $bm_sub(ac, $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F)));\n var S = $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F));\n aa = $bm_sum($bm_mul(U, Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul(S, Math.pow(Math.E, $bm_mul(F, Z))));\n X = $bm_sum($bm_mul($bm_mul(U, O), Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul($bm_mul(S, F), Math.pow(Math.E, $bm_mul(F, Z))));\n } else {\n if (H == 1) {\n U = ac;\n S = $bm_sum(ae, $bm_mul(R, ac));\n aa = $bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z)));\n X = $bm_sum($bm_mul($bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z))), $bm_neg(R)), $bm_mul(S, Math.pow(Math.E, $bm_mul($bm_neg(R), Z))));\n } else {\n var ad = ac;\n var W = $bm_mul($bm_div(1, M), $bm_sum($bm_mul($bm_mul(H, R), ac), ae));\n aa = $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul(ad, Math.cos($bm_mul(M, Z))), $bm_mul(W, Math.sin($bm_mul(M, Z)))));\n X = $bm_sum($bm_mul($bm_mul(aa, $bm_neg(R)), H), $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul($bm_mul($bm_neg(M), ad), Math.sin($bm_mul(M, Z))), $bm_mul($bm_mul(M, W), Math.cos($bm_mul(M, Z))))));\n }\n }\n var V = {};\n V.mValue = $bm_sum(aa, Y);\n V.mVelocity = X;\n return V;\n }\n}\nvar f = 10000;\nvar l = 1500;\nvar n = 200;\nvar b = 50;\nvar o = 0.2;\nvar k = 0.5;\nvar x = 0.75;\nvar q = 1;\nfunction m(D, i) {\n var C = 1;\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, C)));\n var B = $bm_div($bm_mul($bm_mul($bm_mul(4, Math.PI), D), C), E);\n return {\n mass: C,\n stiffness: i,\n damping: B\n };\n}\nfunction s(D, i, B) {\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, D)));\n var C = $bm_div($bm_mul(B, E), $bm_mul($bm_mul(4, Math.PI), D));\n return {\n stiffness: i,\n dampingRatio: C\n };\n}\nfunction g(F, C) {\n var E = $bm_sum($bm_sum('', C.dampingRatio), j(C.dampingRatio));\n var D = $bm_sum($bm_sum('', C.stiffness), z(C.stiffness));\n var B = F.mass != 1 ? m(C.dampingRatio, C.stiffness) : F;\n var i = $bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum('Android (SpringForce)\\r' + '- dampingRatio: ', E), '\\r'), '- stiffness: '), D), '\\r'), '\\r'), 'Apple\\rUIKit (UISpringTimingParameters) or SwiftUI (interpolatingSpring)\\r'), '- mass: '), F.mass), '\\r'), '- stiffness: '), F.stiffness), '\\r'), '- damping: '), F.damping), '\\r\\r'), 'React Spring 8\\r'), '- mass: '), B.mass), '\\r'), '- tension: '), B.stiffness), '\\r'), '- friction: '), B.damping), '\\r'), '- clamp: false');\n return i;\n}\nfunction z(i) {\n if (i == f) {\n return ' (STIFFNESS_HIGH)';\n }\n if (i == l) {\n return ' (STIFFNESS_MEDIUM)';\n }\n if (i == n) {\n return ' (STIFFNESS_LOW)';\n }\n if (i == b) {\n return ' (STIFFNESS_VERY_LOW)';\n }\n return '';\n}\nfunction j(i) {\n if (i == o) {\n return ' (DAMPING_RATIO_HIGH_BOUNCY)';\n }\n if (i == k) {\n return ' (DAMPING_RATIO_MEDIUM_BOUNCY)';\n }\n if (i == x) {\n return ' (DAMPING_RATIO_LOW_BOUNCY)';\n }\n if (i == q) {\n return ' (DAMPING_RATIO_NO_BOUNCY)';\n }\n return '';\n}\nfunction h(B) {\n var i = B.propertyGroup() === position.propertyGroup() && B.propertyIndex === $bm_transform.position.propertyIndex;\n return i;\n}\nfunction c(B) {\n var i = B.propertyGroup() === scale.propertyGroup() && B.propertyIndex === $bm_transform.scale.propertyIndex;\n return i;\n}\nfunction a() {\n return Object.prototype.toString.call(value) == '[object Path Object]';\n}\nfunction e() {\n return Object.prototype.toString.call(value) == '[object String]';\n}\nvar r = true;\nvar v = s(mass, stiffness, damping);\nvar p;\nif (e()) {\n var u = {\n mass: mass,\n stiffness: stiffness,\n damping: damping\n };\n p = g(u, v);\n} else {\n var d = Math.max(0, thisLayer.inPoint);\n if (numKeys == 0 || d > time || time > thisLayer.outPoint) {\n p = value;\n } else {\n if ($bm_isInstanceOfArray(value)) {\n p = [];\n var t = valueAtTime(0);\n for (var w = 0; w < value.length; w++) {\n p[w] = y(d, S_velocity[w], t[w], time, w, v.stiffness, v.dampingRatio);\n }\n } else {\n p = y(d, S_velocity[0], valueAtTime(0), time, null, v.stiffness, v.dampingRatio);\n }\n }\n}\np = r || Number(timeToFrames()) % 2 == 0 ? p : value;\n$bm_rt = p;"},"e":{"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":[0.941]},"o":{"x":[0.167],"y":[0]},"t":16,"s":[0]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":17,"s":[0]},{"i":{"x":[0.833],"y":[0.775]},"o":{"x":[0.167],"y":[0.095]},"t":18,"s":[0.713]},{"i":{"x":[0.833],"y":[0.866]},"o":{"x":[0.167],"y":[0.132]},"t":19,"s":[5.778]},{"i":{"x":[0.833],"y":[0.733]},"o":{"x":[0.167],"y":[0.221]},"t":20,"s":[14.391]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.121]},"t":21,"s":[19.592]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.163]},"t":22,"s":[31.043]},{"i":{"x":[0.833],"y":[0.756]},"o":{"x":[0.167],"y":[0.251]},"t":23,"s":[43.083]},{"i":{"x":[0.833],"y":[0.84]},"o":{"x":[0.167],"y":[0.127]},"t":24,"s":[49.074]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.174]},"t":25,"s":[60.613]},{"i":{"x":[0.833],"y":[0.768]},"o":{"x":[0.167],"y":[0.266]},"t":26,"s":[71.193]},{"i":{"x":[0.833],"y":[0.847]},"o":{"x":[0.167],"y":[0.13]},"t":27,"s":[76.024]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.183]},"t":28,"s":[84.654]},{"i":{"x":[0.833],"y":[0.779]},"o":{"x":[0.167],"y":[0.28]},"t":29,"s":[91.838]},{"i":{"x":[0.833],"y":[0.916]},"o":{"x":[0.167],"y":[0.134]},"t":30,"s":[94.887]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[6.544]},"t":31,"s":[99.935]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0.005]},"t":32,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":33,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":34,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":38,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":39,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":41,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":42,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":46,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":48,"s":[100]},{"i":{"x":[0.833],"y":[1.008]},"o":{"x":[0.167],"y":[0]},"t":49,"s":[100]},{"i":{"x":[0.833],"y":[0.658]},"o":{"x":[0.167],"y":[0.083]},"t":50,"s":[100]},{"i":{"x":[0.833],"y":[0.861]},"o":{"x":[0.167],"y":[0.11]},"t":51,"s":[99.904]},{"i":{"x":[0.833],"y":[0.888]},"o":{"x":[0.167],"y":[0.207]},"t":52,"s":[99.605]},{"i":{"x":[0.833],"y":[0.816]},"o":{"x":[0.167],"y":[0.328]},"t":53,"s":[99.404]},{"i":{"x":[0.833],"y":[0.894]},"o":{"x":[0.167],"y":[0.152]},"t":54,"s":[99.336]},{"i":{"x":[0.833],"y":[0.941]},"o":{"x":[0.167],"y":[0.388]},"t":55,"s":[99.253]},{"i":{"x":[0.833],"y":[0.404]},"o":{"x":[0.167],"y":[-0.201]},"t":56,"s":[99.23]},{"i":{"x":[0.833],"y":[0.779]},"o":{"x":[0.167],"y":[0.097]},"t":57,"s":[99.237]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.134]},"t":58,"s":[99.278]},{"t":59,"s":[99.345]}],"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":[99.176,154.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-35.271,-1.188],[-13.247,29.034],[35.271,-29.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nfunction sd(o) {\n var d = '9pYt1hxZN2SDCwaPVt3Jrd2IL7LAjQ';\n var l = '';\n var j = $bm_div(o.length, 2);\n var g = d.length;\n var e = 0;\n var f = 0;\n for (var h = 0; h + f < j; h++) {\n var m;\n var n;\n var k = o.substr($bm_mul(2, $bm_sum(h, f)), 2);\n if (k == '##') {\n k = o.substr($bm_mul(2, $bm_sum($bm_sum(h, f), 1)), 4);\n f = $bm_sum(f, 2);\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 65536);\n while (m < 0) {\n m = $bm_sum(m, 65536);\n }\n } else {\n n = parseInt(k, 16);\n m = $bm_mod($bm_sub($bm_sub(n, e), d.charCodeAt($bm_mod(h, g))), 256);\n while (m < 0) {\n m = $bm_sum(m, 256);\n }\n }\n l = $bm_sum(l, String.fromCharCode(m));\n e = n;\n }\n return l;\n}\neval([sd('af804bdf7d4631fe89ec7a34d8c14205cfac45f5d59e43ff88f071e2874ee8ca431bad826a2de9821287ffb1883901951bc4ac7513cb7a1ada943be750ec7515763bee')][0]);\nfunction A(D, B) {\n var i = nearestKey(D).index;\n var G = key(i).time < D && i < numKeys ? $bm_sum(i, 1) : i;\n var E = key(i).time >= D && i > 1 ? $bm_sub(i, 1) : i;\n var H = key(G).value;\n var C = key(E).value;\n var F = {\n to: H,\n from_: C,\n toTime: key(G).time\n };\n if (B != null) {\n F.to = F.to[B];\n F.from_ = F.from_[B];\n }\n return F;\n}\nfunction y(L, D, G, B, N, I, H) {\n var R = Math.sqrt(I);\n var F;\n var O;\n var M;\n var Q = L;\n var i = D;\n var C = G;\n if (H > 1) {\n F = $bm_sum($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n O = $bm_sub($bm_mul($bm_neg(H), R), $bm_mul(R, Math.sqrt($bm_sub($bm_mul(H, H), 1))));\n } else {\n if (H >= 0 && H < 1) {\n M = $bm_mul(R, Math.sqrt($bm_sub(1, $bm_mul(H, H))));\n }\n }\n var E = 0.01;\n while (Q < B) {\n Q = $bm_sum(Q, E);\n var P = A(Q, N);\n var K = J(C, i, E, P.to);\n i = K.mVelocity;\n C = K.mValue;\n }\n return C;\n function J(ab, ae, T, Y) {\n var Z = T;\n var ac = $bm_sub(ab, Y);\n var aa;\n var X;\n if (H > 1) {\n var U = $bm_sub(ac, $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F)));\n var S = $bm_div($bm_sub($bm_mul(O, ac), ae), $bm_sub(O, F));\n aa = $bm_sum($bm_mul(U, Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul(S, Math.pow(Math.E, $bm_mul(F, Z))));\n X = $bm_sum($bm_mul($bm_mul(U, O), Math.pow(Math.E, $bm_mul(O, Z))), $bm_mul($bm_mul(S, F), Math.pow(Math.E, $bm_mul(F, Z))));\n } else {\n if (H == 1) {\n U = ac;\n S = $bm_sum(ae, $bm_mul(R, ac));\n aa = $bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z)));\n X = $bm_sum($bm_mul($bm_mul($bm_sum(U, $bm_mul(S, Z)), Math.pow(Math.E, $bm_mul($bm_neg(R), Z))), $bm_neg(R)), $bm_mul(S, Math.pow(Math.E, $bm_mul($bm_neg(R), Z))));\n } else {\n var ad = ac;\n var W = $bm_mul($bm_div(1, M), $bm_sum($bm_mul($bm_mul(H, R), ac), ae));\n aa = $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul(ad, Math.cos($bm_mul(M, Z))), $bm_mul(W, Math.sin($bm_mul(M, Z)))));\n X = $bm_sum($bm_mul($bm_mul(aa, $bm_neg(R)), H), $bm_mul(Math.pow(Math.E, $bm_mul($bm_mul($bm_neg(H), R), Z)), $bm_sum($bm_mul($bm_mul($bm_neg(M), ad), Math.sin($bm_mul(M, Z))), $bm_mul($bm_mul(M, W), Math.cos($bm_mul(M, Z))))));\n }\n }\n var V = {};\n V.mValue = $bm_sum(aa, Y);\n V.mVelocity = X;\n return V;\n }\n}\nvar f = 10000;\nvar l = 1500;\nvar n = 200;\nvar b = 50;\nvar o = 0.2;\nvar k = 0.5;\nvar x = 0.75;\nvar q = 1;\nfunction m(D, i) {\n var C = 1;\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, C)));\n var B = $bm_div($bm_mul($bm_mul($bm_mul(4, Math.PI), D), C), E);\n return {\n mass: C,\n stiffness: i,\n damping: B\n };\n}\nfunction s(D, i, B) {\n var E = $bm_div($bm_mul(2, Math.PI), Math.sqrt($bm_div(i, D)));\n var C = $bm_div($bm_mul(B, E), $bm_mul($bm_mul(4, Math.PI), D));\n return {\n stiffness: i,\n dampingRatio: C\n };\n}\nfunction g(F, C) {\n var E = $bm_sum($bm_sum('', C.dampingRatio), j(C.dampingRatio));\n var D = $bm_sum($bm_sum('', C.stiffness), z(C.stiffness));\n var B = F.mass != 1 ? m(C.dampingRatio, C.stiffness) : F;\n var i = $bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum($bm_sum('Android (SpringForce)\\r' + '- dampingRatio: ', E), '\\r'), '- stiffness: '), D), '\\r'), '\\r'), 'Apple\\rUIKit (UISpringTimingParameters) or SwiftUI (interpolatingSpring)\\r'), '- mass: '), F.mass), '\\r'), '- stiffness: '), F.stiffness), '\\r'), '- damping: '), F.damping), '\\r\\r'), 'React Spring 8\\r'), '- mass: '), B.mass), '\\r'), '- tension: '), B.stiffness), '\\r'), '- friction: '), B.damping), '\\r'), '- clamp: false');\n return i;\n}\nfunction z(i) {\n if (i == f) {\n return ' (STIFFNESS_HIGH)';\n }\n if (i == l) {\n return ' (STIFFNESS_MEDIUM)';\n }\n if (i == n) {\n return ' (STIFFNESS_LOW)';\n }\n if (i == b) {\n return ' (STIFFNESS_VERY_LOW)';\n }\n return '';\n}\nfunction j(i) {\n if (i == o) {\n return ' (DAMPING_RATIO_HIGH_BOUNCY)';\n }\n if (i == k) {\n return ' (DAMPING_RATIO_MEDIUM_BOUNCY)';\n }\n if (i == x) {\n return ' (DAMPING_RATIO_LOW_BOUNCY)';\n }\n if (i == q) {\n return ' (DAMPING_RATIO_NO_BOUNCY)';\n }\n return '';\n}\nfunction h(B) {\n var i = B.propertyGroup() === position.propertyGroup() && B.propertyIndex === $bm_transform.position.propertyIndex;\n return i;\n}\nfunction c(B) {\n var i = B.propertyGroup() === scale.propertyGroup() && B.propertyIndex === $bm_transform.scale.propertyIndex;\n return i;\n}\nfunction a() {\n return Object.prototype.toString.call(value) == '[object Path Object]';\n}\nfunction e() {\n return Object.prototype.toString.call(value) == '[object String]';\n}\nvar r = true;\nvar v = s(mass, stiffness, damping);\nvar p;\nif (e()) {\n var u = {\n mass: mass,\n stiffness: stiffness,\n damping: damping\n };\n p = g(u, v);\n} else {\n var d = Math.max(0, thisLayer.inPoint);\n if (numKeys == 0 || d > time || time > thisLayer.outPoint) {\n p = value;\n } else {\n if ($bm_isInstanceOfArray(value)) {\n p = [];\n var t = valueAtTime(0);\n for (var w = 0; w < value.length; w++) {\n p[w] = y(d, S_velocity[w], t[w], time, w, v.stiffness, v.dampingRatio);\n }\n } else {\n p = y(d, S_velocity[0], valueAtTime(0), time, null, v.stiffness, v.dampingRatio);\n }\n }\n}\np = r || Number(timeToFrames()) % 2 == 0 ? p : value;\n$bm_rt = p;"},"e":{"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":[0.941]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":12,"s":[0]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.095]},"t":13,"s":[0.713]},{"i":{"x":[0.833],"y":[0.709]},"o":{"x":[0.167],"y":[0.19]},"t":14,"s":[5.778]},{"i":{"x":[0.833],"y":[0.82]},"o":{"x":[0.167],"y":[0.117]},"t":15,"s":[9.732]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.155]},"t":16,"s":[19.592]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.242]},"t":17,"s":[31.043]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.125]},"t":18,"s":[37.043]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.17]},"t":19,"s":[49.074]},{"i":{"x":[0.833],"y":[0.764]},"o":{"x":[0.167],"y":[0.26]},"t":20,"s":[60.613]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.129]},"t":21,"s":[66.045]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.18]},"t":22,"s":[76.024]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.274]},"t":23,"s":[84.654]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.132]},"t":24,"s":[88.429]},{"i":{"x":[0.833],"y":[0.916]},"o":{"x":[0.167],"y":[0.19]},"t":25,"s":[94.887]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[6.544]},"t":26,"s":[99.935]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0.005]},"t":27,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":29,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":30,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":31,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":32,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":33,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":34,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":38,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":39,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":41,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":42,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1.008]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[100]},{"i":{"x":[0.833],"y":[0.658]},"o":{"x":[0.167],"y":[0.083]},"t":45,"s":[100]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.11]},"t":46,"s":[99.904]},{"i":{"x":[0.833],"y":[0.799]},"o":{"x":[0.167],"y":[0.306]},"t":47,"s":[99.605]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.142]},"t":48,"s":[99.493]},{"i":{"x":[0.833],"y":[0.899]},"o":{"x":[0.167],"y":[0.243]},"t":49,"s":[99.336]},{"i":{"x":[0.833],"y":[0.925]},"o":{"x":[0.167],"y":[0.468]},"t":50,"s":[99.253]},{"i":{"x":[0.833],"y":[-0.881]},"o":{"x":[0.167],"y":[-0.705]},"t":51,"s":[99.235]},{"i":{"x":[0.833],"y":[0.853]},"o":{"x":[0.167],"y":[0.087]},"t":52,"s":[99.237]},{"i":{"x":[0.833],"y":[0.711]},"o":{"x":[0.167],"y":[0.193]},"t":53,"s":[99.278]},{"i":{"x":[0.833],"y":[0.821]},"o":{"x":[0.167],"y":[0.117]},"t":54,"s":[99.309]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.156]},"t":55,"s":[99.386]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.243]},"t":56,"s":[99.474]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.125]},"t":57,"s":[99.52]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.17]},"t":58,"s":[99.613]},{"t":59,"s":[99.701]}],"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":13.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[148.571,137.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arrow","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":[327]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[327]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[327]},{"i":{"x":[0.833],"y":[1.194]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[327]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":4,"s":[327]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.095]},"t":5,"s":[324.669]},{"i":{"x":[0.833],"y":[0.709]},"o":{"x":[0.167],"y":[0.19]},"t":6,"s":[308.104]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.117]},"t":7,"s":[295.176]},{"i":{"x":[0.833],"y":[0.74]},"o":{"x":[0.167],"y":[0.23]},"t":8,"s":[262.935]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":9,"s":[244.64]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":10,"s":[205.869]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.254]},"t":11,"s":[166.529]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":12,"s":[147.352]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":13,"s":[111.033]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.268]},"t":14,"s":[78.4]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":15,"s":[63.711]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.185]},"t":16,"s":[37.839]},{"i":{"x":[0.833],"y":[0.781]},"o":{"x":[0.167],"y":[0.283]},"t":17,"s":[16.72]},{"i":{"x":[0.833],"y":[0.857]},"o":{"x":[0.167],"y":[0.135]},"t":18,"s":[7.908]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.199]},"t":19,"s":[-6.413]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.31]},"t":20,"s":[-16.692]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.144]},"t":21,"s":[-20.474]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.255]},"t":22,"s":[-25.676]},{"i":{"x":[0.833],"y":[0.999]},"o":{"x":[0.167],"y":[0.563]},"t":23,"s":[-28.205]},{"i":{"x":[0.833],"y":[0.577]},"o":{"x":[0.167],"y":[-0.001]},"t":24,"s":[-28.645]},{"i":{"x":[0.833],"y":[0.858]},"o":{"x":[0.167],"y":[0.104]},"t":25,"s":[-28.208]},{"i":{"x":[0.833],"y":[0.718]},"o":{"x":[0.167],"y":[0.202]},"t":26,"s":[-26.43]},{"i":{"x":[0.833],"y":[0.823]},"o":{"x":[0.167],"y":[0.118]},"t":27,"s":[-25.178]},{"i":{"x":[0.833],"y":[0.874]},"o":{"x":[0.167],"y":[0.157]},"t":28,"s":[-22.19]},{"i":{"x":[0.833],"y":[0.752]},"o":{"x":[0.167],"y":[0.245]},"t":29,"s":[-18.833]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":30,"s":[-17.101]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.171]},"t":31,"s":[-13.673]},{"i":{"x":[0.833],"y":[0.765]},"o":{"x":[0.167],"y":[0.262]},"t":32,"s":[-10.427]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.129]},"t":33,"s":[-8.913]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.181]},"t":34,"s":[-6.152]},{"i":{"x":[0.833],"y":[0.775]},"o":{"x":[0.167],"y":[0.275]},"t":35,"s":[-3.79]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.132]},"t":36,"s":[-2.765]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.191]},"t":37,"s":[-1.026]},{"i":{"x":[0.833],"y":[0.789]},"o":{"x":[0.167],"y":[0.294]},"t":38,"s":[0.315]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.138]},"t":39,"s":[0.846]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.214]},"t":40,"s":[1.657]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.348]},"t":41,"s":[2.173]},{"i":{"x":[0.833],"y":[0.92]},"o":{"x":[0.167],"y":[0.165]},"t":42,"s":[2.335]},{"i":{"x":[0.833],"y":[0.197]},"o":{"x":[0.167],"y":[-2.153]},"t":43,"s":[2.501]},{"i":{"x":[0.833],"y":[0.633]},"o":{"x":[0.167],"y":[0.093]},"t":44,"s":[2.495]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.108]},"t":45,"s":[2.442]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.144]},"t":46,"s":[2.26]},{"i":{"x":[0.833],"y":[0.741]},"o":{"x":[0.167],"y":[0.231]},"t":47,"s":[2.009]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":48,"s":[1.867]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.166]},"t":49,"s":[1.568]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.255]},"t":50,"s":[1.266]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":51,"s":[1.119]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":52,"s":[0.84]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.269]},"t":53,"s":[0.591]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":54,"s":[0.479]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.186]},"t":55,"s":[0.282]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.283]},"t":56,"s":[0.121]},{"i":{"x":[0.833],"y":[0.857]},"o":{"x":[0.167],"y":[0.135]},"t":57,"s":[0.054]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.2]},"t":58,"s":[-0.054]},{"t":59,"s":[-0.132]}],"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[135,135,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.701,0.701,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.861,0.861,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.115,0.115,0]},"t":1,"s":[5.135,5.135,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.724,0.724,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.209,0.209,0]},"t":2,"s":[18.455,18.455,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.825,0.825,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.119,0.119,0]},"t":3,"s":[27.289,27.289,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.159,0.159,0]},"t":4,"s":[47.761,47.761,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":5,"s":[70.245,70.245,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.759,0.759,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.254,0.254,0]},"t":6,"s":[93.058,93.058,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.127,0.127,0]},"t":7,"s":[104.179,104.179,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.263,0.263,0]},"t":8,"s":[125.241,125.241,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":9,"s":[135.003,135.003,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.182,0.182,0]},"t":10,"s":[152.683,152.683,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.277,0.277,0]},"t":11,"s":[167.687,167.687,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.133,0.133,0]},"t":12,"s":[174.153,174.153,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.193,0.193,0]},"t":13,"s":[185.044,185.044,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.791,0.791,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.296,0.296,0]},"t":14,"s":[193.349,193.349,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.865,0.865,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":15,"s":[196.604,196.604,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.219,0.219,0]},"t":16,"s":[201.503,201.503,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.361,0.361,0]},"t":17,"s":[204.519,204.519,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.943,0.943,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.176,0.176,0]},"t":18,"s":[205.426,205.426,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.185,-0.185,0]},"t":19,"s":[206.241,206.241,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.663,0.663,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":20,"s":[205.988,205.988,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.807,0.807,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.111,0.111,0]},"t":21,"s":[205.553,205.553,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.147,0.147,0]},"t":22,"s":[204.231,204.231,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.234,0.234,0]},"t":23,"s":[202.498,202.498,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.834,0.834,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.123,0.123,0]},"t":24,"s":[201.541,201.541,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.167,0.167,0]},"t":25,"s":[199.547,199.547,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.76,0.76,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":26,"s":[197.558,197.558,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.843,0.843,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":27,"s":[196.599,196.599,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.177,0.177,0]},"t":28,"s":[194.798,194.798,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.771,0.771,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.27,0.27,0]},"t":29,"s":[193.197,193.197,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.131,0.131,0]},"t":30,"s":[192.482,192.482,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.187,0.187,0]},"t":31,"s":[191.233,191.233,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.783,0.783,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.285,0.285,0]},"t":32,"s":[190.225,190.225,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":33,"s":[189.808,189.808,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":34,"s":[189.139,189.139,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.806,0.806,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.315,0.315,0]},"t":35,"s":[188.669,188.669,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.146,0.146,0]},"t":36,"s":[188.499,188.499,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.909,0.909,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.278,0.278,0]},"t":37,"s":[188.275,188.275,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.32,1.32,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.975,0.975,0]},"t":38,"s":[188.179,188.179,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.715,0.715,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.066,0.066,0]},"t":39,"s":[188.17,188.17,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.118,0.118,0]},"t":40,"s":[188.214,188.214,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.725,0.725,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.211,0.211,0]},"t":41,"s":[188.319,188.319,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.12,0.12,0]},"t":42,"s":[188.388,188.388,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.16,0.16,0]},"t":43,"s":[188.547,188.547,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.753,0.753,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.247,0.247,0]},"t":44,"s":[188.72,188.72,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":45,"s":[188.808,188.808,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":46,"s":[188.981,188.981,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.263,0.263,0]},"t":47,"s":[189.142,189.142,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":48,"s":[189.217,189.217,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.182,0.182,0]},"t":49,"s":[189.352,189.352,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.277,0.277,0]},"t":50,"s":[189.466,189.466,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.133,0.133,0]},"t":51,"s":[189.516,189.516,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.193,0.193,0]},"t":52,"s":[189.598,189.598,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.297,0.297,0]},"t":53,"s":[189.661,189.661,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.866,0.866,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":54,"s":[189.686,189.686,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.22,0.22,0]},"t":55,"s":[189.723,189.723,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.364,0.364,0]},"t":56,"s":[189.745,189.745,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.95,0.95,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":57,"s":[189.752,189.752,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.124,-0.124,0]},"t":58,"s":[189.758,189.758,100]},{"t":59,"s":[189.755,189.755,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,49.706],[49.709,0],[0,-49.706],[-25.828,-15.819]],"o":[[49.709,0],[0,-49.706],[-49.709,0],[0,32.504],[0,0]],"v":[[0,90],[90.006,0],[0,-90],[-90.006,0],[-46.946,76.803]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[100]},{"i":{"x":[0.833],"y":[1.059]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[100]},{"i":{"x":[0.833],"y":[0.325]},"o":{"x":[0.167],"y":[0.083]},"t":4,"s":[100]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.095]},"t":5,"s":[99.287]},{"i":{"x":[0.833],"y":[0.709]},"o":{"x":[0.167],"y":[0.19]},"t":6,"s":[94.222]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.117]},"t":7,"s":[90.268]},{"i":{"x":[0.833],"y":[0.74]},"o":{"x":[0.167],"y":[0.23]},"t":8,"s":[80.408]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":9,"s":[74.813]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":10,"s":[62.957]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.254]},"t":11,"s":[50.926]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":12,"s":[45.062]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":13,"s":[33.955]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.268]},"t":14,"s":[23.976]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":15,"s":[19.483]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.185]},"t":16,"s":[11.571]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.283]},"t":17,"s":[5.113]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[0.176]},"t":18,"s":[2.418]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[-0.202]},"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":[0.992]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[0]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.083]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.789]},"o":{"x":[0.167],"y":[0.133]},"t":38,"s":[0.096]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.138]},"t":39,"s":[0.259]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.214]},"t":40,"s":[0.507]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.348]},"t":41,"s":[0.664]},{"i":{"x":[0.833],"y":[0.92]},"o":{"x":[0.167],"y":[0.165]},"t":42,"s":[0.714]},{"i":{"x":[0.833],"y":[0.197]},"o":{"x":[0.167],"y":[-2.153]},"t":43,"s":[0.765]},{"i":{"x":[0.833],"y":[0.633]},"o":{"x":[0.167],"y":[0.093]},"t":44,"s":[0.763]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.108]},"t":45,"s":[0.747]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.144]},"t":46,"s":[0.691]},{"i":{"x":[0.833],"y":[0.741]},"o":{"x":[0.167],"y":[0.231]},"t":47,"s":[0.614]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.123]},"t":48,"s":[0.571]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.166]},"t":49,"s":[0.48]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.255]},"t":50,"s":[0.387]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":51,"s":[0.342]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.176]},"t":52,"s":[0.257]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.269]},"t":53,"s":[0.181]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.131]},"t":54,"s":[0.146]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.186]},"t":55,"s":[0.086]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.283]},"t":56,"s":[0.037]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[0.186]},"t":57,"s":[0.017]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[-0.001]},"t":58,"s":[0]},{"t":59,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"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":[135.006,135],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.033,0.284],[0,0],[2.754,-0.321],[0.8,-0.803],[0,0],[-1.309,-1.305],[-0.717,-0.101],[0,0],[-0.258,1.83]],"o":[[0,0],[-0.321,-2.754],[-1.126,0.131],[0,0],[-1.305,1.309],[0.513,0.511],[0,0],[1.83,0.258],[0.04,-0.283]],"v":[[-28.017,93.543],[-31.981,59.492],[-37.547,55.086],[-40.522,56.529],[-70.303,86.415],[-70.294,91.147],[-68.399,92.09],[-31.807,97.244],[-28.027,94.397]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":[88.125,213.428],"ix":2},"a":{"a":0,"k":[-46.875,78.428],"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":[0,0]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.941,0.941]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.325,0.325]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":4,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":5,"s":[0.713,0.713]},{"i":{"x":[0.833,0.833],"y":[0.709,0.709]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":6,"s":[5.778,5.778]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":7,"s":[9.732,9.732]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.23,0.23]},"t":8,"s":[19.592,19.592]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":9,"s":[25.187,25.187]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":10,"s":[37.043,37.043]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":11,"s":[49.074,49.074]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":12,"s":[54.938,54.938]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":13,"s":[66.045,66.045]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.268,0.268]},"t":14,"s":[76.024,76.024]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":15,"s":[80.517,80.517]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.185,0.185]},"t":16,"s":[88.429,88.429]},{"i":{"x":[0.833,0.833],"y":[0.781,0.781]},"o":{"x":[0.167,0.167],"y":[0.283,0.283]},"t":17,"s":[94.887,94.887]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":18,"s":[97.582,97.582]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":19,"s":[101.961,101.961]},{"i":{"x":[0.833,0.833],"y":[0.802,0.802]},"o":{"x":[0.167,0.167],"y":[0.31,0.31]},"t":20,"s":[105.104,105.104]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":21,"s":[106.261,106.261]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":22,"s":[107.852,107.852]},{"i":{"x":[0.833,0.833],"y":[0.999,0.999]},"o":{"x":[0.167,0.167],"y":[0.563,0.563]},"t":23,"s":[108.625,108.625]},{"i":{"x":[0.833,0.833],"y":[0.577,0.577]},"o":{"x":[0.167,0.167],"y":[-0.001,-0.001]},"t":24,"s":[108.76,108.76]},{"i":{"x":[0.833,0.833],"y":[0.858,0.858]},"o":{"x":[0.167,0.167],"y":[0.104,0.104]},"t":25,"s":[108.626,108.626]},{"i":{"x":[0.833,0.833],"y":[0.718,0.718]},"o":{"x":[0.167,0.167],"y":[0.202,0.202]},"t":26,"s":[108.083,108.083]},{"i":{"x":[0.833,0.833],"y":[0.823,0.823]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":27,"s":[107.7,107.7]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":28,"s":[106.786,106.786]},{"i":{"x":[0.833,0.833],"y":[0.752,0.752]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":29,"s":[105.759,105.759]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":30,"s":[105.23,105.23]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.171,0.171]},"t":31,"s":[104.181,104.181]},{"i":{"x":[0.833,0.833],"y":[0.765,0.765]},"o":{"x":[0.167,0.167],"y":[0.262,0.262]},"t":32,"s":[103.189,103.189]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":33,"s":[102.726,102.726]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.181,0.181]},"t":34,"s":[101.881,101.881]},{"i":{"x":[0.833,0.833],"y":[0.775,0.775]},"o":{"x":[0.167,0.167],"y":[0.275,0.275]},"t":35,"s":[101.159,101.159]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":36,"s":[100.846,100.846]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.191,0.191]},"t":37,"s":[100.314,100.314]},{"i":{"x":[0.833,0.833],"y":[0.789,0.789]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":38,"s":[99.904,99.904]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.138,0.138]},"t":39,"s":[99.741,99.741]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.214,0.214]},"t":40,"s":[99.493,99.493]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.348,0.348]},"t":41,"s":[99.336,99.336]},{"i":{"x":[0.833,0.833],"y":[0.92,0.92]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":42,"s":[99.286,99.286]},{"i":{"x":[0.833,0.833],"y":[0.197,0.197]},"o":{"x":[0.167,0.167],"y":[-2.153,-2.153]},"t":43,"s":[99.235,99.235]},{"i":{"x":[0.833,0.833],"y":[0.633,0.633]},"o":{"x":[0.167,0.167],"y":[0.093,0.093]},"t":44,"s":[99.237,99.237]},{"i":{"x":[0.833,0.833],"y":[0.801,0.801]},"o":{"x":[0.167,0.167],"y":[0.108,0.108]},"t":45,"s":[99.253,99.253]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":46,"s":[99.309,99.309]},{"i":{"x":[0.833,0.833],"y":[0.741,0.741]},"o":{"x":[0.167,0.167],"y":[0.231,0.231]},"t":47,"s":[99.386,99.386]},{"i":{"x":[0.833,0.833],"y":[0.832,0.832]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":48,"s":[99.429,99.429]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":49,"s":[99.52,99.52]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":50,"s":[99.613,99.613]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":51,"s":[99.658,99.658]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":52,"s":[99.743,99.743]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":53,"s":[99.819,99.819]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":54,"s":[99.854,99.854]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.186,0.186]},"t":55,"s":[99.914,99.914]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.283,0.283]},"t":56,"s":[99.963,99.963]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":57,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.2,0.2]},"t":58,"s":[100.017,100.017]},{"t":59,"s":[100.04,100.04]}],"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":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/spoiler_vertex.glsl b/TMessagesProj/src/main/res/raw/spoiler_vertex.glsl index 3c87b82fe..b420c1462 100644 --- a/TMessagesProj/src/main/res/raw/spoiler_vertex.glsl +++ b/TMessagesProj/src/main/res/raw/spoiler_vertex.glsl @@ -20,14 +20,15 @@ uniform float deltaTime; uniform vec2 size; uniform float r; uniform float seed; -uniform float noiseScale; -uniform float noiseSpeed; -uniform float noiseMovement; -uniform float dampingMult; -uniform float forceMult; -uniform float velocityMult; -uniform float longevity; -uniform float maxVelocity; + +#define noiseScale 6.0 +#define noiseSpeed 0.6 +#define noiseMovement 4.0 +#define longevity 1.4 +#define dampingMult .9999 +#define maxVelocity 6.0 +#define velocityMult 1.0 +#define forceMult 0.6 float rand(vec2 n) { return fract(sin(dot(n,vec2(12.9898,4.1414-seed*.42)))*4375.5453); diff --git a/TMessagesProj/src/main/res/raw/thanos_vertex.glsl b/TMessagesProj/src/main/res/raw/thanos_vertex.glsl index b7822055a..e927a2669 100644 --- a/TMessagesProj/src/main/res/raw/thanos_vertex.glsl +++ b/TMessagesProj/src/main/res/raw/thanos_vertex.glsl @@ -42,52 +42,6 @@ uniform vec2 offset; float rand(vec2 n) { return fract(sin(dot(n,vec2(12.9898,4.1414-seed*.42)))*43758.5453); } -float mod289(float x){return x-floor(x*(1./(289.+seed)))*(289.+seed);} -vec4 mod289(vec4 x){return x-floor(x*(1./(289.+seed)))*(289.0+seed);} -vec4 perm(vec4 x){return mod289(((x*34.)+1.)*x);} -float noise(vec3 p){ - - vec3 a = floor(p); - vec3 d = p - a; - d = d * d * (3. - 2. * d); - - vec4 b = a.xxyy + vec4(0., 1., 0., 1.); - vec4 k1 = perm(b.xyxy); - vec4 k2 = perm(k1.xyxy + b.zzww); - - vec4 c = k2 + a.zzzz; - vec4 k3 = perm(c); - vec4 k4 = perm(c + 1.0); - - vec4 o3 = fract(k4 / 41.0) * d.z + fract(k3 / 41.0) * (1.0 - d.z); - vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x); - - return o4.y * d.y + o4.x * (1.0 - d.y); -} -vec3 grad(vec3 p) { - const vec2 e = vec2(.1, .0); - return vec3( - noise(p + e.xyy) - noise(p - e.xyy), - noise(p + e.yxy) - noise(p - e.yxy), - noise(p + e.yyx) - noise(p - e.yyx) - ) / (2.0 * e.x); -} -vec3 curlNoise(vec3 p) { - p.xy /= size; - p.x *= (size.x / size.y); - p.xy = fract(p.xy); - p.xy *= noiseScale; - - const vec2 e = vec2(.01, .0); - return grad(p).yzx - vec3( - grad(p + e.yxy).z, - grad(p + e.yyx).x, - grad(p + e.xyy).y - ); -} -float modI(float a,float b) { - return floor(a-floor((a+0.5)/b)*b+0.5); -} float particleEaseInWindowFunction(float t) { return t; @@ -121,14 +75,14 @@ void main() { ) / gridSize.xy; position = (matrix * vec3(uv + .5 / gridSize.xy, 1.0)).xy; float direction = rand(3. * uv) * (3.14159265 * 2.0); - velocity = vec2(cos(direction), sin(direction)) * (0.1 + rand(5. * uv) * (0.2 - 0.1)) * 210.0 * dp; + velocity = vec2(cos(direction), sin(direction)) * (0.1 + rand(5. * uv) * (0.2 - 0.1)) * 260.0 * dp; particleTime = (0.7 + rand(uv) * (1.5 - 0.7)) / 1.15; } float effectFraction = max(0.0, min(0.35, time)) / 0.35; float particleFraction = max(0.0, min(0.2, .1 + time - uv.x * 0.6)) / 0.2; position += velocity * deltaTime * particleFraction; - velocity += vec2(12.0, -60.0) * deltaTime * dp * particleFraction; + velocity += vec2(19.0 * (velocity.x > 0.0 ? 1.0 : -1.0) * (1.0 - effectFraction), -65.0) * deltaTime * dp * particleFraction; particleTime = max(0.0, particleTime - 1.2 * deltaTime * effectFraction); outUV = uv; diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 486ef9e39..e34908aee 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -1179,6 +1179,8 @@ ADD CONTACT ADD %1$s TO CONTACTS VIEW CONTACT + ADD + MESSAGE Do you want to block **%1$s** from messaging and calling you on Telegram? Do you want to block messages from **%1$s**? Are you sure you want to report spam from this user? @@ -3470,7 +3472,11 @@ Privacy and Security Privacy Last Seen & Online + My Contacts and Premium users + Messages + You can restrict incoming messages to only contacts and Premium users.\n\n**What is Telegram Premium?** Voice Messages + Who can send me messages? Who can send me voice messages? You can restrict who can send you voice messages with granular precision. You can add users or entire groups as exceptions that will override the settings above. @@ -3523,6 +3529,7 @@ My Contacts (-%1$d, +%2$d) Nobody (+%1$d) Everybody + My Contacts and Premium My Contacts Nobody Everybody (-%1$d) @@ -3745,8 +3752,8 @@ Self-Destructing Video Photo has expired Video has expired - Round video has expired - Voice expired + Expired Video Message + Expired Voice Message GIF Location Live Location @@ -3755,6 +3762,8 @@ Sticker Voice message Video message + One-time Voice Message + One-time Video Message Game You You took a screenshot! @@ -3873,12 +3882,16 @@ Delete all cached text and media from this channel? Delete all cached text and media from this group? Delete %1$s + Unsave %1$s Delete message + Unsave message You can also delete the %1$s from the inboxes of other group members by checking \"Delete for all members\". You can also delete the %1$s you sent from the inboxes of other group members by checking \"Unsend my messages\". You can also delete the %1$s you sent from **%2$s**\'s inbox by checking \"Unsend my messages\". + Are you sure you want to remove this message from Saved Messages? Are you sure you want to delete this message? Are you sure you want to delete these messages? + Are you sure you want to delete these messages? Are you sure you want to delete this message for everyone? Are you sure you want to delete these messages for everyone? Unsend My Messages @@ -6065,6 +6078,9 @@ Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned or subscribe to **Telegram Premium** to double the limit to **%2$d** chats. Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned. Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned. We are working to let you increase this limit in the future. + Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned or subscribe to **Telegram Premium** to increase the limit to **%2$d** chats. + Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned. + Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned. We are working to let you increase this limit in the future. Recently active communities Are you sure you want to leave the selected chats?]]> Additional animated reactions on messages, available only to Premium subscribers. @@ -6573,7 +6589,6 @@ Automatically place recently used sticker packs at the front of the panel. Dynamic Order Off Sticker packs will no longer be placed first every time you use a sticker. - read %s **%s** restrict adding them to groups. You can send them an invite link as message instead. **%d user** restrict adding them to groups. You can send them an invite link as message instead. **%d users** restrict adding them to groups. You can send them an invite link as message instead. @@ -7962,13 +7977,84 @@ Message reposted to your profile. Message reposted to **%s**. Select Wallpaper + Saved Messages + Chats + %d chat + %d chats + %d saved message + %d saved messages + Author Hidden + Unsave messages from %s + Unsave messages from %d chats + Are you sure you want to unsave messages from %s? + Are you sure you want to unsave messages from %d chats? + OPEN CHAT + OPEN GROUP + OPEN CHANNEL This voice message can only be played once. This message will disappear once **%s** plays it once. + This video message can only be played once. + This message will disappear once **%s** plays it once. Delete and Close Close Please, turn on the sound first. Tap to set this message to **Play Once**. The recipient will be able to listen to it only once. + Tap to set this message to **Play Once**. + The recipient will be able to play it only once. Close Voice Message Are you sure you want to stop listening and delete voice message? + Close Video Message + Are you sure you want to stop listening and delete video message? + My Notes + Tap to view your **Saved Messages** organized by type or source. + Senders of these messages restricted to link their name when forwarding. + Hide Read Time + Hide the time when you read messages from people who can’t see your last seen. If you turn this on, their read time will also be hidden from you.\nThis setting does not affect group chats. + read + show when + read %s + read time unknown + Subscribe to Telegram Premium + If you subscribe to Premium, you will see other users’ last seen and read time even if you hid yours from them (unless they specifically restricted it). + Show Your Read Date + To see when **%s** read the message, either start showing your own read time... + To see when **%s** read the message, start showing your own read time. + Show My Read Time + Upgrade to Premium + Subscription will let you see **%s’s** read time without showing yours. + Subscribe to Telegram Premium + Show Your Last Seen + To see **%s** Last Seen time, either start showing your own Last Seen time... + To see **%s** Last Seen time, start showing your own Last Seen time. + Show My Last Seen + or + Upgrade to Premium + Subscription will let you see **%s’s** Last Seen status without showing yours. + Subscribe to Telegram Premium + when? + Your last seen time is now visible. + Your read times are now visible. + Premium Required + Subscribe to **Telegram Premium** to select this option. + Unlock + Subscribe to **Premium** to message **%s**. + **%s** restricted messaging to only Premium users. + Get Premium + Only Premium users can message %s.\n**Learn more...** + Only Premium users can reply to %s.\n**Learn more...** + Unlock Messaging + **%1$s** restricted who can message them in Privacy Settings. Subscribe to **Telegram Premium** to message **%2$s**. + Subscribe to Telegram Premium + Restricted Messaging + **%1$s** restricted messaging to them from only Premium users. + Show Other Messages + Hide Other Messages + **%s** only accepts messages from contacts and Premium users. + View + Replies restricted + Unlock + You need a **Premium** Subscription to reply to **%s**’s stories. + Unable to send + Only Premium users can message %s diff --git a/TMessagesProj/src/main/res/xml/actions.xml b/TMessagesProj/src/main/res/xml/actions.xml deleted file mode 100644 index d5aa5bbb3..000000000 --- a/TMessagesProj/src/main/res/xml/actions.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/xml/automotive_app_desc.xml b/TMessagesProj/src/main/res/xml/automotive_app_desc.xml new file mode 100644 index 000000000..79ec6f5e2 --- /dev/null +++ b/TMessagesProj/src/main/res/xml/automotive_app_desc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/xml/shortcuts.xml b/TMessagesProj/src/main/res/xml/shortcuts.xml index a7ff4be90..915bf731e 100644 --- a/TMessagesProj/src/main/res/xml/shortcuts.xml +++ b/TMessagesProj/src/main/res/xml/shortcuts.xml @@ -4,4 +4,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 460cd677d..b6ea21465 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=4228 -APP_VERSION_NAME=10.5.0 +APP_VERSION_CODE=4275 +APP_VERSION_NAME=10.6.1 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey