diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 04241d3b6..db6643c91 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -46,6 +46,16 @@ dependencies { implementation 'com.google.code.gson:gson:2.10' implementation 'com.google.guava:guava:31.1-android' + implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1' + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { + because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") + } + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' } @@ -108,6 +118,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"\"" buildConfigField "boolean", "DEBUG_VERSION", "true" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true" @@ -121,6 +132,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_PRIVATE") + "\"" buildConfigField "boolean", "DEBUG_VERSION", "true" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true" @@ -134,6 +146,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_PUBLIC") + "\"" buildConfigField "boolean", "DEBUG_VERSION", "true" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false" @@ -147,6 +160,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_HARDCORE") + "\"" buildConfigField "boolean", "DEBUG_VERSION", "true" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true" @@ -160,6 +174,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"\"" buildConfigField "boolean", "DEBUG_VERSION", "false" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false" @@ -174,6 +189,7 @@ android { multiDexEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro' ndk.debugSymbolLevel = 'FULL' + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\"" buildConfigField "String", "APP_CENTER_HASH", "\"\"" buildConfigField "boolean", "DEBUG_VERSION", "false" buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false" diff --git a/TMessagesProj/jni/image.cpp b/TMessagesProj/jni/image.cpp index 6169b000a..8fb78c18e 100644 --- a/TMessagesProj/jni/image.cpp +++ b/TMessagesProj/jni/image.cpp @@ -1186,6 +1186,7 @@ std::vector> gatherPositions(std::vectorGetIntArrayElements(colors, nullptr); float *newPixelCache = nullptr; + + if (width * height != pixelCacheSize && pixelCache != nullptr) { + delete[] pixelCache; + pixelCache = nullptr; + } + pixelCacheSize = width * height; + if (pixelCache == nullptr) { newPixelCache = new float[width * height * 2]; } diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp index fa53030ed..6457d8957 100644 --- a/TMessagesProj/jni/tgnet/Connection.cpp +++ b/TMessagesProj/jni/tgnet/Connection.cpp @@ -122,6 +122,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { buffer->rewind(); + NativeByteBuffer *reuseLater = nullptr; while (buffer->hasRemaining()) { if (!hasSomeDataSinceLastConnect) { currentDatacenter->storeCurrentAddressAndPortNum(); @@ -154,14 +155,11 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { if ((fByte & (1 << 7)) != 0) { buffer->position(mark); if (buffer->remaining() < 4) { - NativeByteBuffer *reuseLater = restOfTheData; + reuseLater = restOfTheData; restOfTheData = BuffersStorage::getInstance().getFreeBuffer(16384); restOfTheData->writeBytes(buffer); restOfTheData->limit(restOfTheData->position()); lastPacketLength = 0; - if (reuseLater != nullptr) { - reuseLater->reuse(); - } break; } int32_t ackId = buffer->readBigInt32(nullptr) & (~(1 << 31)); @@ -175,14 +173,11 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { buffer->position(mark); if (buffer->remaining() < 4) { if (restOfTheData == nullptr || (restOfTheData != nullptr && restOfTheData->position() != 0)) { - NativeByteBuffer *reuseLater = restOfTheData; + reuseLater = restOfTheData; restOfTheData = BuffersStorage::getInstance().getFreeBuffer(16384); restOfTheData->writeBytes(buffer); restOfTheData->limit(restOfTheData->position()); lastPacketLength = 0; - if (reuseLater != nullptr) { - reuseLater->reuse(); - } } else { restOfTheData->position(restOfTheData->limit()); } @@ -195,14 +190,11 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { } else { if (buffer->remaining() < 4) { if (restOfTheData == nullptr || (restOfTheData != nullptr && restOfTheData->position() != 0)) { - NativeByteBuffer *reuseLater = restOfTheData; + reuseLater = restOfTheData; restOfTheData = BuffersStorage::getInstance().getFreeBuffer(16384); restOfTheData->writeBytes(buffer); restOfTheData->limit(restOfTheData->position()); lastPacketLength = 0; - if (reuseLater != nullptr) { - reuseLater->reuse(); - } } else { restOfTheData->position(restOfTheData->limit()); } @@ -223,7 +215,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { if (currentProtocolType != ProtocolTypeDD && currentProtocolType != ProtocolTypeTLS && currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) { if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received invalid packet length", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType); reconnect(); - return; + break; } if (currentPacketLength < buffer->remaining()) { @@ -233,8 +225,6 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { } else { if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received packet size less(%u) then message size(%u)", this, currentDatacenter->instanceNum, currentDatacenter->getDatacenterId(), connectionType, buffer->remaining(), currentPacketLength); - NativeByteBuffer *reuseLater = nullptr; - if (restOfTheData != nullptr && restOfTheData->capacity() < len) { reuseLater = restOfTheData; restOfTheData = nullptr; @@ -248,10 +238,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { restOfTheData->limit(len); } lastPacketLength = len; - if (reuseLater != nullptr) { - reuseLater->reuse(); - } - return; + break; } uint32_t old = buffer->limit(); @@ -262,7 +249,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { if (restOfTheData != nullptr) { if ((lastPacketLength != 0 && restOfTheData->position() == lastPacketLength) || (lastPacketLength == 0 && !restOfTheData->hasRemaining())) { - restOfTheData->reuse(); + reuseLater = restOfTheData; restOfTheData = nullptr; } else { restOfTheData->compact(); @@ -276,6 +263,9 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) { parseLaterBuffer = nullptr; } } + if (reuseLater != nullptr) { + reuseLater->reuse(); + } } void Connection::connect() { diff --git a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp index c3913cd4d..9da006944 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp @@ -253,6 +253,54 @@ private: bool _isMuted = true; }; +namespace { +class AudioSinkImpl: public webrtc::AudioSinkInterface { +public: + AudioSinkImpl(std::function update) : + _update(update) { + } + + virtual ~AudioSinkImpl() { + } + + virtual void OnData(const Data& audio) override { + if (_update && audio.channels == 1) { + const int16_t *samples = (const int16_t *)audio.data; + int numberOfSamplesInFrame = (int)audio.samples_per_channel; + + int16_t currentPeak = 0; + for (int i = 0; i < numberOfSamplesInFrame; i++) { + int16_t sample = samples[i]; + if (sample < 0) { + sample = -sample; + } + if (_peak < sample) { + _peak = sample; + } + if (currentPeak < sample) { + currentPeak = sample; + } + _peakCount += 1; + } + + if (_peakCount >= 4400) { + float level = ((float)(_peak)) / 8000.0f; + _peak = 0; + _peakCount = 0; + _update(0, level); + } + } + } + +private: + std::function _update; + + int _peakCount = 0; + uint16_t _peak = 0; +}; + +} + class IncomingV2AudioChannel : public sigslot::has_slots<> { public: IncomingV2AudioChannel( @@ -261,6 +309,7 @@ public: webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, signaling::MediaContent const &mediaContent, + std::function &&onAudioLevelUpdated, std::shared_ptr threads) : _threads(threads), _ssrc(mediaContent.ssrc), @@ -278,9 +327,7 @@ public: _threads->getNetworkThread()->BlockingCall([&]() { _audioChannel->SetRtpTransport(rtpTransport); }); - - - + std::vector codecs; for (const auto &payloadType : mediaContent.payloadTypes) { cricket::AudioCodec codec(payloadType.id, payloadType.name, payloadType.clockrate, 0, payloadType.channels); @@ -317,11 +364,14 @@ public: streamParams.set_stream_ids({ streamId }); incomingAudioDescription->AddStream(streamParams); - threads->getWorkerThread()->BlockingCall([&]() { + threads->getWorkerThread()->BlockingCall([this, &outgoingAudioDescription, &incomingAudioDescription, onAudioLevelUpdated = std::move(onAudioLevelUpdated), ssrc = mediaContent.ssrc]() { _audioChannel->SetPayloadTypeDemuxingEnabled(false); std::string errorDesc; _audioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, errorDesc); _audioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, errorDesc); + + std::unique_ptr audioLevelSink(new AudioSinkImpl(std::move(onAudioLevelUpdated))); + _audioChannel->media_channel()->SetRawAudioSink(ssrc, std::move(audioLevelSink)); }); outgoingAudioDescription.reset(); @@ -1101,7 +1151,7 @@ public: mediaDeps.adm = _audioDeviceModule; - webrtc:: AudioProcessingBuilder builder; + webrtc::AudioProcessingBuilder builder; mediaDeps.audio_processing = builder.Create(); _availableVideoFormats = mediaDeps.video_encoder_factory->GetSupportedFormats(); @@ -1468,6 +1518,9 @@ public: _rtpTransport, _uniqueRandomIdGenerator.get(), content, + [audioLevelUpdated = _audioLevelUpdated](float myLvl, float level) { + audioLevelUpdated(myLvl, level); + }, _threads )); } diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 12ff1899e..fded91118 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -79,6 +79,8 @@ + + @@ -266,6 +268,9 @@ + - - + + diff --git a/TMessagesProj/src/main/assets/darkblue.attheme b/TMessagesProj/src/main/assets/darkblue.attheme index bb945993a..8c3eda0ba 100644 --- a/TMessagesProj/src/main/assets/darkblue.attheme +++ b/TMessagesProj/src/main/assets/darkblue.attheme @@ -429,7 +429,7 @@ chat_searchPanelText=-8796932 chat_inContactIcon=-1 code_comment=-2130706433 chat_outCodeBackground=857487708 -chat_inCodeBackground=856033549 +chat_inCodeBackground=-1 code_keyword=-27776 code_constant=-27776 code_function=-27776 diff --git a/TMessagesProj/src/main/assets/night.attheme b/TMessagesProj/src/main/assets/night.attheme index 1a394741d..46217ff1c 100644 --- a/TMessagesProj/src/main/assets/night.attheme +++ b/TMessagesProj/src/main/assets/night.attheme @@ -454,7 +454,7 @@ chat_searchPanelText=-10767620 chat_inContactIcon=-1 code_comment=-2130706433 chat_outCodeBackground=859062986 -chat_inCodeBackground=855638016 +chat_inCodeBackground=-1 code_keyword=-27776 code_constant=-27776 code_function=-27776 diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java index 01f4a439f..66516c7b0 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.LongSparseArray; import android.view.View; import android.view.ViewPropertyAnimator; import android.view.animation.Interpolator; @@ -14,11 +15,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.MessageObject; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.BotHelpCell; import org.telegram.ui.Cells.ChatActionCell; @@ -27,6 +30,7 @@ import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.ChatGreetingsView; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ThanosEffect; import org.telegram.ui.TextMessageEnterTransition; import org.telegram.ui.VoiceMessageEnterTransition; @@ -125,9 +129,60 @@ public class ChatListItemAnimator extends DefaultItemAnimator { return; } // First, remove stuff - for (RecyclerView.ViewHolder holder : mPendingRemovals) { - animateRemoveImpl(holder); + boolean hadThanos = false; + final boolean supportsThanos = getThanosEffectContainer != null && supportsThanosEffectContainer != null && supportsThanosEffectContainer.run(); + if (supportsThanos) { + LongSparseArray> groupsToRemoveWithThanos = null; + for (int i = 0; i < mPendingRemovals.size(); ++i) { + RecyclerView.ViewHolder holder = mPendingRemovals.get(i); + if (toBeSnapped.contains(holder) && holder.itemView instanceof ChatMessageCell && ((ChatMessageCell) holder.itemView).getCurrentMessagesGroup() != null) { + MessageObject msg = ((ChatMessageCell) holder.itemView).getMessageObject(); + if (msg != null && msg.getGroupId() != 0) { + if (groupsToRemoveWithThanos == null) { + groupsToRemoveWithThanos = new LongSparseArray<>(); + } + ArrayList holders = groupsToRemoveWithThanos.get(msg.getGroupId()); + if (holders == null) { + groupsToRemoveWithThanos.put(msg.getGroupId(), holders = new ArrayList<>()); + } + toBeSnapped.remove(holder); + mPendingRemovals.remove(i); + i--; + holders.add(holder); + } + } + } + if (groupsToRemoveWithThanos != null) { + for (int i = 0; i < groupsToRemoveWithThanos.size(); ++i) { + // check whether we remove the whole group + ArrayList holders = groupsToRemoveWithThanos.valueAt(i); + if (holders.size() <= 0) continue; + boolean wholeGroup = true; + RecyclerView.ViewHolder firstHolder = holders.get(0); + if (firstHolder.itemView instanceof ChatMessageCell) { + MessageObject.GroupedMessages group = ((ChatMessageCell) firstHolder.itemView).getCurrentMessagesGroup(); + if (group != null) { + wholeGroup = group.messages.size() <= holders.size(); + } + } + if (!wholeGroup) { + // not whole group, fallback to prev animation + mPendingRemovals.addAll(holders); + } else { + animateRemoveGroupImpl(holders); + hadThanos = true; + } + } + } } + for (RecyclerView.ViewHolder holder : mPendingRemovals) { + boolean thanos = toBeSnapped.remove(holder) && supportsThanos; + animateRemoveImpl(holder, thanos); + if (thanos) { + hadThanos = true; + } + } + final boolean finalThanos = hadThanos; mPendingRemovals.clear(); // Next, move stuff if (movesPending) { @@ -139,7 +194,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator { @Override public void run() { for (MoveInfo moveInfo : moves) { - animateMoveImpl(moveInfo.holder, moveInfo); + animateMoveImpl(moveInfo.holder, moveInfo, finalThanos); } moves.clear(); mMovesList.remove(moves); @@ -147,7 +202,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator { }; if (delayAnimations && removalsPending) { View view = moves.get(0).holder.itemView; - ViewCompat.postOnAnimationDelayed(view, mover, getMoveAnimationDelay()); + ViewCompat.postOnAnimationDelayed(view, mover, hadThanos ? 0 : getMoveAnimationDelay()); } else { mover.run(); } @@ -661,6 +716,9 @@ public class ChatListItemAnimator extends DefaultItemAnimator { @Override protected void animateMoveImpl(RecyclerView.ViewHolder holder, MoveInfo moveInfo) { + animateMoveImpl(holder, moveInfo, false); + } + protected void animateMoveImpl(RecyclerView.ViewHolder holder, MoveInfo moveInfo, boolean withThanos) { int fromX = moveInfo.fromX; int fromY = moveInfo.fromY; int toX = moveInfo.toX; @@ -843,10 +901,12 @@ public class ChatListItemAnimator extends DefaultItemAnimator { } } - if (translationInterpolator != null) { + if (withThanos) { + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); + } else if (translationInterpolator != null) { animatorSet.setInterpolator(translationInterpolator); } - animatorSet.setDuration(getMoveDuration()); + animatorSet.setDuration((long) (getMoveDuration() * (withThanos ? 1.9f : 1f))); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animator) { @@ -1372,36 +1432,72 @@ public class ChatListItemAnimator extends DefaultItemAnimator { animatorSet.start(); } - protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { + protected void animateRemoveImpl(final RecyclerView.ViewHolder holder, boolean thanos) { if (BuildVars.LOGS_ENABLED) { - FileLog.d("animate remove impl"); + FileLog.d("animate remove impl " + (thanos ? " with thanos" : "")); } final View view = holder.itemView; mRemoveAnimations.add(holder); - ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), 0f); - - dispatchRemoveStarting(holder); - - animator.setDuration(getRemoveDuration()); - animator.addListener( - new AnimatorListenerAdapter() { - - @Override - public void onAnimationEnd(Animator animator) { - animator.removeAllListeners(); - view.setAlpha(1); - view.setScaleX(1f); - view.setScaleY(1f); - view.setTranslationX(0); - view.setTranslationY(0); - if (mRemoveAnimations.remove(holder)) { - dispatchRemoveFinished(holder); - dispatchFinishedWhenDone(); + if (thanos && getThanosEffectContainer != null) { + ThanosEffect thanosEffect = getThanosEffectContainer.run(); + dispatchRemoveStarting(holder); + thanosEffect.animate(view, () -> { + view.setVisibility(View.VISIBLE); + if (mRemoveAnimations.remove(holder)) { + dispatchRemoveFinished(holder); + dispatchFinishedWhenDone(); + } + }); + } else { + ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), 0f); + dispatchRemoveStarting(holder); + animator.setDuration(getRemoveDuration()); + animator.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + animator.removeAllListeners(); + view.setAlpha(1); + view.setScaleX(1f); + view.setScaleY(1f); + view.setTranslationX(0); + view.setTranslationY(0); + if (mRemoveAnimations.remove(holder)) { + dispatchRemoveFinished(holder); + dispatchFinishedWhenDone(); + } } - } - }); - animators.put(holder, animator); - animator.start(); + }); + animators.put(holder, animator); + animator.start(); + } + recyclerListView.stopScroll(); + } + + private void animateRemoveGroupImpl(final ArrayList holders) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("animate remove group impl with thanos"); + } + mRemoveAnimations.addAll(holders); + ThanosEffect thanosEffect = getThanosEffectContainer.run(); + for (int i = 0; i < holders.size(); ++i) { + dispatchRemoveStarting(holders.get(i)); + } + final ArrayList views = new ArrayList<>(); + for (int i = 0; i < holders.size(); ++i) { + views.add(holders.get(i).itemView); + } + thanosEffect.animateGroup(views, () -> { + for (int i = 0; i < views.size(); ++i) { + views.get(i).setVisibility(View.VISIBLE); + } + if (mRemoveAnimations.removeAll(holders)) { + for (int i = 0; i < holders.size(); ++i) { + dispatchRemoveFinished(holders.get(i)); + } + dispatchFinishedWhenDone(); + } + }); recyclerListView.stopScroll(); } @@ -1502,5 +1598,27 @@ public class ChatListItemAnimator extends DefaultItemAnimator { int captionX; int captionY; } + + private final ArrayList toBeSnapped = new ArrayList<>(); + public void prepareThanos(RecyclerView.ViewHolder viewHolder) { + if (viewHolder == null) return; + toBeSnapped.add(viewHolder); + if (viewHolder.itemView instanceof ChatMessageCell) { + MessageObject msg = ((ChatMessageCell) viewHolder.itemView).getMessageObject(); + if (msg != null) { + msg.deletedByThanos = true; + } + } + } + + private Utilities.Callback0Return supportsThanosEffectContainer; + private Utilities.Callback0Return getThanosEffectContainer; + public void setOnSnapMessage( + Utilities.Callback0Return supportsThanosEffectContainer, + Utilities.Callback0Return getThanosEffectContainer + ) { + this.supportsThanosEffectContainer = supportsThanosEffectContainer; + this.getThanosEffectContainer = getThanosEffectContainer; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index c7e4b5863..1b0801312 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -4893,6 +4893,10 @@ public class AndroidUtilities { } public static void updateViewVisibilityAnimated(View view, boolean show, float scaleFactor, boolean goneOnHide, boolean animated) { + updateViewVisibilityAnimated(view, show, scaleFactor, goneOnHide, 1f, animated); + } + + public static void updateViewVisibilityAnimated(View view, boolean show, float scaleFactor, boolean goneOnHide, float maxAlpha, boolean animated) { if (view == null) { return; } @@ -4904,7 +4908,7 @@ public class AndroidUtilities { view.animate().setListener(null).cancel(); view.setVisibility(show ? View.VISIBLE : (goneOnHide ? View.GONE : View.INVISIBLE)); view.setTag(show ? 1 : null); - view.setAlpha(1f); + view.setAlpha(maxAlpha); view.setScaleX(1f); view.setScaleY(1f); } else if (show && view.getTag() == null) { @@ -4915,7 +4919,7 @@ public class AndroidUtilities { view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } - view.animate().alpha(1f).scaleY(1f).scaleX(1f).setDuration(150).start(); + view.animate().alpha(maxAlpha).scaleY(1f).scaleX(1f).setDuration(150).start(); view.setTag(1); } else if (!show && view.getTag() != null) { view.animate().setListener(null).cancel(); @@ -5112,7 +5116,7 @@ public class AndroidUtilities { ); } - public static CharSequence replaceCharSequence(String what, CharSequence from, CharSequence obj) { + public static SpannableStringBuilder replaceCharSequence(String what, CharSequence from, CharSequence obj) { SpannableStringBuilder spannableStringBuilder; if (from instanceof SpannableStringBuilder) { spannableStringBuilder = (SpannableStringBuilder) from; @@ -5241,14 +5245,14 @@ public class AndroidUtilities { canvas.restore(); } Utilities.stackBlurBitmap(bitmap, Math.max((int) amount, Math.max(w, h) / 180)); - AndroidUtilities.runOnUIThread(() -> { +// AndroidUtilities.runOnUIThread(() -> { onBitmapDone.run(bitmap); - }); +// }); } catch (Exception e) { FileLog.e(e); - AndroidUtilities.runOnUIThread(() -> { +// AndroidUtilities.runOnUIThread(() -> { onBitmapDone.run(null); - }); +// }); } // }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index a577695a5..f427f8ab3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -17,6 +17,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.net.ConnectivityManager; import android.net.Network; @@ -260,7 +262,11 @@ public class ApplicationLoader extends Application { if (BuildVars.LOGS_ENABLED) { FileLog.d("app start time = " + (startTime = SystemClock.elapsedRealtime())); - FileLog.d("buildVersion = " + BuildVars.BUILD_VERSION); + try { + FileLog.d("buildVersion = " + ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0).versionCode); + } catch (Exception e) { + FileLog.e(e); + } } if (applicationContext == null) { applicationContext = getApplicationContext(); @@ -350,6 +356,13 @@ public class ApplicationLoader extends Application { return true; } + private static long lastNetworkCheck = -1; + private static void ensureCurrentNetworkGet() { + final long now = System.currentTimeMillis(); + ensureCurrentNetworkGet(now - lastNetworkCheck > 5000); + lastNetworkCheck = now; + } + private static void ensureCurrentNetworkGet(boolean force) { if (force || currentNetworkInfo == null) { try { @@ -416,6 +429,11 @@ public class ApplicationLoader extends Application { return false; } + public static boolean useLessData() { + ensureCurrentNetworkGet(); + return BuildVars.DEBUG_PRIVATE_VERSION && (SharedConfig.forceLessData || isConnectionSlow()); + } + public static boolean isConnectionSlow() { try { ensureCurrentNetworkGet(false); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java index 6731ac65a..c55c47411 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java @@ -96,7 +96,7 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien } public String formatCurrency(long amount, String currency, int exp, boolean rounded) { - if (currency.isEmpty()) { + if (currency == null || currency.isEmpty()) { return String.valueOf(amount); } Currency cur = Currency.getInstance(currency); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 4c5454d0d..ea1601608 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,8 +24,7 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 4139; - public static String BUILD_VERSION_STRING = "10.3.2"; + public static String BUILD_VERSION_STRING = BuildConfig.BUILD_VERSION_STRING; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index 7cb7b1dd1..d3891b270 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -2107,13 +2107,13 @@ public class ChatObject { public static int getProfileColorId(TLRPC.Chat chat) { if (chat == null) return 0; -// if (chat.profile_color != null && (chat.profile_color.flags & 1) != 0) return chat.profile_color.color; + if (chat.profile_color != null && (chat.profile_color.flags & 1) != 0) return chat.profile_color.color; return -1; } public static long getProfileEmojiId(TLRPC.Chat chat) { -// if (chat != null && chat.profile_color != null && (chat.profile_color.flags & 2) != 0) return chat.profile_color.background_emoji_id; - return -1; + if (chat != null && chat.profile_color != null && (chat.profile_color.flags & 2) != 0) return chat.profile_color.background_emoji_id; + return 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java index 29cb2c552..e71d7e30b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -214,7 +214,7 @@ public class ChatThemeController extends BaseController { if (wallPaper.uploadingImage != null) { return TextUtils.equals(oldWallpaper.uploadingImage, wallPaper.uploadingImage); } - return wallPaper.id == oldWallpaper.id && TextUtils.equals(ChatBackgroundDrawable.hash(wallPaper.settings), ChatBackgroundDrawable.hash(oldWallpaper.settings)); + return wallPaper.id == oldWallpaper.id && TextUtils.equals(ChatBackgroundDrawable.hash(wallPaper.settings), ChatBackgroundDrawable.hash(oldWallpaper.settings)) && TextUtils.equals(ChatThemeController.getWallpaperEmoticon(wallPaper), ChatThemeController.getWallpaperEmoticon(oldWallpaper)); } return false; } @@ -263,6 +263,10 @@ public class ChatThemeController extends BaseController { emoticon = getEmojiSharedPreferences().getString("chatTheme_" + currentAccount + "_" + dialogId, null); dialogEmoticonsMap.put(dialogId, emoticon); } + return getTheme(emoticon); + } + + public EmojiThemes getTheme(String emoticon) { if (emoticon != null) { for (EmojiThemes theme : allChatThemes) { if (emoticon.equals(theme.getEmoticon())) { @@ -274,10 +278,10 @@ public class ChatThemeController extends BaseController { } public void saveChatWallpaper(long dialogId, TLRPC.WallPaper wallPaper) { - if (dialogId < 0) { - return; - } if (wallPaper != null) { + if (wallPaper.document == null) { + return; + } SerializedData data = new SerializedData(wallPaper.getObjectSize()); wallPaper.serializeToStream(data); String wallpaperString = Utilities.bytesToHex(data.toByteArray()); @@ -293,12 +297,16 @@ public class ChatThemeController extends BaseController { } public TLRPC.WallPaper getDialogWallpaper(long dialogId) { - if (dialogId < 0) { - return null; - } - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); - if (userFull != null) { - return userFull.wallpaper; + if (dialogId >= 0) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + return userFull.wallpaper; + } + } else { + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + return chatFull.wallpaper; + } } String wallpaperString = getEmojiSharedPreferences().getString("chatWallpaper_" + currentAccount + "_" + dialogId, null); if (wallpaperString != null) { @@ -411,30 +419,75 @@ public class ChatThemeController extends BaseController { return; } final long dialogId = userFull.id; - userFull.wallpaper_overridden = update.wallpaper_overridden; - userFull.wallpaper = update.wallpaper; - userFull.flags |= 16777216; + if ((update.flags & 1) != 0) { + userFull.wallpaper_overridden = update.wallpaper_overridden; + userFull.wallpaper = update.wallpaper; + userFull.flags |= 16777216; + } else { + userFull.wallpaper_overridden = false; + userFull.wallpaper = null; + userFull.flags &=~ 16777216; + } getMessagesStorage().updateUserInfo(userFull, false); - saveChatWallpaper(dialogId, null); + saveChatWallpaper(dialogId, userFull.wallpaper); AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); }); } } else { - // todo + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-DialogObject.getPeerDialogId(update.peer)); + if (chatFull != null) { + if (wallpaperEquals(chatFull.wallpaper, update.wallpaper)) { + return; + } + final long dialogId = -chatFull.id; + if ((update.flags & 1) != 0) { + chatFull.wallpaper = update.wallpaper; + chatFull.flags2 |= 128; + } else { + chatFull.wallpaper = null; + chatFull.flags2 &=~ 128; + } + getMessagesStorage().updateChatInfo(chatFull, false); + saveChatWallpaper(dialogId, chatFull.wallpaper); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); + }); + } } } public static boolean wallpaperEquals(TLRPC.WallPaper a, TLRPC.WallPaper b) { - if ((a == null || a instanceof TLRPC.TL_wallPaperNoFile) && (b == null || b instanceof TLRPC.TL_wallPaperNoFile)) { + if (a == null && b == null) { return true; } if (a instanceof TLRPC.TL_wallPaper && b instanceof TLRPC.TL_wallPaper) { return a.id == b.id; } + if (a instanceof TLRPC.TL_wallPaperNoFile && b instanceof TLRPC.TL_wallPaperNoFile) { + if (a.settings != null && b.settings != null) { + return TextUtils.equals(getWallpaperEmoticon(a), getWallpaperEmoticon(b)); + } + return a.id == b.id; + } return false; } + public static String getWallpaperEmoticon(TLRPC.WallPaper a) { + if (a != null) { + if (a.settings != null && !TextUtils.isEmpty(a.settings.emoticon)) { + return a.settings.emoticon; + } + return ""; + } + return null; + } + + public static boolean isNotEmoticonWallpaper(TLRPC.WallPaper a) { + String emoticon = getWallpaperEmoticon(a); + return emoticon != null && emoticon.length() == 0; + } + public void clearWallpaper(long dialogId, boolean notify) { clearWallpaper(dialogId, notify, false); } @@ -460,6 +513,16 @@ public class ChatThemeController extends BaseController { } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); req.peer = MessagesController.getInputPeer(chat); + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + chatFull.wallpaper = null; + chatFull.flags2 &= ~128; + getMessagesStorage().updateChatInfo(chatFull, false); + } + saveChatWallpaper(dialogId, null); + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); + } } getConnectionsManager().sendRequest(req, (response, error) -> { @@ -467,13 +530,12 @@ public class ChatThemeController extends BaseController { }); } - public int setWallpaperToUser(long dialogId, String wallpaperLocalPath, Theme.OverrideWallpaperInfo wallpaperInfo, MessageObject serverWallpaper, Runnable callback) { + public int setWallpaperToPeer(long dialogId, String wallpaperLocalPath, Theme.OverrideWallpaperInfo wallpaperInfo, MessageObject serverWallpaper, Runnable callback) { TLRPC.TL_messages_setChatWallPaper req = new TLRPC.TL_messages_setChatWallPaper(); - if (dialogId > 0) { + if (dialogId >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); req.peer = MessagesController.getInputPeer(user); } else { - //chat not supported yet TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); req.peer = MessagesController.getInputPeer(chat); } @@ -484,52 +546,71 @@ public class ChatThemeController extends BaseController { req.flags |= 2; req.id = serverWallpaper.getId(); - TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + TLRPC.UserFull userFull = null; + TLRPC.ChatFull chatFull = null; + if (dialogId >= 0) { + userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + } else { + chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + } + + TLRPC.TL_messageActionSetChatWallPaper action = (TLRPC.TL_messageActionSetChatWallPaper) serverWallpaper.messageOwner.action; + TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); + wallPaper.id = action.wallpaper.id; + wallPaper.document = action.wallpaper.document; + wallPaper.settings = new TLRPC.TL_wallPaperSettings(); + wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); + wallPaper.settings.motion = wallpaperInfo.isMotion; + wallPaper.settings.blur = wallpaperInfo.isBlurred; + wallPaper.settings.background_color = wallpaperInfo.color; + wallPaper.settings.second_background_color = wallpaperInfo.gradientColor1; + wallPaper.settings.third_background_color = wallpaperInfo.gradientColor2; + wallPaper.settings.fourth_background_color = wallpaperInfo.gradientColor3; + wallPaper.settings.rotation = wallpaperInfo.rotation; + wallPaper.uploadingImage = wallpaperLocalPath; + TLRPC.WallPaper pastWallpaper = null; if (userFull != null) { - TLRPC.TL_messageActionSetChatWallPaper action = (TLRPC.TL_messageActionSetChatWallPaper) serverWallpaper.messageOwner.action; - TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); - wallPaper.id = action.wallpaper.id; - wallPaper.document = action.wallpaper.document; - wallPaper.settings = new TLRPC.TL_wallPaperSettings(); - wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); - wallPaper.settings.motion = wallpaperInfo.isMotion; - wallPaper.settings.blur = wallpaperInfo.isBlurred; - wallPaper.settings.background_color = wallpaperInfo.color; - wallPaper.settings.second_background_color = wallpaperInfo.gradientColor1; - wallPaper.settings.third_background_color = wallpaperInfo.gradientColor2; - wallPaper.settings.fourth_background_color = wallpaperInfo.gradientColor3; - wallPaper.settings.rotation = wallpaperInfo.rotation; - wallPaper.uploadingImage = wallpaperLocalPath; - if (userFull.wallpaper != null && userFull.wallpaper.uploadingImage != null && userFull.wallpaper.uploadingImage.equals(wallPaper.uploadingImage)) { - wallPaper.stripedThumb = userFull.wallpaper.stripedThumb; - } + pastWallpaper = userFull.wallpaper; + } else if (chatFull != null) { + pastWallpaper = chatFull.wallpaper; + } + if (pastWallpaper != null && pastWallpaper.uploadingImage != null && pastWallpaper.uploadingImage.equals(wallPaper.uploadingImage)) { + wallPaper.stripedThumb = pastWallpaper.stripedThumb; + } - wallPaper.settings.flags |= 1; - wallPaper.settings.flags |= 8; - wallPaper.settings.flags |= 16; - wallPaper.settings.flags |= 32; - wallPaper.settings.flags |= 64; + wallPaper.settings.flags |= 1; + wallPaper.settings.flags |= 8; + wallPaper.settings.flags |= 16; + wallPaper.settings.flags |= 32; + wallPaper.settings.flags |= 64; - userFull.wallpaper = new TLRPC.TL_wallPaper(); - userFull.wallpaper.pattern = action.wallpaper.pattern; - userFull.wallpaper.id = action.wallpaper.id; - userFull.wallpaper.document = action.wallpaper.document; - userFull.wallpaper.flags = action.wallpaper.flags; - userFull.wallpaper.creator = action.wallpaper.creator; - userFull.wallpaper.dark = action.wallpaper.dark; - userFull.wallpaper.isDefault = action.wallpaper.isDefault; - userFull.wallpaper.slug = action.wallpaper.slug; - userFull.wallpaper.access_hash = action.wallpaper.access_hash; - userFull.wallpaper.stripedThumb = action.wallpaper.stripedThumb; - userFull.wallpaper.settings = wallPaper.settings; - userFull.wallpaper.flags |= 4; + TLRPC.TL_wallPaper wallpaper = new TLRPC.TL_wallPaper(); + wallpaper.pattern = action.wallpaper.pattern; + wallpaper.id = action.wallpaper.id; + wallpaper.document = action.wallpaper.document; + wallpaper.flags = action.wallpaper.flags; + wallpaper.creator = action.wallpaper.creator; + wallpaper.dark = action.wallpaper.dark; + wallpaper.isDefault = action.wallpaper.isDefault; + wallpaper.slug = action.wallpaper.slug; + wallpaper.access_hash = action.wallpaper.access_hash; + wallpaper.stripedThumb = action.wallpaper.stripedThumb; + wallpaper.settings = wallPaper.settings; + wallpaper.flags |= 4; + if (userFull != null) { + userFull.wallpaper = wallpaper; userFull.flags |= 16777216; - getMessagesStorage().updateUserInfo(userFull, false); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); - if (callback != null) { - callback.run(); - } + } else if (chatFull != null) { + chatFull.wallpaper = wallpaper; + chatFull.flags2 |= 128; + getMessagesStorage().updateChatInfo(chatFull, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); + } + + if (callback != null) { + callback.run(); } } else { req.flags |= 1; @@ -543,27 +624,44 @@ public class ChatThemeController extends BaseController { return ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.Updates) { TLRPC.Updates res = (TLRPC.Updates) response; - TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + TLRPC.UserFull userFull = null; + TLRPC.ChatFull chatFull = null; + if (dialogId >= 0) { + userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + } else { + chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + } + TLRPC.WallPaper pastWallpaper = null; if (userFull != null) { - for (int i = 0; i < res.updates.size(); i++) { - if (res.updates.get(i) instanceof TLRPC.TL_updateNewMessage) { - TLRPC.Message message = ((TLRPC.TL_updateNewMessage) res.updates.get(i)).message; - if (message.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { - if (finalApplyOnRequest) { - TLRPC.TL_messageActionSetChatWallPaper actionSetChatWallPaper = (TLRPC.TL_messageActionSetChatWallPaper) message.action; - actionSetChatWallPaper.wallpaper.uploadingImage = wallpaperLocalPath; - if (userFull.wallpaper != null && userFull.wallpaper.uploadingImage != null && userFull.wallpaper.uploadingImage.equals(actionSetChatWallPaper.wallpaper.uploadingImage)) { - actionSetChatWallPaper.wallpaper.stripedThumb = userFull.wallpaper.stripedThumb; - } + pastWallpaper = userFull.wallpaper; + } else if (chatFull != null) { + pastWallpaper = chatFull.wallpaper; + } + for (int i = 0; i < res.updates.size(); i++) { + if (res.updates.get(i) instanceof TLRPC.TL_updateNewMessage) { + TLRPC.Message message = ((TLRPC.TL_updateNewMessage) res.updates.get(i)).message; + if (message.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { + if (finalApplyOnRequest) { + TLRPC.TL_messageActionSetChatWallPaper actionSetChatWallPaper = (TLRPC.TL_messageActionSetChatWallPaper) message.action; + actionSetChatWallPaper.wallpaper.uploadingImage = wallpaperLocalPath; + if (pastWallpaper != null && pastWallpaper.uploadingImage != null && pastWallpaper.uploadingImage.equals(actionSetChatWallPaper.wallpaper.uploadingImage)) { + actionSetChatWallPaper.wallpaper.stripedThumb = pastWallpaper.stripedThumb; + } + if (userFull != null) { userFull.wallpaper = actionSetChatWallPaper.wallpaper; userFull.flags |= 16777216; - saveChatWallpaper(dialogId, userFull.wallpaper); getMessagesStorage().updateUserInfo(userFull, false); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + } else if (chatFull != null) { + chatFull.wallpaper = actionSetChatWallPaper.wallpaper; + chatFull.flags2 |= 128; + saveChatWallpaper(dialogId, chatFull.wallpaper); + getMessagesStorage().updateChatInfo(chatFull, false); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); } - break; } + break; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java index 1bf846e35..8b269fdcf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java @@ -163,4 +163,26 @@ public class DialogObject { } return null; } + + public static long getEmojiStatusDocumentId(TLRPC.EmojiStatus emojiStatus) { + if (emojiStatus instanceof TLRPC.TL_emojiStatus) { + return ((TLRPC.TL_emojiStatus) emojiStatus).document_id; + } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { + return ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id; + } else { + return 0; + } + } + + public static int getEmojiStatusUntil(TLRPC.EmojiStatus emojiStatus) { + if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { + return ((TLRPC.TL_emojiStatusUntil) emojiStatus).until; + } + return 0; + } + + public static boolean emojiStatusesEqual(TLRPC.EmojiStatus a, TLRPC.EmojiStatus b) { + return getEmojiStatusDocumentId(a) == getEmojiStatusDocumentId(b) && getEmojiStatusUntil(a) == getEmojiStatusUntil(b); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index bb4bdedc3..d1de09781 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -2102,7 +2102,7 @@ public class FileLoadOperation { requestingReference = true; if (parentObject instanceof MessageObject) { MessageObject messageObject = (MessageObject) parentObject; - if (messageObject.getId() < 0 && messageObject.messageOwner.media.webpage != null) { + if (messageObject.getId() < 0 && messageObject.messageOwner != null && messageObject.messageOwner.media != null && messageObject.messageOwner.media.webpage != null) { parentObject = messageObject.messageOwner.media.webpage; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 9f4fa3c08..0ba4d9047 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -887,7 +887,7 @@ public class FileLoader extends BaseController { } else { storeDir = getDirectory(type); } - } else if (cacheType == 2) { + } else if (cacheType == ImageLoader.CACHE_TYPE_ENCRYPTED) { operation.setEncryptFile(true); } operation.setPaths(currentAccount, fileName, loaderQueue, storeDir, tempDir, storeFileName); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index 570f956d2..32682a310 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -248,7 +248,7 @@ public class FileRefController extends BaseController { } if (parentObject instanceof MessageObject) { MessageObject messageObject = (MessageObject) parentObject; - if (messageObject.getRealId() < 0 && messageObject.messageOwner.media.webpage != null) { + if (messageObject.getRealId() < 0 && messageObject.messageOwner != null && messageObject.messageOwner.media != null && messageObject.messageOwner.media.webpage != null) { parentObject = messageObject.messageOwner.media.webpage; } } @@ -1087,6 +1087,9 @@ public class FileRefController extends BaseController { if (storyItem.media.document != null) { result = getFileReference(storyItem.media.document, requester.location, needReplacement, locationReplacement); } + if (storyItem.media.alt_document != null) { + result = getFileReference(storyItem.media.alt_document, requester.location, needReplacement, locationReplacement); + } } } Object arg = requester.args[1]; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index bdec42be0..653409b0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -103,6 +103,10 @@ import java.util.zip.GZIPInputStream; */ public class ImageLoader { + public static final int CACHE_TYPE_NONE = 0; + public static final int CACHE_TYPE_CACHE = 1; + public static final int CACHE_TYPE_ENCRYPTED = 2; + private static final boolean DEBUG_MODE = false; private HashMap bitmapUseCounts = new HashMap<>(); @@ -4225,7 +4229,7 @@ public class ImageLoader { } else { File file = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(photoSize, true); boolean isEncrypted = false; - if (MessageObject.shouldEncryptPhotoOrVideo(message)) { + if (MessageObject.shouldEncryptPhotoOrVideo(UserConfig.selectedAccount, message)) { file = new File(file.getAbsolutePath() + ".enc"); isEncrypted = true; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 26d7d02cf..bfa725edf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1017,7 +1017,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } else if (bitmapDrawable instanceof AnimatedFileDrawable) { AnimatedFileDrawable animatedFileDrawable = (AnimatedFileDrawable) drawable; animatedFileDrawable.setRoundRadius(roundRadius); - } else if (bitmapDrawable.getBitmap() != null) { + } else if (bitmapDrawable.getBitmap() != null && !bitmapDrawable.getBitmap().isRecycled()) { setDrawableShader(drawable, new BitmapShader(bitmapDrawable.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java b/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java index c48221982..f299997c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java @@ -39,7 +39,8 @@ public class LiteMode { public static final int FLAG_CHAT_SPOILER = 128; public static final int FLAG_CHAT_BLUR = 256; public static final int FLAG_CHAT_SCALE = 32768; - public static final int FLAGS_CHAT = FLAG_CHAT_BACKGROUND | FLAG_CHAT_FORUM_TWOCOLUMN | FLAG_CHAT_SPOILER | FLAG_CHAT_BLUR | FLAG_CHAT_SCALE; + public static final int FLAG_CHAT_THANOS = 65536; + public static final int FLAGS_CHAT = FLAG_CHAT_BACKGROUND | FLAG_CHAT_FORUM_TWOCOLUMN | FLAG_CHAT_SPOILER | FLAG_CHAT_BLUR | FLAG_CHAT_SCALE | FLAG_CHAT_THANOS; public static final int FLAG_CALLS_ANIMATIONS = 512; public static final int FLAG_AUTOPLAY_VIDEOS = 1024; @@ -49,8 +50,9 @@ public class LiteMode { FLAG_ANIMATED_EMOJI_CHAT_PREMIUM | FLAG_ANIMATED_EMOJI_KEYBOARD_PREMIUM | FLAG_ANIMATED_EMOJI_REACTIONS_PREMIUM | - FLAG_AUTOPLAY_GIFS - ); // 2076 + FLAG_AUTOPLAY_GIFS | + FLAG_CHAT_THANOS + ); // 67612 public static int PRESET_MEDIUM = ( FLAGS_ANIMATED_STICKERS | FLAG_ANIMATED_EMOJI_KEYBOARD_PREMIUM | @@ -59,16 +61,18 @@ public class LiteMode { FLAG_CHAT_FORUM_TWOCOLUMN | FLAG_CALLS_ANIMATIONS | FLAG_AUTOPLAY_VIDEOS | - FLAG_AUTOPLAY_GIFS - ); // 7775 + FLAG_AUTOPLAY_GIFS | + FLAG_CHAT_THANOS + ); // 73311 public static int PRESET_HIGH = ( FLAGS_ANIMATED_STICKERS | FLAGS_ANIMATED_EMOJI | FLAGS_CHAT | FLAG_CALLS_ANIMATIONS | FLAG_AUTOPLAY_VIDEOS | - FLAG_AUTOPLAY_GIFS - ); // 65535 + FLAG_AUTOPLAY_GIFS | + FLAG_CHAT_THANOS + ); // 131071 public static int PRESET_POWER_SAVER = 0; private static int BATTERY_LOW = 10; @@ -196,8 +200,12 @@ public class LiteMode { } final SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - if (!preferences.contains("lite_mode2")) { - if (preferences.contains("lite_mode")) { + if (!preferences.contains("lite_mode3")) { + if (preferences.contains("lite_mode2")) { + defaultValue = preferences.getInt("lite_mode2", defaultValue); + defaultValue |= FLAG_CHAT_THANOS; + preferences.edit().putInt("lite_mode3", defaultValue).apply(); + } else if (preferences.contains("lite_mode")) { defaultValue = preferences.getInt("lite_mode", defaultValue); if (defaultValue == 4095) { defaultValue = PRESET_HIGH; @@ -248,7 +256,7 @@ public class LiteMode { } int prevValue = value; - value = preferences.getInt("lite_mode2", defaultValue); + value = preferences.getInt("lite_mode3", defaultValue); if (loaded) { onFlagsUpdate(prevValue, value); } @@ -257,7 +265,7 @@ public class LiteMode { } public static void savePreference() { - MessagesController.getGlobalMainSettings().edit().putInt("lite_mode2", value).putInt("lite_mode_battery_level", powerSaverLevel).apply(); + MessagesController.getGlobalMainSettings().edit().putInt("lite_mode3", value).putInt("lite_mode_battery_level", powerSaverLevel).apply(); } public static int getPowerSaverLevel() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 8593d8d63..50c45f8c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1061,10 +1061,10 @@ public class LocaleController { } private String getStringInternal(String key, int res) { - return getStringInternal(key, null, res); + return getStringInternal(key, null, 0, res); } - private String getStringInternal(String key, String fallback, int res) { + private String getStringInternal(String key, String fallback, int fallbackRes, int res) { String value = BuildVars.USE_CLOUD_STRINGS ? localeValues.get(key) : null; if (value == null) { if (BuildVars.USE_CLOUD_STRINGS && fallback != null) { @@ -1074,6 +1074,11 @@ public class LocaleController { try { value = ApplicationLoader.applicationContext.getString(res); } catch (Exception e) { + if (fallbackRes != 0) { + try { + value = ApplicationLoader.applicationContext.getString(fallbackRes); + } catch (Exception ignored) {} + } FileLog.e(e); } } @@ -1107,8 +1112,12 @@ public class LocaleController { return getInstance().getStringInternal(key, res); } + public static String getString(String key, String fallback, int fallbackRes, int res) { + return getInstance().getStringInternal(key, fallback, fallbackRes, res); + } + public static String getString(String key, String fallback, int res) { - return getInstance().getStringInternal(key, fallback, res); + return getInstance().getStringInternal(key, fallback, 0, res); } public static String getString(String key) { @@ -1129,7 +1138,8 @@ public class LocaleController { String param = getInstance().stringForQuantity(getInstance().currentPluralRules.quantityForNumber(plural)); param = key + "_" + param; int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); - return getString(param, key + "_other", resourceId); + int fallbackResourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(key + "_other", "string", ApplicationLoader.applicationContext.getPackageName()); + return getString(param, key + "_other", resourceId, fallbackResourceId); } public static String formatPluralString(String key, int plural, Object... args) { @@ -1146,6 +1156,10 @@ public class LocaleController { return formatString(param, key + "_other", resourceId, fallbackResourceId, argsWithPlural); } + public static String getStringParamForNumber(int number) { + return getInstance().stringForQuantity(getInstance().currentPluralRules.quantityForNumber(number)); + } + public static String formatPluralStringComma(String key, int plural) { return formatPluralStringComma(key, plural, ','); } @@ -1611,6 +1625,24 @@ public class LocaleController { return "LOC_ERR: formatDateChat"; } + public static String formatSmallDateChat(long date) { + try { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + int currentYear = calendar.get(Calendar.YEAR); + date *= 1000; + + calendar.setTimeInMillis(date); + if (currentYear == calendar.get(Calendar.YEAR)) { + return getInstance().formatterDayMonth.format(date); + } + return getInstance().formatterDayMonth.format(date) + ", " + calendar.get(Calendar.YEAR); + } catch (Exception e) { + FileLog.e(e); + } + return "LOC_ERR: formatDateChat"; + } + public static String formatDate(long date) { try { date *= 1000; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index bf26ad48b..5911e3704 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -779,6 +779,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, private int sendAfterDone; private boolean sendAfterDoneNotify; private int sendAfterDoneScheduleDate; + private boolean sendAfterDoneOnce; private Runnable recordStartRunnable; private DispatchQueue recordQueue; @@ -867,7 +868,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } else { recordBuffers.add(buffer); if (sendAfterDone != 3) { - stopRecordingInternal(sendAfterDone, sendAfterDoneNotify, sendAfterDoneScheduleDate); + stopRecordingInternal(sendAfterDone, sendAfterDoneNotify, sendAfterDoneScheduleDate, sendAfterDoneOnce); } } } @@ -1133,7 +1134,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (isPlayingMessage(playingMessageObject) && !isMessagePaused()) { pauseMessage(playingMessageObject); } else if (recordStartRunnable != null || recordingAudio != null) { - stopRecording(2, false, 0); + stopRecording(2, false, 0, false); } EmbedBottomSheet embedBottomSheet = EmbedBottomSheet.getInstance(); if (embedBottomSheet != null) { @@ -1585,6 +1586,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, int addedCount = 0; for (int a = 0; a < arr.size(); a++) { MessageObject message = arr.get(a); + if (message.isVoiceOnce()) continue; if (playlistMap.containsKey(message.getId())) { continue; } @@ -1618,7 +1620,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, ArrayList arr = (ArrayList) args[1]; for (int a = 0; a < arr.size(); a++) { messageObject = arr.get(a); - if ((messageObject.isVoice() || messageObject.isRoundVideo()) && (!voiceMessagesPlaylistUnread || messageObject.isContentUnread() && !messageObject.isOut())) { + if ((messageObject.isVoice() || messageObject.isRoundVideo()) && !messageObject.isVoiceOnce() && !messageObject.isRoundOnce() && (!voiceMessagesPlaylistUnread || messageObject.isContentUnread() && !messageObject.isOut())) { voiceMessagesPlaylist.add(messageObject); voiceMessagesPlaylistMap.put(messageObject.getId(), messageObject); } @@ -1913,7 +1915,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (BuildVars.LOGS_ENABLED) { FileLog.d("stop record"); } - stopRecording(2, false, 0); + stopRecording(2, false, 0, false); raiseToEarRecord = false; ignoreOnPause = false; // if (!ignoreAccelerometerGestures() && proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { @@ -2051,7 +2053,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, return; } if (stopRecording) { - stopRecording(fromChat ? 2 : 0, false, 0); + stopRecording(fromChat ? 2 : 0, false, 0, false); } if (!sensorsStarted || ignoreOnPause || accelerometerSensor == null && (gravitySensor == null || linearAcceleration == null) || proximitySensor == null || raiseChat != chatActivity) { return; @@ -2361,6 +2363,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, int addedCount = 0; for (int i = 0; i < n; i++) { MessageObject messageObject = new MessageObject(currentAccount, res.messages.get(i), false, true); + if (messageObject.isVoiceOnce()) continue; if (playlistMap.containsKey(messageObject.getId())) { continue; } @@ -3761,6 +3764,9 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } public boolean isPlayingMessage(MessageObject messageObject) { + if (messageObject != null && messageObject.isRepostPreview) { + return false; + } if (audioPlayer == null && videoPlayer == null || messageObject == null || playingMessageObject == null) { return false; } @@ -3954,7 +3960,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, }); } - private void stopRecordingInternal(final int send, boolean notify, int scheduleDate) { + private void stopRecordingInternal(final int send, boolean notify, int scheduleDate, boolean once) { if (send != 0) { final TLRPC.TL_document audioToSend = recordingAudio; final File recordingAudioFileToSend = recordingAudioFile; @@ -3987,7 +3993,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, audioToSend.attributes.add(attributeAudio); if (duration > 700) { if (send == 1) { - SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMsg, recordReplyingTopMsg, null, null, null, null, notify, scheduleDate, 0, null, null, false); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMsg, recordReplyingTopMsg, null, null, null, null, notify, scheduleDate, once ? 0x7FFFFFFF : 0, null, null, false); params.replyToStoryItem = recordReplyingStory; SendMessagesHelper.getInstance(recordingCurrentAccount).sendMessage(params); } @@ -4020,7 +4026,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, manualRecording = false; } - public void stopRecording(final int send, boolean notify, int scheduleDate) { + public void stopRecording(final int send, boolean notify, int scheduleDate, boolean once) { if (recordStartRunnable != null) { recordQueue.cancelRunnable(recordStartRunnable); recordStartRunnable = null; @@ -4028,7 +4034,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, recordQueue.postRunnable(() -> { if (sendAfterDone == 3) { sendAfterDone = 0; - stopRecordingInternal(send, notify, scheduleDate); + stopRecordingInternal(send, notify, scheduleDate, once); return; } if (audioRecorder == null) { @@ -4038,6 +4044,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, sendAfterDone = send; sendAfterDoneNotify = notify; sendAfterDoneScheduleDate = scheduleDate; + sendAfterDoneOnce = once; audioRecorder.stop(); setBluetoothScoOn(false); } catch (Exception e) { @@ -4050,7 +4057,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } } if (send == 0) { - stopRecordingInternal(0, false, 0); + stopRecordingInternal(0, false, 0, false); } try { feedbackView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); @@ -5018,12 +5025,13 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, thread.start(); } + public static boolean forceBroadcastNewPhotos; private static void broadcastNewPhotos(final int guid, final ArrayList mediaAlbumsSorted, final ArrayList photoAlbumsSorted, final Integer cameraAlbumIdFinal, final AlbumEntry allMediaAlbumFinal, final AlbumEntry allPhotosAlbumFinal, final AlbumEntry allVideosAlbumFinal, int delay) { if (broadcastPhotosRunnable != null) { AndroidUtilities.cancelRunOnUIThread(broadcastPhotosRunnable); } AndroidUtilities.runOnUIThread(broadcastPhotosRunnable = () -> { - if (PhotoViewer.getInstance().isVisible()) { + if (PhotoViewer.getInstance().isVisible() && !forceBroadcastNewPhotos) { broadcastNewPhotos(guid, mediaAlbumsSorted, photoAlbumsSorted, cameraAlbumIdFinal, allMediaAlbumFinal, allPhotosAlbumFinal, allVideosAlbumFinal, 1000); return; } @@ -5376,20 +5384,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, framerate, bitrate, originalBitrate, startTime, endTime, avatarStartTime, needCompress, duration, - info.filterState, - info.paintPath, - info.blurPath, - info.mediaEntities, - info.isPhoto, - info.cropState, - info.roundVideo, callback, - info.gradientTopColor, - info.gradientBottomColor, - info.muted, - info.isStory, - info.hdrInfo, - info.parts); + info); convertVideoParams.soundInfos.addAll(info.mixedSoundInfos); boolean error = videoConvertor.convertVideo(convertVideoParams); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index c577da7e1..7b597bcab 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -260,6 +260,7 @@ public class MediaDataController extends BaseController { private LongSparseArray groupStickerSets = new LongSparseArray<>(); private ConcurrentHashMap stickerSetsByName = new ConcurrentHashMap<>(100, 1.0f, 1); private TLRPC.TL_messages_stickerSet stickerSetDefaultStatuses = null; + private TLRPC.TL_messages_stickerSet stickerSetDefaultChannelStatuses = null; private HashMap diceStickerSetsByEmoji = new HashMap<>(); private LongSparseArray diceEmojiStickerSetsById = new LongSparseArray<>(); private HashSet loadingDiceStickerSets = new HashSet<>(); @@ -317,11 +318,11 @@ public class MediaDataController extends BaseController { public final ArrayList premiumPreviewStickers = new ArrayList<>(); boolean previewStickersLoading; - private long[] emojiStatusesHash = new long[2]; - private ArrayList[] emojiStatuses = new ArrayList[2]; - private Long[] emojiStatusesFetchDate = new Long[2]; - private boolean[] emojiStatusesFromCacheFetched = new boolean[2]; - private boolean[] emojiStatusesFetching = new boolean[2]; + private long[] emojiStatusesHash = new long[4]; + private ArrayList[] emojiStatuses = new ArrayList[4]; + private Long[] emojiStatusesFetchDate = new Long[4]; + private boolean[] emojiStatusesFromCacheFetched = new boolean[4]; + private boolean[] emojiStatusesFetching = new boolean[4]; public void cleanup() { for (int a = 0; a < recentStickers.length; a++) { @@ -1217,6 +1218,8 @@ public class MediaDataController extends BaseController { cacheSet = stickerSetsByName.get(inputStickerSet.short_name.toLowerCase()); } else if (inputStickerSet instanceof TLRPC.TL_inputStickerSetEmojiDefaultStatuses && stickerSetDefaultStatuses != null) { cacheSet = stickerSetDefaultStatuses; + } else if (inputStickerSet instanceof TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses && stickerSetDefaultChannelStatuses != null) { + cacheSet = stickerSetDefaultChannelStatuses; } if (cacheSet != null) { if (onResponse != null) { @@ -1264,6 +1267,9 @@ public class MediaDataController extends BaseController { if (inputStickerSet instanceof TLRPC.TL_inputStickerSetEmojiDefaultStatuses) { stickerSetDefaultStatuses = set; } + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetEmojiDefaultStatuses) { + stickerSetDefaultChannelStatuses = set; + } } saveStickerSetIntoCache(set); getNotificationCenter().postNotificationName(NotificationCenter.groupStickersDidLoad, set.set.id, set); @@ -5567,6 +5573,13 @@ public class MediaDataController extends BaseController { } } + if (channelId != 0 && messageObject.getDialogId() != -channelId) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(channelId); + if (chat != null && !ChatObject.isPublic(chat)) { + continue; + } + } + SparseArray> sparseArray = replyMessageOwners.get(dialogId); ArrayList ids = dialogReplyMessagesIds.get(channelId); if (sparseArray == null) { @@ -8180,6 +8193,16 @@ public class MediaDataController extends BaseController { return emojiStatuses[type]; } + public ArrayList getDefaultChannelEmojiStatuses() { + final int type = 2; // default channel + if (!emojiStatusesFromCacheFetched[type]) { + fetchEmojiStatuses(type, true); + } else if (emojiStatuses[type] == null || emojiStatusesFetchDate[type] != null && (System.currentTimeMillis() / 1000 - emojiStatusesFetchDate[type]) > 60 * 30) { + fetchEmojiStatuses(type, false); + } + return emojiStatuses[type]; + } + public ArrayList getRecentEmojiStatuses() { final int type = 0; // recent if (!emojiStatusesFromCacheFetched[type]) { @@ -8271,10 +8294,14 @@ public class MediaDataController extends BaseController { TLRPC.TL_account_getRecentEmojiStatuses recentReq = new TLRPC.TL_account_getRecentEmojiStatuses(); recentReq.hash = emojiStatusesHash[type]; req = recentReq; - } else { + } else if (type == 1) { TLRPC.TL_account_getDefaultEmojiStatuses defaultReq = new TLRPC.TL_account_getDefaultEmojiStatuses(); defaultReq.hash = emojiStatusesHash[type]; req = defaultReq; + } else { + TLRPC.TL_account_getChannelDefaultEmojiStatuses defaultReq = new TLRPC.TL_account_getChannelDefaultEmojiStatuses(); + defaultReq.hash = emojiStatusesHash[type]; + req = defaultReq; } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { emojiStatusesFetchDate[type] = System.currentTimeMillis() / 1000; @@ -8518,4 +8545,42 @@ public class MediaDataController extends BaseController { })); } } + + public TLRPC.TL_emojiList restrictedStatusEmojis; + public void loadRestrictedStatusEmojis() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("restrictedstatuses_" + currentAccount, Context.MODE_PRIVATE); + + String value = preferences.getString("restrictedstatuses", null); + long lastCheckTime = preferences.getLong("restrictedstatuses_last_check", 0); + + TLRPC.TL_emojiList emojiList = null; + if (value != null) { + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + try { + emojiList = (TLRPC.TL_emojiList) TLRPC.TL_emojiList.TLdeserialize(serializedData, serializedData.readInt32(true), true); + restrictedStatusEmojis = emojiList; + } catch (Throwable e) { + FileLog.e(e); + } + } + + if (emojiList == null || (System.currentTimeMillis() - lastCheckTime) > 24 * 60 * 60 * 1000) { + TLRPC.TL_account_getChannelRestrictedStatusEmojis req = new TLRPC.TL_account_getChannelRestrictedStatusEmojis(); + if (emojiList != null) { + req.hash = emojiList.hash; + } + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_emojiList) { + SerializedData data = new SerializedData(response.getObjectSize()); + response.serializeToStream(data); + SharedPreferences.Editor editor = preferences.edit(); + restrictedStatusEmojis = (TLRPC.TL_emojiList) response; + editor.putString("restrictedstatuses", Utilities.bytesToHex(data.toByteArray())); + editor.putLong("restrictedstatuses_last_check", System.currentTimeMillis()); + + editor.apply(); + } + })); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 24c2fa93f..5f4165cc8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -69,6 +69,7 @@ import org.telegram.ui.Components.URLSpanNoUnderlineBold; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.spoilers.SpoilerEffect; +import org.telegram.ui.PeerColorActivity; import java.io.BufferedReader; import java.io.File; @@ -122,6 +123,7 @@ public class MessageObject { public static final int TYPE_GIFT_PREMIUM_CHANNEL = 25; public static final int TYPE_GIVEAWAY = 26; public static final int TYPE_JOINED_CHANNEL = 27; // recommendations list + public static final int TYPE_GIVEAWAY_RESULTS = 28; public int localType; public String localName; @@ -165,6 +167,7 @@ public class MessageObject { public String dateKey; public String monthKey; public boolean deleted; + public boolean deletedByThanos; public float audioProgress; public float forceSeekTo = -1; public int audioProgressMs; @@ -212,7 +215,6 @@ public class MessageObject { public boolean replyTextRevealed; public int overrideLinkColor = -1; public long overrideLinkEmoji = -1; - public MessagesController.PeerColor overrideProfilePeerColor; private boolean channelJoined; public boolean channelJoinedExpanded; @@ -305,6 +307,8 @@ public class MessageObject { " & ", " . " }; + public boolean isRepostPreview; + public boolean isRepostVideoPreview; public boolean forceAvatar; public Drawable customAvatarDrawable; @@ -441,7 +445,14 @@ public class MessageObject { } public boolean hasMediaSpoilers() { - return messageOwner.media != null && messageOwner.media.spoiler || needDrawBluredPreview(); + return !isRepostPreview && (messageOwner.media != null && messageOwner.media.spoiler || needDrawBluredPreview()); + } + + public boolean shouldDrawReactions() { + if (isRepostPreview) { + return false; + } + return true; } public boolean shouldDrawReactionsInLayout() { @@ -1487,8 +1498,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); + } + + 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) { Theme.createCommonMessageResources(); + this.isRepostPreview = isRepostPreview; + this.isRepostVideoPreview = isRepostVideoPreview; + currentAccount = accountNum; messageOwner = message; replyMessageObject = replyToMessage; @@ -2696,6 +2714,133 @@ public class MessageObject { } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeColor) { TLRPC.TL_channelAdminLogEventActionChangeColor action = (TLRPC.TL_channelAdminLogEventActionChangeColor) event.action; messageText = replaceWithLink(LocaleController.formatString(R.string.EventLogChangedColor, AvatarDrawable.colorName(action.prev_value).toLowerCase(), AvatarDrawable.colorName(action.new_value).toLowerCase()), "un1", fromUser); + } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangePeerColor) { + TLRPC.TL_channelAdminLogEventActionChangePeerColor action = (TLRPC.TL_channelAdminLogEventActionChangePeerColor) event.action; + SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(R.string.EventLogChangedPeerColorIcon)); + + SpannableStringBuilder prev = new SpannableStringBuilder(); + if ((action.prev_value.flags & 1) != 0) { + prev.append("c"); + prev.setSpan(new PeerColorActivity.PeerColorSpan(false, currentAccount, action.prev_value.color).setSize(dp(18)), prev.length() - 1, prev.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ((action.prev_value.flags & 2) != 0) { + if (prev.length() > 0) + prev.append(", "); + prev.append("e"); + prev.setSpan(new AnimatedEmojiSpan(action.prev_value.background_emoji_id, Theme.chat_actionTextPaint.getFontMetricsInt()), prev.length() - 1, prev.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (prev.length() == 0) { + prev.append(LocaleController.getString(R.string.EventLogEmojiNone)); + } + + SpannableStringBuilder next = new SpannableStringBuilder(); + if ((action.new_value.flags & 1) != 0) { + next.append("c"); + next.setSpan(new PeerColorActivity.PeerColorSpan(false, currentAccount, action.new_value.color).setSize(dp(18)), next.length() - 1, next.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ((action.new_value.flags & 2) != 0) { + if (next.length() > 0) + next.append(", "); + next.append("e"); + next.setSpan(new AnimatedEmojiSpan(action.new_value.background_emoji_id, Theme.chat_actionTextPaint.getFontMetricsInt()), next.length() - 1, next.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (next.length() == 0) { + next.append(LocaleController.getString(R.string.EventLogEmojiNone)); + } + + ssb = AndroidUtilities.replaceCharSequence("%1$s", ssb, prev); + ssb = AndroidUtilities.replaceCharSequence("%2$s", ssb, next); + + messageText = replaceWithLink(ssb, "un1", fromUser); + } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor) { + TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor action = (TLRPC.TL_channelAdminLogEventActionChangeProfilePeerColor) event.action; + SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString(R.string.EventLogChangedProfileColorIcon)); + + SpannableStringBuilder prev = new SpannableStringBuilder(); + if ((action.prev_value.flags & 1) != 0) { + prev.append("c"); + prev.setSpan(new PeerColorActivity.PeerColorSpan(true, currentAccount, action.prev_value.color).setSize(dp(18)), prev.length() - 1, prev.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ((action.prev_value.flags & 2) != 0) { + if (prev.length() > 0) + prev.append(", "); + prev.append("e"); + prev.setSpan(new AnimatedEmojiSpan(action.prev_value.background_emoji_id, Theme.chat_actionTextPaint.getFontMetricsInt()), prev.length() - 1, prev.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (prev.length() == 0) { + prev.append(LocaleController.getString(R.string.EventLogEmojiNone)); + } + + SpannableStringBuilder next = new SpannableStringBuilder(); + if ((action.new_value.flags & 1) != 0) { + next.append("c"); + next.setSpan(new PeerColorActivity.PeerColorSpan(true, currentAccount, action.new_value.color).setSize(dp(18)), next.length() - 1, next.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ((action.new_value.flags & 2) != 0) { + if (next.length() > 0) + next.append(", "); + next.append("e"); + next.setSpan(new AnimatedEmojiSpan(action.new_value.background_emoji_id, Theme.chat_actionTextPaint.getFontMetricsInt()), next.length() - 1, next.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (next.length() == 0) { + next.append(LocaleController.getString(R.string.EventLogEmojiNone)); + } + + ssb = AndroidUtilities.replaceCharSequence("%1$s", ssb, prev); + ssb = AndroidUtilities.replaceCharSequence("%2$s", ssb, next); + + messageText = replaceWithLink(ssb, "un1", fromUser); + } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus) { + TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus action = (TLRPC.TL_channelAdminLogEventActionChangeEmojiStatus) event.action; + + boolean prevNone = false; + SpannableString prev; + if (action.prev_value instanceof TLRPC.TL_emojiStatusEmpty) { + prev = new SpannableString(LocaleController.getString(R.string.EventLogEmojiNone)); + prevNone = true; + } else { + prev = new SpannableString("e"); + prev.setSpan(new AnimatedEmojiSpan(DialogObject.getEmojiStatusDocumentId(action.prev_value), Theme.chat_actionTextPaint.getFontMetricsInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + boolean hasUntil = action.new_value instanceof TLRPC.TL_emojiStatusUntil; + + SpannableString next; + if (action.new_value instanceof TLRPC.TL_emojiStatusEmpty) { + next = new SpannableString(LocaleController.getString(R.string.EventLogEmojiNone)); + } else { + next = new SpannableString("e"); + next.setSpan(new AnimatedEmojiSpan(DialogObject.getEmojiStatusDocumentId(action.new_value), Theme.chat_actionTextPaint.getFontMetricsInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString( + prevNone ? ( + hasUntil ? R.string.EventLogChangedEmojiStatusFor : R.string.EventLogChangedEmojiStatus + ) : ( + hasUntil ? R.string.EventLogChangedEmojiStatusFromFor : R.string.EventLogChangedEmojiStatusFrom + ) + )); + + ssb = AndroidUtilities.replaceCharSequence("%1$s", ssb, prev); + ssb = AndroidUtilities.replaceCharSequence("%2$s", ssb, next); + if (hasUntil) { + String until = LocaleController.formatTTLString((int) ((DialogObject.getEmojiStatusUntil(action.new_value) - event.date) * 1.05f)); + ssb = AndroidUtilities.replaceCharSequence("%3$s", ssb, until); + } + + messageText = replaceWithLink(ssb, "un1", fromUser); + } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeWallpaper) { + TLRPC.TL_channelAdminLogEventActionChangeWallpaper action = (TLRPC.TL_channelAdminLogEventActionChangeWallpaper) event.action; + if (action.new_value instanceof TLRPC.TL_wallPaperNoFile && action.new_value.id == 0 && action.new_value.settings == null) { + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogRemovedWallpaper), "un1", fromUser); + } else { + photoThumbs = new ArrayList<>(); + if (action.new_value.document != null) { + photoThumbs.addAll(action.new_value.document.thumbs); + photoThumbsObject = action.new_value.document; + } + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChangedWallpaper), "un1", fromUser); + } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji) { TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji action = (TLRPC.TL_channelAdminLogEventActionChangeBackgroundEmoji) event.action; messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChangedEmoji), "un1", fromUser); @@ -3441,7 +3586,7 @@ public class MessageObject { } public boolean hasInlineBotButtons() { - return !isRestrictedMessage && messageOwner != null && messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup && !messageOwner.reply_markup.rows.isEmpty(); + return !isRestrictedMessage && !isRepostPreview && messageOwner != null && messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup && !messageOwner.reply_markup.rows.isEmpty(); } public void measureInlineBotButtons() { @@ -3555,6 +3700,8 @@ public class MessageObject { } else { messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChat, user.first_name); } + } else if (fromChat != null) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChannel); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; @@ -3593,6 +3740,8 @@ public class MessageObject { } messageText = AndroidUtilities.replaceCharSequence("%s", messageText, userName); } + } else if (fromChat != null) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChannel); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionGroupCallScheduled) { TLRPC.TL_messageActionGroupCallScheduled action = (TLRPC.TL_messageActionGroupCallScheduled) messageOwner.action; @@ -3790,9 +3939,9 @@ public class MessageObject { stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceUndistributed", giveawayResults.unclaimed_count)); } messageText = stringBuilder; - } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode && ((TLRPC.TL_messageActionGiftCode) messageOwner.action).boost_peer != null) { messageText = LocaleController.getString("BoostingReceivedGiftNoName", R.string.BoostingReceivedGiftNoName); - } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium) { + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium || messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { if (fromObject instanceof TLRPC.User && ((TLRPC.User) fromObject).self) { TLRPC.User user = getUser(users, sUsers, messageOwner.peer_id.user_id); messageText = replaceWithLink(AndroidUtilities.replaceTags(LocaleController.getString(R.string.ActionGiftOutbound)), "un1", user); @@ -3874,39 +4023,61 @@ public class MessageObject { } } } else if (messageOwner.action instanceof TLRPC.TL_messageActionRequestedPeer) { - TLRPC.Peer peer = ((TLRPC.TL_messageActionRequestedPeer) messageOwner.action).peer; - TLObject peerObject = null; - if (peer instanceof TLRPC.TL_peerUser) { - peerObject = MessagesController.getInstance(currentAccount).getUser(peer.user_id); - if (peerObject == null) { - peerObject = getUser(users, sUsers, peer.user_id); + List peerObjects = new ArrayList<>(); + int sharedUsers = 0; + int sharedChannels = 0; + int sharedChats = 0; + List peers = ((TLRPC.TL_messageActionRequestedPeer) messageOwner.action).peers; + for (TLRPC.Peer peer : peers) { + TLObject peerObject = null; + if (peer instanceof TLRPC.TL_peerUser) { + peerObject = MessagesController.getInstance(currentAccount).getUser(peer.user_id); + if (peerObject == null) { + peerObject = getUser(users, sUsers, peer.user_id); + } + } else if (peer instanceof TLRPC.TL_peerChat) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.chat_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.chat_id); + } + } else if (peer instanceof TLRPC.TL_peerChannel) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.channel_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.channel_id); + } } - } else if (peer instanceof TLRPC.TL_peerChat) { - peerObject = MessagesController.getInstance(currentAccount).getChat(peer.chat_id); - if (peerObject == null) { - peerObject = getChat(chats, sChats, peer.chat_id); + if (peer instanceof TLRPC.TL_peerUser) { + sharedUsers++; + } else if (peer instanceof TLRPC.TL_peerChat) { + sharedChats++; + } else { + sharedChannels++; } - } else if (peer instanceof TLRPC.TL_peerChannel) { - peerObject = MessagesController.getInstance(currentAccount).getChat(peer.channel_id); - if (peerObject == null) { - peerObject = getChat(chats, sChats, peer.channel_id); + if (peerObject != null) { + peerObjects.add(peerObject); } } + if (sharedUsers > 0 && sharedUsers != peerObjects.size()) { + messageText = LocaleController.getPluralString("ActionRequestedPeerUserPlural", sharedUsers); + } else if (sharedChannels > 0 && sharedChannels != peerObjects.size()) { + messageText = LocaleController.getPluralString("ActionRequestedPeerChannelPlural", sharedChannels); + } else if (sharedChats > 0 && sharedChats != peerObjects.size()) { + messageText = LocaleController.getPluralString("ActionRequestedPeerChatPlural", sharedChats); + } else { + String separator = ", "; + SpannableStringBuilder names = new SpannableStringBuilder(); + for (int i = 0; i < peerObjects.size(); i++) { + names.append(replaceWithLink("un1", "un1", peerObjects.get(i))); + if (i < peerObjects.size() - 1) { + names.append(separator); + } + } + messageText = AndroidUtilities.replaceCharSequence("un1", LocaleController.getString(R.string.ActionRequestedPeer), names); + } TLRPC.User bot = MessagesController.getInstance(currentAccount).getUser(getDialogId()); if (bot == null) { bot = getUser(users, sUsers, getDialogId()); } - if (peerObject == null) { - if (peer instanceof TLRPC.TL_peerUser) { - messageText = LocaleController.getString(R.string.ActionRequestedPeerUser); - } else if (peer instanceof TLRPC.TL_peerChat) { - messageText = LocaleController.getString(R.string.ActionRequestedPeerChat); - } else { - messageText = LocaleController.getString(R.string.ActionRequestedPeerChannel); - } - } else { - messageText = replaceWithLink(LocaleController.getString(R.string.ActionRequestedPeer), "un1", peerObject); - } messageText = replaceWithLink(messageText, "un2", bot); } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) { TLRPC.TL_messageActionSetMessagesTTL action = (TLRPC.TL_messageActionSetMessagesTTL) messageOwner.action; @@ -4241,15 +4412,19 @@ public class MessageObject { } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { String emoticon = ((TLRPC.TL_messageActionSetChatTheme) messageOwner.action).emoticon; String userName = UserObject.getFirstName(fromUser); + boolean isChannel = fromUser == null && fromChat != null; + if (isChannel) { + userName = fromChat.title; + } boolean isUserSelf = UserObject.isUserSelf(fromUser); if (TextUtils.isEmpty(emoticon)) { messageText = isUserSelf ? LocaleController.formatString("ChatThemeDisabledYou", R.string.ChatThemeDisabledYou) - : LocaleController.formatString("ChatThemeDisabled", R.string.ChatThemeDisabled, userName, emoticon); + : LocaleController.formatString(isChannel ? R.string.ChannelThemeDisabled : R.string.ChatThemeDisabled, userName, emoticon); } else { messageText = isUserSelf ? LocaleController.formatString("ChatThemeChangedYou", R.string.ChatThemeChangedYou, emoticon) - : LocaleController.formatString("ChatThemeChangedTo", R.string.ChatThemeChangedTo, userName, emoticon); + : LocaleController.formatString(isChannel ? R.string.ChannelThemeChangedTo : R.string.ChatThemeChangedTo, userName, emoticon); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByRequest) { if (UserObject.isUserSelf(fromUser)) { @@ -4272,6 +4447,8 @@ public class MessageObject { // messageText = getMediaTitle(getMedia(messageOwner)); // I'm afraid doing this if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveaway) { messageText = LocaleController.getString("BoostingGiveawayChannelStarted", R.string.BoostingGiveawayChannelStarted); + } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveawayResults) { + messageText = LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaStory) { if (getMedia(messageOwner).via_mention) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(getMedia(messageOwner).user_id); @@ -4375,6 +4552,8 @@ public class MessageObject { public CharSequence getMediaTitle(TLRPC.MessageMedia media) { if (media instanceof TLRPC.TL_messageMediaGiveaway) { return LocaleController.getString("BoostingGiveaway", R.string.BoostingGiveaway); + } else if (media instanceof TLRPC.TL_messageMediaGiveawayResults) { + return LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (media instanceof TLRPC.TL_messageMediaStory) { if (media.via_mention) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(media.user_id); @@ -4522,6 +4701,8 @@ public class MessageObject { type = TYPE_DATE; } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveaway) { type = TYPE_GIVEAWAY; + } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGiveawayResults) { + type = TYPE_GIVEAWAY_RESULTS; } else if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDice) { type = TYPE_ANIMATED_STICKER; if (getMedia(messageOwner).document == null) { @@ -4579,6 +4760,19 @@ public class MessageObject { contentType = 1; } } + } else if (currentEvent != null && currentEvent.action instanceof TLRPC.TL_channelAdminLogEventActionChangeWallpaper) { + TLRPC.TL_channelAdminLogEventActionChangeWallpaper wallPaper = (TLRPC.TL_channelAdminLogEventActionChangeWallpaper) currentEvent.action; + contentType = 1; + if (wallPaper.new_value instanceof TLRPC.TL_wallPaperNoFile && wallPaper.new_value.id == 0 && wallPaper.new_value.settings == null) { + type = TYPE_DATE; + } else { + type = TYPE_ACTION_WALLPAPER; + photoThumbs = new ArrayList<>(); + if (wallPaper.new_value.document != null) { + photoThumbs.addAll(wallPaper.new_value.document.thumbs); + photoThumbsObject = wallPaper.new_value.document; + } + } } else if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper) { contentType = 1; @@ -4600,10 +4794,10 @@ public class MessageObject { photoThumbsObject = messageOwner.action.photo; } else if (messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { type = TYPE_TEXT; - } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode && ((TLRPC.TL_messageActionGiftCode) messageOwner.action).boost_peer != null) { contentType = 1; type = TYPE_GIFT_PREMIUM_CHANNEL; - } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium) { + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftPremium || messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { contentType = 1; type = TYPE_GIFT_PREMIUM; } else if (messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { @@ -5937,6 +6131,9 @@ public class MessageObject { } public boolean needDrawShareButton() { + if (isRepostPreview) { + return false; + } if (type == TYPE_JOINED_CHANNEL) { return false; } else if (isSponsored()) { @@ -6158,10 +6355,11 @@ public class MessageObject { 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(messageText, 0, messageText.length(), paint, maxWidth) + StaticLayout.Builder.obtain(text, 0, text.length(), paint, maxWidth) .setLineSpacing(lineAdd, lineSpacing) .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) @@ -6174,13 +6372,76 @@ public class MessageObject { } textLayout = builder.build(); } else { - textLayout = new StaticLayout(messageText, paint, maxWidth, align, lineSpacing, lineAdd, false); + textLayout = new StaticLayout(text, paint, maxWidth, align, lineSpacing, lineAdd, false); } } catch (Exception e) { FileLog.e(e); return; } + if (isRepostPreview) { + int maxLines = 22; + if (type != MessageObject.TYPE_TEXT) { + maxLines = hasValidGroupId() ? 7 : 12; + } + if (isWebpage()) { + maxLines -= 8; + } + if (textLayout.getLineCount() > maxLines) { + String readMore = LocaleController.getString(R.string.ReadMore); + int readMoreWidth = (int) Math.ceil(paint.measureText("… " + readMore) + AndroidUtilities.dp(1)); + + float maxRight = 0; + for (int i = 0; i < maxLines; ++i) { + maxRight = Math.max(maxRight, textLayout.getLineRight(i)); + } + + int start = textLayout.getLineStart(maxLines - 1); + int end = textLayout.getLineEnd(maxLines - 1) - 1; + int offset = end; + for (; offset >= start; --offset) { + if (textLayout.getPrimaryHorizontal(offset) < maxRight - readMoreWidth) { + break; + } + } + for (; offset >= start; --offset) { + if (Character.isWhitespace(text.charAt(offset))) { + break; + } + } + text = new SpannableStringBuilder(text.subSequence(0, offset)).append("… ").append(readMore); + ((SpannableStringBuilder) text).setSpan(new CharacterStyle() { + @Override + public void updateDrawState(TextPaint tp) { + tp.setColor(Theme.chat_msgTextPaint.linkColor); + } + }, 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); + } + } catch (Exception e) { + FileLog.e(e); + return; + } + } + } + if (hasSingleQuote) { maxWidth += AndroidUtilities.dp(32); } else if (hasSingleCode) { @@ -6202,9 +6463,9 @@ public class MessageObject { float prevOffset = 0; ArrayList textRanges = new ArrayList<>(); - if (messageText instanceof Spanned && (hasQuote || hasCode)) { + if (text instanceof Spanned && (hasQuote || hasCode)) { singleLayout = false; - cutIntoRanges(messageText, textRanges); + cutIntoRanges(text, textRanges); } else if (singleLayout || blocksCount == 1) { textRanges.add(new TextRange(0, textLayout.getText().length())); } else { @@ -6281,7 +6542,7 @@ public class MessageObject { } } - CharSequence blockText = messageText.subSequence(range.start, range.end); + CharSequence blockText = text.subSequence(range.start, range.end); int blockMaxWidth = maxWidth; if (block.quote) { blockMaxWidth -= dp(24); @@ -6506,6 +6767,9 @@ public class MessageObject { textWidth = Math.max(textWidth, Math.min(maxWidth, linesMaxWidth)); } + if (block.languageLayout != null) { + textWidth = (int) Math.max(textWidth, Math.min(block.languageLayout.getCurrentWidth() + dp(15), block.textLayout == null ? 0 : block.textLayout.getWidth())); + } linesOffset += currentBlockLinesCount; @@ -6589,6 +6853,62 @@ public class MessageObject { FileLog.e(e); return; } + if (messageObject != null && messageObject.isRepostPreview) { + int maxLines = 22; + if (messageObject.type != MessageObject.TYPE_TEXT) { + maxLines = messageObject.hasValidGroupId() ? 7 : 12; + } + if (messageObject.isWebpage()) { + maxLines -= 8; + } + if (textLayout.getLineCount() > maxLines) { + String readMore = LocaleController.getString(R.string.ReadMore); + int readMoreWidth = (int) Math.ceil(textPaint.measureText("… " + readMore) + AndroidUtilities.dp(1)); + + float maxRight = 0; + for (int i = 0; i < maxLines; ++i) { + maxRight = Math.max(maxRight, textLayout.getLineRight(i)); + } + + int start = textLayout.getLineStart(maxLines - 1); + int end = textLayout.getLineEnd(maxLines - 1) - 1; + int offset = end; + for (; offset >= start; --offset) { + if (textLayout.getPrimaryHorizontal(offset) < maxRight - readMoreWidth) { + break; + } + } + for (; offset >= start; --offset) { + if (Character.isWhitespace(text.charAt(offset))) { + break; + } + } + text = new SpannableStringBuilder(text.subSequence(0, offset)).append("… ").append(readMore); + ((SpannableStringBuilder) text).setSpan(new CharacterStyle() { + @Override + public void updateDrawState(TextPaint tp) { + tp.setColor(Theme.chat_msgTextPaint.linkColor); + } + }, 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); + } + } catch (Exception e) { + FileLog.e(e); + return; + } + } + } if (hasSingleQuote) { width += AndroidUtilities.dp(32); @@ -6874,6 +7194,9 @@ public class MessageObject { textWidth = Math.max(textWidth, Math.min(width, linesMaxWidth)); } + if (block.languageLayout != null) { + textWidth = (int) Math.max(textWidth, Math.min(block.languageLayout.getCurrentWidth() + dp(15), block.textLayout == null ? 0 : block.textLayout.getWidth())); + } linesOffset += currentBlockLinesCount; if (messageObject != null && !messageObject.isSpoilersRevealed && !messageObject.spoiledLoginCode) { @@ -6918,6 +7241,9 @@ public class MessageObject { } public boolean needDrawAvatar() { + if (isRepostPreview) { + return true; + } if (forceAvatar || customAvatarDrawable != null) { return true; } @@ -6925,6 +7251,9 @@ public class MessageObject { } private boolean needDrawAvatarInternal() { + if (isRepostPreview) { + return true; + } if (forceAvatar || customAvatarDrawable != null) { return true; } @@ -7199,7 +7528,22 @@ public class MessageObject { return 0; } - public static boolean shouldEncryptPhotoOrVideo(TLRPC.Message message) { + public static long getChatId(TLRPC.Message message) { + if (message == null) { + return 0; + } + if (message.peer_id instanceof TLRPC.TL_peerChat) { + return message.peer_id.chat_id; + } else if (message.peer_id instanceof TLRPC.TL_peerChannel) { + return message.peer_id.channel_id; + } + return 0; + } + + public static boolean shouldEncryptPhotoOrVideo(int currentAccount, TLRPC.Message message) { + 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 { @@ -7208,7 +7552,7 @@ public class MessageObject { } public boolean shouldEncryptPhotoOrVideo() { - return shouldEncryptPhotoOrVideo(messageOwner); + return shouldEncryptPhotoOrVideo(currentAccount, messageOwner); } public static boolean isSecretPhotoOrVideo(TLRPC.Message message) { @@ -7230,6 +7574,9 @@ public class MessageObject { } public boolean needDrawBluredPreview() { + if (isRepostPreview) { + return false; + } if (hasExtendedMediaPreview()) { return true; } else if (messageOwner instanceof TLRPC.TL_message_secret) { @@ -8063,6 +8410,14 @@ public class MessageObject { return isVoiceMessage(messageOwner); } + public boolean isVoiceOnce() { + return isVoice() && messageOwner != null && messageOwner.media != null && messageOwner.media.ttl_seconds == 0x7FFFFFFF; + } + + public boolean isRoundOnce() { + return isRoundVideo() && messageOwner != null && messageOwner.media != null && messageOwner.media.ttl_seconds == 0x7FFFFFFF; + } + public boolean isVideo() { return isVideoMessage(messageOwner); } @@ -9095,6 +9450,7 @@ public class MessageObject { } public boolean probablyRingtone() { + if (isVoiceOnce()) return false; if (getDocument() != null && RingtoneDataStore.ringtoneSupportedMimeType.contains(getDocument().mime_type) && getDocument().size < MessagesController.getInstance(currentAccount).ringtoneSizeMax * 2) { for (int a = 0; a < getDocument().attributes.size(); a++) { TLRPC.DocumentAttribute attribute = getDocument().attributes.get(a); @@ -9166,6 +9522,14 @@ public class MessageObject { return type == MessageObject.TYPE_GIVEAWAY; } + public boolean isGiveawayOrGiveawayResults() { + return isGiveaway() || isGiveawayResults(); + } + + public boolean isGiveawayResults() { + return type == MessageObject.TYPE_GIVEAWAY_RESULTS; + } + public boolean isAnyGift() { return type == MessageObject.TYPE_GIFT_PREMIUM || type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL; } @@ -9332,7 +9696,7 @@ public class MessageObject { final boolean hasLinkPreview = !isRestrictedMessage && MessageObject.getMedia(messageOwner) instanceof TLRPC.TL_messageMediaWebPage && MessageObject.getMedia(messageOwner).webpage instanceof TLRPC.TL_webPage; final TLRPC.WebPage webpage = hasLinkPreview ? MessageObject.getMedia(messageOwner).webpage : null; final String webpageType = webpage != null ? webpage.type : null; - return hasLinkPreview && !isGiveaway() && + return hasLinkPreview && !isGiveawayOrGiveawayResults() && webpage != null && (webpage.photo != null || isVideoDocument(webpage.document)) && !(webpage != null && TextUtils.isEmpty(webpage.description) && TextUtils.isEmpty(webpage.title)) && !(isSponsored() && sponsoredWebPage == null && sponsoredChannelPost == 0) && // drawInstantViewType = 1 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java index ebdd54330..b500c29ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java @@ -196,6 +196,7 @@ public class MessagePreviewParams { public boolean webpagePhoto; public boolean noforwards; + public boolean hasSecretMessages; public TLRPC.WebPage webpage; public CharacterStyle currentLink; @@ -206,10 +207,13 @@ public class MessagePreviewParams { } public void updateReply(MessageObject replyMessageObject, MessageObject.GroupedMessages group, long dialogId, ChatActivity.ReplyQuote replyQuote) { - if (isSecret || replyMessageObject == null || replyMessageObject.type == MessageObject.TYPE_DATE || replyMessageObject.type == MessageObject.TYPE_ACTION_PHOTO || replyMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER || replyMessageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { + if (isSecret || replyMessageObject == null || replyMessageObject.type == MessageObject.TYPE_DATE || replyMessageObject.type == MessageObject.TYPE_ACTION_PHOTO + || replyMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER || replyMessageObject.type == MessageObject.TYPE_SUGGEST_PHOTO + || replyMessageObject.type == MessageObject.TYPE_GIFT_PREMIUM || replyMessageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL || replyMessageObject.type == MessageObject.TYPE_PHONE_CALL) { replyMessageObject = null; replyQuote = null; } + hasSecretMessages = replyMessageObject != null && (replyMessageObject.isVoiceOnce() || replyMessageObject.isRoundOnce()); if (replyMessageObject != null || replyQuote != null) { if (group != null) { replyMessage = new Messages(null, 1, group.messages, dialogId, null); @@ -341,19 +345,23 @@ public class MessagePreviewParams { public boolean hasLink(CharSequence text, String url) { if (url != null) { - Spannable spanned = SpannableString.valueOf(text); try { - AndroidUtilities.addLinks(spanned, Linkify.WEB_URLS); + Spannable spanned = SpannableString.valueOf(text); + try { + AndroidUtilities.addLinks(spanned, Linkify.WEB_URLS); + } catch (Exception e2) { + FileLog.e(e2); + } + URLSpan[] urlSpans = spanned.getSpans(0, spanned.length(), URLSpan.class); + + for (int i = 0; i < urlSpans.length; ++i) { + if (areUrlsEqual(urlSpans[i].getURL(), url)) { + return true; + } + } } catch (Exception e) { FileLog.e(e); } - URLSpan[] urlSpans = spanned.getSpans(0, spanned.length(), URLSpan.class); - - for (int i = 0; i < urlSpans.length; ++i) { - if (areUrlsEqual(urlSpans[i].getURL(), url)) { - return true; - } - } } return false; } @@ -449,6 +457,10 @@ public class MessagePreviewParams { } message.out = out == null ? messageObject.messageOwner.out : out; + if (message.out) { + message.from_id = new TLRPC.TL_peerUser(); + message.from_id.user_id = UserConfig.getInstance(messageObject.currentAccount).getClientUserId(); + } message.unread = false; message.via_bot_id = messageObject.messageOwner.via_bot_id; message.reply_markup = messageObject.messageOwner.reply_markup; @@ -464,7 +476,7 @@ public class MessagePreviewParams { if (msgtype == 0) { TLRPC.MessageFwdHeader header = null; - long clientUserId = UserConfig.getInstance(messageObject.currentAccount).clientUserId; + long clientUserId = UserConfig.getInstance(messageObject.currentAccount).getClientUserId(); if (!isSecret) { if (messageObject.messageOwner.fwd_from != null) { header = messageObject.messageOwner.fwd_from; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index abba21a22..2ecc71924 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -515,7 +515,6 @@ public class MessagesController extends BaseController implements NotificationCe public int ringtoneSizeMax; public boolean storiesExportNopublicLink; public int authorizationAutoconfirmPeriod; - public int channelColorLevelMin; public int quoteLengthMax; public boolean giveawayGiftsPurchaseAvailable; public PeerColors peerColors; @@ -565,6 +564,13 @@ public class MessagesController extends BaseController implements NotificationCe public int storiesSentWeeklyLimitPremium; public int storiesSentMonthlyLimitDefault; public int storiesSentMonthlyLimitPremium; + public int storiesSuggestedReactionsLimitDefault; + public int storiesSuggestedReactionsLimitPremium; + public int channelBgIconLevelMin; + public int channelProfileIconLevelMin; + public int channelEmojiStatusLevelMin; + public int channelWallpaperLevelMin; + public int channelCustomWallpaperLevelMin; public int uploadMaxFileParts; public int uploadMaxFilePartsPremium; @@ -580,6 +586,13 @@ public class MessagesController extends BaseController implements NotificationCe public boolean premiumLocked; public int transcribeButtonPressed; + public boolean premiumFeaturesBlocked() { + return premiumLocked && !getUserConfig().isPremium(); + } + public boolean premiumPurchaseBlocked() { + return premiumLocked; + } + public List directPaymentsCurrency = new ArrayList<>(); public NewMessageCallback newMessageCallback; @@ -715,7 +728,7 @@ public class MessagesController extends BaseController implements NotificationCe } public boolean isPremiumUser(TLRPC.User currentUser) { - return !premiumLocked && currentUser.premium; + return !premiumFeaturesBlocked() && currentUser.premium; } public boolean didPressTranscribeButtonEnough() { @@ -733,7 +746,7 @@ public class MessagesController extends BaseController implements NotificationCe public ArrayList filterPremiumStickers(ArrayList stickerSets) { - if (!premiumLocked) { + if (!premiumFeaturesBlocked()) { return stickerSets; } for (int i = 0; i < stickerSets.size(); i++) { @@ -749,7 +762,7 @@ public class MessagesController extends BaseController implements NotificationCe } public TLRPC.TL_messages_stickerSet filterPremiumStickers(TLRPC.TL_messages_stickerSet stickerSet) { - if (!premiumLocked || stickerSet == null) { + if (!premiumFeaturesBlocked() || stickerSet == null) { return stickerSet; } try { @@ -1416,9 +1429,16 @@ public class MessagesController extends BaseController implements NotificationCe storyExpiringLimitDefault = mainPreferences.getInt("storyExpiringLimitDefault", 50); storyExpiringLimitPremium = mainPreferences.getInt("storyExpiringLimitPremium", 100); storiesSentWeeklyLimitDefault = mainPreferences.getInt("storiesSentWeeklyLimitDefault", 7); + storiesSuggestedReactionsLimitDefault = mainPreferences.getInt("storiesSuggestedReactionsLimitDefault", 1); + storiesSuggestedReactionsLimitPremium = mainPreferences.getInt("storiesSuggestedReactionsLimitPremium", 5); storiesSentWeeklyLimitPremium = mainPreferences.getInt("storiesSentWeeklyLimitPremium", 70); storiesSentMonthlyLimitDefault = mainPreferences.getInt("storiesSentMonthlyLimitDefault", 30); storiesSentMonthlyLimitPremium = mainPreferences.getInt("storiesSentMonthlyLimitPremium", 300); + channelBgIconLevelMin = mainPreferences.getInt("channelBgIconLevelMin", 1); + channelProfileIconLevelMin = mainPreferences.getInt("channelProfileIconLevelMin", 1); + channelEmojiStatusLevelMin = mainPreferences.getInt("channelEmojiStatusLevelMin", 1); + channelWallpaperLevelMin = mainPreferences.getInt("channelWallpaperLevelMin", 1); + channelCustomWallpaperLevelMin = mainPreferences.getInt("channelCustomWallpaperLevelMin", 1); chatlistInvitesLimitPremium = mainPreferences.getInt("chatlistInvitesLimitPremium", isTest ? 5 : 20); chatlistJoinedLimitDefault = mainPreferences.getInt("chatlistJoinedLimitDefault", 2); chatlistJoinedLimitPremium = mainPreferences.getInt("chatlistJoinedLimitPremium", isTest ? 5 : 20); @@ -1426,7 +1446,6 @@ public class MessagesController extends BaseController implements NotificationCe storiesEntities = mainPreferences.getString("storiesEntities", "premium"); storiesExportNopublicLink = mainPreferences.getBoolean("storiesExportNopublicLink", false); authorizationAutoconfirmPeriod = mainPreferences.getInt("authorization_autoconfirm_period", 604800); - channelColorLevelMin = mainPreferences.getInt("channelColorLevelMin", 1); quoteLengthMax = mainPreferences.getInt("quoteLengthMax", 1024); giveawayGiftsPurchaseAvailable = mainPreferences.getBoolean("giveawayGiftsPurchaseAvailable", false); peerColors = PeerColors.fromString(PeerColors.TYPE_NAME, mainPreferences.getString("peerColors", "")); @@ -3348,6 +3367,28 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "stories_suggested_reactions_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSuggestedReactionsLimitDefault) { + storiesSuggestedReactionsLimitDefault = (int) num.value; + editor.putInt("storiesSuggestedReactionsLimitDefault", storiesSuggestedReactionsLimitDefault); + changed = true; + } + } + break; + } + case "stories_suggested_reactions_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSuggestedReactionsLimitPremium) { + storiesSuggestedReactionsLimitPremium = (int) num.value; + editor.putInt("storiesSuggestedReactionsLimitPremium", storiesSuggestedReactionsLimitPremium); + changed = true; + } + } + break; + } case "stories_sent_weekly_limit_default": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; @@ -3480,17 +3521,6 @@ public class MessagesController extends BaseController implements NotificationCe } break; } - case "channel_color_level_min": { - if (value.value instanceof TLRPC.TL_jsonNumber) { - TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; - if (channelColorLevelMin != num.value) { - channelColorLevelMin = (int) num.value; - editor.putInt("channelColorLevelMin", channelColorLevelMin); - changed = true; - } - } - break; - } case "quote_length_max": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; @@ -3570,6 +3600,61 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "channel_bg_icon_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != channelBgIconLevelMin) { + channelBgIconLevelMin = (int) num.value; + editor.putInt("channelBgIconLevelMin", channelBgIconLevelMin); + changed = true; + } + } + break; + } + case "channel_profile_bg_icon_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != channelProfileIconLevelMin) { + channelProfileIconLevelMin = (int) num.value; + editor.putInt("channelProfileIconLevelMin", channelProfileIconLevelMin); + changed = true; + } + } + break; + } + case "channel_emoji_status_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != channelEmojiStatusLevelMin) { + channelEmojiStatusLevelMin = (int) num.value; + editor.putInt("channelEmojiStatusLevelMin", channelEmojiStatusLevelMin); + changed = true; + } + } + break; + } + case "channel_wallpaper_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != channelWallpaperLevelMin) { + channelWallpaperLevelMin = (int) num.value; + editor.putInt("channelWallpaperLevelMin", channelWallpaperLevelMin); + changed = true; + } + } + break; + } + case "channel_custom_wallpaper_level_min": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != channelCustomWallpaperLevelMin) { + channelCustomWallpaperLevelMin = (int) num.value; + editor.putInt("channelCustomWallpaperLevelMin", channelCustomWallpaperLevelMin); + changed = true; + } + } + break; + } } } @@ -3652,6 +3737,50 @@ public class MessagesController extends BaseController implements NotificationCe public final ArrayList colors = new ArrayList<>(); private final LongSparseArray colorsById = new LongSparseArray<>(); + public boolean needUpdate() { + boolean noLevels = true; + boolean hasStandardColors = false; + for (int i = 0; i < colors.size(); ++i) { + if (colors.get(i).lvl > 0) { + noLevels = false; + } + if (colors.get(i).id < 7) { + hasStandardColors = true; + } + } + return noLevels || type == TYPE_NAME && !hasStandardColors; + } + + public int colorsAvailable(int lvl) { + int count = 0; + for (int i = 0; i < colors.size(); ++i) { + if (!colors.get(i).hidden && lvl >= colors.get(i).lvl) { + count++; + } + } + return count; + } + + public int maxLevel() { + int maxLvl = 0; + for (int i = 0; i < colors.size(); ++i) { + if (!colors.get(i).hidden) { + maxLvl = Math.max(maxLvl, colors.get(i).lvl); + } + } + return maxLvl; + } + + public int minLevel() { + int minLvl = maxLevel(); + for (int i = 0; i < colors.size(); ++i) { + if (!colors.get(i).hidden) { + minLvl = Math.min(minLvl, colors.get(i).lvl); + } + } + return minLvl; + } + private PeerColors(int type, int hash) { this.type = type; this.hash = hash; @@ -3692,6 +3821,7 @@ public class MessagesController extends BaseController implements NotificationCe PeerColor peerColor = PeerColor.fromString(colorParts[i]); if (peerColor == null) continue; + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; if (!peerColor.hidden) peerColors.colors.add(peerColor); peerColors.colorsById.put(peerColor.id, peerColor); @@ -3702,7 +3832,7 @@ public class MessagesController extends BaseController implements NotificationCe private static int color(String str) { return Integer.parseUnsignedInt("ff" + str, 16); } - + public static PeerColors fromTL(int type, TLRPC.TL_help_peerColors tl) { if (tl == null) return null; try { @@ -3710,7 +3840,7 @@ public class MessagesController extends BaseController implements NotificationCe for (int i = 0; i < tl.colors.size(); ++i) { PeerColor peerColor = PeerColor.fromTL(tl.colors.get(i)); if (peerColor == null) continue; - if (peerColor.id < 7 && type == TYPE_NAME) continue; + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; if (!peerColor.hidden) peerColors.colors.add(peerColor); peerColors.colorsById.put(peerColor.id, peerColor); @@ -3748,7 +3878,7 @@ public class MessagesController extends BaseController implements NotificationCe FileLog.e(e2); continue; } - if (type == TYPE_NAME && peerColor.id < 7) continue; + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; peerColors.colorsById.put(id, peerColor); } } @@ -3794,10 +3924,20 @@ public class MessagesController extends BaseController implements NotificationCe } public static class PeerColor { + public boolean isDefaultName; public int id; public boolean hidden; + public int lvl; private final int[] colors = new int[6]; private final int[] darkColors = new int[6]; + public int getColor(int i, Theme.ResourcesProvider resourcesProvider) { + if (i < 0 || i > 5) return 0; + if (isDefaultName && id >= 0 && id < 7) { + return Theme.getColor(Theme.keys_avatar_nameInMessage[id], resourcesProvider); + } + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); + return (isDark ? darkColors : colors)[i]; + } public int getColor1(boolean isDark) { return (isDark ? darkColors : colors)[0]; } @@ -3831,9 +3971,6 @@ public class MessagesController extends BaseController implements NotificationCe public int getColor5() { return (Theme.isCurrentThemeDark() ? darkColors : colors)[4]; } - public int getColor6() { - return (Theme.isCurrentThemeDark() ? darkColors : colors)[5]; - } public boolean hasColor2() { return getColor2() != getColor1(); } @@ -3870,6 +4007,9 @@ public class MessagesController extends BaseController implements NotificationCe public void appendString(StringBuilder sb) { sb.append("#"); if (hidden) sb.append("H"); + if (lvl > 0) { + sb.append("[").append(lvl).append("]"); + } sb.append(id); sb.append("{"); sb.append(colors[0]); @@ -3918,6 +4058,9 @@ public class MessagesController extends BaseController implements NotificationCe final PeerColor peerColor = new PeerColor(); peerColor.id = tl.color_id; peerColor.hidden = tl.hidden; + if ((tl.flags & 8) != 0) { + peerColor.lvl = tl.channel_min_level; + } System.arraycopy(optionToColors(tl.colors), 0, peerColor.colors, 0, 6); System.arraycopy(optionToColors(tl.dark_colors), 0, peerColor.darkColors, 0, 6); @@ -3962,16 +4105,25 @@ public class MessagesController extends BaseController implements NotificationCe if (string == null || string.isEmpty() || string.charAt(0) != '#') return null; int startIndex = 1; - boolean hidden = string.length() > 1 && string.charAt(1) == 'H'; + boolean hidden = string.length() > 1 && string.charAt(startIndex) == 'H'; if (hidden) { startIndex++; } + int lvl = 0; + if (string.length() > startIndex && string.charAt(startIndex) == '[') { + int eindex = string.indexOf(']'); + if (eindex > startIndex) { + lvl = Utilities.parseInt(string.substring(startIndex + 1, eindex)); + startIndex = eindex + 1; + } + } int index = string.indexOf('{'); if (index < 0) return null; try { final PeerColor peerColor = new PeerColor(); peerColor.id = Utilities.parseInt(string.substring(startIndex, index)); peerColor.hidden = hidden; + peerColor.lvl = lvl; final String[] parts = string.substring(index + 1, string.length() - 1).split("@"); String[] colorsString = parts[0].split(","); for (int i = 0; i < 6; ++i) @@ -4458,7 +4610,7 @@ public class MessagesController extends BaseController implements NotificationCe } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.wallpapersNeedReload, wallPaper.slug); if (uploadingWallpaperInfo.requestIds != null && overrideWallpaperInfo.dialogId != 0) { - uploadingWallpaperInfo.requestIds.add(ChatThemeController.getInstance(currentAccount).setWallpaperToUser(overrideWallpaperInfo.dialogId, uploadingWallpaperFinal, overrideWallpaperInfo, null, null)); + uploadingWallpaperInfo.requestIds.add(ChatThemeController.getInstance(currentAccount).setWallpaperToPeer(overrideWallpaperInfo.dialogId, uploadingWallpaperFinal, overrideWallpaperInfo, null, null)); } } }); @@ -4853,7 +5005,6 @@ public class MessagesController extends BaseController implements NotificationCe loadingSuggestedFilters = false; loadingRemoteFilters = false; suggestedFilters.clear(); - gettingAppChangelog = false; dialogFiltersLoaded = false; ignoreSetOnline = false; @@ -5230,6 +5381,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + updateEmojiStatusUntilUpdate(-chat.id, chat.emoji_status); if (chat.min) { if (oldChat != null) { if (!fromCache) { @@ -5311,7 +5463,7 @@ public class MessagesController extends BaseController implements NotificationCe } else { oldChat.flags |= 16384; } - if (!chat.stories_hidden_min) { + if (chat.stories_hidden_min) { chat.stories_hidden = oldChat.stories_hidden; } if (oldFlags != newFlags || oldFlags2 != newFlags2) { @@ -5699,6 +5851,7 @@ public class MessagesController extends BaseController implements NotificationCe getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); getMessagesStorage().updateChatInfo(res.full_chat, false); getStoriesController().updateStoriesFromFullPeer(dialogId, res.full_chat.stories); + ChatThemeController.getInstance(currentAccount).saveChatWallpaper(-chatId, res.full_chat.wallpaper); if (ChatObject.isChannel(chat)) { Integer value = dialogs_read_inbox_max.get(dialogId); if (value == null) { @@ -5780,7 +5933,10 @@ public class MessagesController extends BaseController implements NotificationCe dialog.ttl_period = res.full_chat.ttl_period; getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } - dialog.view_forum_as_messages = res.full_chat.view_forum_as_messages; + if (dialog.view_forum_as_messages != res.full_chat.view_forum_as_messages) { + dialog.view_forum_as_messages = res.full_chat.view_forum_as_messages; + getMessagesStorage().setDialogViewThreadAsMessages(dialogId, res.full_chat.view_forum_as_messages); + } } }); } else { @@ -10975,7 +11131,6 @@ public class MessagesController extends BaseController implements NotificationCe migratingDialogs = false; getNotificationCenter().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); } else { - generateUpdateMessage(); if (!added && loadType == DIALOGS_LOAD_TYPE_CACHE && dialogsEndReached.get(folderId)) { loadDialogs(folderId, 0, count, false); } @@ -12117,13 +12272,28 @@ public class MessagesController extends BaseController implements NotificationCe processUpdates((TLRPC.Updates) response, false); AndroidUtilities.runOnUIThread(() -> { if (convertRunnable != null) { + TLRPC.Chat prevChat = null; for (int a = 0; a < updates.chats.size(); a++) { TLRPC.Chat chat = updates.chats.get(a); - if (ChatObject.isChannel(chat)) { - convertRunnable.run(chat.id); + if (chatId == chat.id) { + prevChat = chat; break; } } + if (prevChat != null && prevChat.migrated_to != null) { + long newChatId = prevChat.migrated_to.channel_id; + TLRPC.Chat newChat = null; + for (int a = 0; a < updates.chats.size(); a++) { + TLRPC.Chat chat = updates.chats.get(a); + if (newChatId == chat.id) { + newChat = chat; + break; + } + } + if (newChat != null) { + convertRunnable.run(newChatId); + } + } } }); } else { @@ -12960,27 +13130,6 @@ public class MessagesController extends BaseController implements NotificationCe getContactsController().deleteUnknownAppAccounts(); } - - private boolean gettingAppChangelog; - - public void generateUpdateMessage() { - if (gettingAppChangelog || BuildVars.DEBUG_VERSION || SharedConfig.lastUpdateVersion == null || SharedConfig.lastUpdateVersion.equals(BuildVars.BUILD_VERSION_STRING)) { - return; - } - gettingAppChangelog = true; - TLRPC.TL_help_getAppChangelog req = new TLRPC.TL_help_getAppChangelog(); - req.prev_app_version = SharedConfig.lastUpdateVersion; - getConnectionsManager().sendRequest(req, (response, error) -> { - if (error == null) { - SharedConfig.lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; - SharedConfig.saveConfig(); - } - if (response instanceof TLRPC.Updates) { - processUpdates((TLRPC.Updates) response, false); - } - }); - } - public void registerForPush(@PushListenerController.PushType int pushType, String regid) { if (TextUtils.isEmpty(regid) || registeringForPush || getUserConfig().getClientUserId() == 0) { return; @@ -17256,9 +17405,13 @@ public class MessagesController extends BaseController implements NotificationCe } TLRPC.Dialog dialog = getDialog(-update.channel_id); if (dialog != null) { - dialog.view_forum_as_messages = update.enabled; + if (dialog.view_forum_as_messages != update.enabled) { + dialog.view_forum_as_messages = update.enabled; + getMessagesStorage().setDialogViewThreadAsMessages(-update.channel_id, update.enabled); + } + } else { + getMessagesStorage().setDialogViewThreadAsMessages(-update.channel_id, update.enabled); } - getMessagesStorage().setDialogViewThreadAsMessages(-update.channel_id, update.enabled); } } if (editor != null) { @@ -19191,13 +19344,13 @@ public class MessagesController extends BaseController implements NotificationCe boolean onMessageReceived(TLRPC.Message message); } - public void updateEmojiStatusUntilUpdate(long userId, TLRPC.EmojiStatus status) { + public void updateEmojiStatusUntilUpdate(long dialogId, TLRPC.EmojiStatus status) { if (status instanceof TLRPC.TL_emojiStatusUntil) { - emojiStatusUntilValues.put(userId, ((TLRPC.TL_emojiStatusUntil) status).until); + emojiStatusUntilValues.put(dialogId, ((TLRPC.TL_emojiStatusUntil) status).until); } else { - if (!emojiStatusUntilValues.containsKey(userId)) + if (!emojiStatusUntilValues.containsKey(dialogId)) return; - emojiStatusUntilValues.remove(userId); + emojiStatusUntilValues.remove(dialogId); } updateEmojiStatusUntil(); @@ -19413,10 +19566,18 @@ public class MessagesController extends BaseController implements NotificationCe } FileLoader.getInstance(currentAccount).cancelFileUpload(uploadingWallpaper, false); if (uploadingWallpaperInfo.dialogId != 0) { - TLRPC.UserFull userFull = getUserFull(uploadingWallpaperInfo.dialogId); - if (userFull != null) { - userFull.wallpaper = uploadingWallpaperInfo.prevUserWallpaper; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, uploadingWallpaperInfo.dialogId, userFull); + if (uploadingWallpaperInfo.dialogId >= 0) { + TLRPC.UserFull userFull = getUserFull(uploadingWallpaperInfo.dialogId); + if (userFull != null) { + userFull.wallpaper = uploadingWallpaperInfo.prevUserWallpaper; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, uploadingWallpaperInfo.dialogId, userFull); + } + } else { + TLRPC.ChatFull chatFull = getChatFull(-uploadingWallpaperInfo.dialogId); + if (chatFull != null) { + chatFull.wallpaper = uploadingWallpaperInfo.prevUserWallpaper; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull, 0, false, false); + } } } uploadingWallpaperInfo = null; @@ -19544,9 +19705,12 @@ public class MessagesController extends BaseController implements NotificationCe } public void checkPeerColors(boolean force) { - if (peerColors == null || force) { + if (peerColors == null || peerColors.needUpdate() || force) { TLRPC.TL_help_getPeerColors req = new TLRPC.TL_help_getPeerColors(); req.hash = peerColors != null ? peerColors.hash : 0; + if (peerColors != null && peerColors.needUpdate()) { + req.hash = 0; + } getConnectionsManager().sendRequest(req, (res, err) -> { if (res instanceof TLRPC.TL_help_peerColors) { AndroidUtilities.runOnUIThread(() -> { @@ -19556,9 +19720,12 @@ public class MessagesController extends BaseController implements NotificationCe } }); } - if (profilePeerColors == null || force) { + if (profilePeerColors == null || profilePeerColors.needUpdate() || force) { TLRPC.TL_help_getPeerProfileColors req = new TLRPC.TL_help_getPeerProfileColors(); req.hash = profilePeerColors != null ? profilePeerColors.hash : 0; + if (profilePeerColors != null && profilePeerColors.needUpdate()) { + req.hash = 0; + } getConnectionsManager().sendRequest(req, (res, err) -> { if (res instanceof TLRPC.TL_help_peerColors) { AndroidUtilities.runOnUIThread(() -> { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 18015e67c..ace1a6c24 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -14160,6 +14160,14 @@ public class MessagesStorage extends BaseController { } } } + if (message.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + TLRPC.TL_messageMediaGiveawayResults giveaway = (TLRPC.TL_messageMediaGiveawayResults) message.media; + for (Long uid : giveaway.winners) { + if (!usersToLoad.contains(uid)) { + usersToLoad.add(uid); + } + } + } if (message.media instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll messageMediaPoll = (TLRPC.TL_messageMediaPoll) message.media; if (!messageMediaPoll.results.recent_voters.isEmpty()) { @@ -14168,8 +14176,19 @@ public class MessagesStorage extends BaseController { } } } - if (message.media instanceof TLRPC.TL_messageMediaStory && message.media.storyItem != null && message.media.storyItem.fwd_from != null) { - addLoadPeerInfo(message.media.storyItem.fwd_from.from, usersToLoad, chatsToLoad); + if (message.media instanceof TLRPC.TL_messageMediaStory && message.media.storyItem != null) { + if (message.media.storyItem.fwd_from != null) { + addLoadPeerInfo(message.media.storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } + if (message.media.storyItem != null && message.media.storyItem.media_areas != null) { + for (int j = 0; j < message.media.storyItem.media_areas.size(); ++j) { + if (message.media.storyItem.media_areas.get(j) instanceof TL_stories.TL_mediaAreaChannelPost) { + long channelId = ((TL_stories.TL_mediaAreaChannelPost) message.media.storyItem.media_areas.get(j)).channel_id; + if (!chatsToLoad.contains(channelId)) + chatsToLoad.add(channelId); + } + } + } } if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage != null && message.media.webpage.attributes != null) { for (int i = 0; i < message.media.webpage.attributes.size(); ++i) { @@ -14178,6 +14197,15 @@ public class MessagesStorage extends BaseController { if (attr.storyItem != null && attr.storyItem.fwd_from != null) { addLoadPeerInfo(attr.storyItem.fwd_from.from, usersToLoad, chatsToLoad); } + if (attr.storyItem != null && attr.storyItem.media_areas != null) { + for (int j = 0; j < attr.storyItem.media_areas.size(); ++j) { + if (attr.storyItem.media_areas.get(j) instanceof TL_stories.TL_mediaAreaChannelPost) { + long channelId = ((TL_stories.TL_mediaAreaChannelPost) attr.storyItem.media_areas.get(j)).channel_id; + if (!chatsToLoad.contains(channelId)) + chatsToLoad.add(channelId); + } + } + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 8df45b841..fa191a308 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -210,6 +210,8 @@ public class NotificationCenter { public static final int updateBotMenuButton = totalEvents++; + public static final int giftsToUserSent = totalEvents++; + public static final int didStartedMultiGiftsSelector = totalEvents++; public static final int boostedChannelByUser = totalEvents++; public static final int boostByChannelCreated = totalEvents++; public static final int didUpdatePremiumGiftStickers = totalEvents++; @@ -221,6 +223,7 @@ 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++; //global public static final int pushMessagesUpdated = totalEvents++; @@ -285,21 +288,22 @@ public class NotificationCenter { public static final int userEmojiStatusUpdated = totalEvents++; public static final int requestPermissions = totalEvents++; public static final int permissionsGranted = totalEvents++; - public static int topicsDidLoaded = totalEvents++; - public static int chatSwithcedToForum = totalEvents++; - public static int didUpdateGlobalAutoDeleteTimer = totalEvents++; - public static int onDatabaseReset = totalEvents++; - public static int wallpaperSettedToUser = totalEvents++; - public static int storiesUpdated = totalEvents++; - public static int storiesListUpdated = totalEvents++; - public static int storiesDraftsUpdated = totalEvents++; - public static int chatlistFolderUpdate = totalEvents++; + public static final int topicsDidLoaded = totalEvents++; + public static final int chatSwithcedToForum = totalEvents++; + public static final int didUpdateGlobalAutoDeleteTimer = totalEvents++; + public static final int onDatabaseReset = totalEvents++; + public static final int wallpaperSettedToUser = totalEvents++; + public static final int storiesUpdated = totalEvents++; + public static final int storiesListUpdated = totalEvents++; + public static final int storiesDraftsUpdated = totalEvents++; + public static final int chatlistFolderUpdate = totalEvents++; public static final int uploadStoryProgress = totalEvents++; public static final int uploadStoryEnd = totalEvents++; public static final int customTypefacesLoaded = totalEvents++; public static final int stealthModeChanged = totalEvents++; public static final int onReceivedChannelDifference = totalEvents++; public static final int storiesReadUpdated = totalEvents++; + public static final int nearEarEvent = totalEvents++; public static boolean alreadyLogged; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index c56f701f7..535974bb9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -2120,6 +2120,8 @@ public class NotificationsController extends BaseController { } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { return LocaleController.getString("BoostingGiveaway", R.string.BoostingGiveaway); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + return LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { return LocaleController.getString("AttachLocation", R.string.AttachLocation); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { @@ -2369,6 +2371,8 @@ public class NotificationsController extends BaseController { } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; msg = LocaleController.formatString("NotificationMessageChannelGiveaway", R.string.NotificationMessageChannelGiveaway, name, giveaway.quantity, giveaway.months); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + msg = LocaleController.formatString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) messageObject.messageOwner.media; if (mediaPoll.poll.quiz) { @@ -2823,6 +2827,8 @@ public class NotificationsController extends BaseController { } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; msg = LocaleController.formatString("NotificationMessageChannelGiveaway", R.string.NotificationMessageChannelGiveaway, chat.title, giveaway.quantity, giveaway.months); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + msg = LocaleController.formatString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { msg = LocaleController.formatString("NotificationMessageGroupMap", R.string.NotificationMessageGroupMap, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java new file mode 100644 index 000000000..a3896ed82 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java @@ -0,0 +1,76 @@ +package org.telegram.messenger; + +import androidx.collection.LongSparseArray; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLiteException; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.HashMap; + +public class SavedMessagesController { + + private final int currentAccount; + + public boolean loading, loaded; + public LongSparseArray> messages = new LongSparseArray>(); + + public SavedMessagesController(int account) { + this.currentAccount = account; + } + + public void getSavedMessagesDialogs() { + if (loaded || loading) { + 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); + + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.send_state = cursor.intValue(3); + MessageObject.setUnreadFlags(message, cursor.intValue(4)); + + MessageObject messageObject = new MessageObject(currentAccount, message, true, true); + ArrayList messageObjects = messages.get(did); + if (messageObjects == null) { + messages.put(did, messageObjects = new ArrayList<>()); + } + messageObjects.add(messageObject); + } + } + + AndroidUtilities.runOnUIThread(() -> { + SavedMessagesController.this.messages.clear(); + SavedMessagesController.this.messages.putAll(messages); + loading = false; + }); + } catch (SQLiteException e) { + e.printStackTrace(); + } finally { + if (cursor != null) { + cursor.dispose(); + cursor = null; + } + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index fab279e0e..3fbbfce0e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -21,7 +21,6 @@ import android.os.Environment; import android.os.SystemClock; import android.text.TextUtils; import android.util.Base64; -import android.util.Log; import android.webkit.WebView; import androidx.annotation.IntDef; @@ -234,7 +233,6 @@ public class SharedConfig { public static int lastPauseTime; public static boolean isWaitingForPasscodeEnter; public static boolean useFingerprint = true; - public static String lastUpdateVersion; public static int suggestStickers; public static boolean suggestAnimatedEmoji; public static int keepMedia = CacheByChatsController.KEEP_MEDIA_ONE_MONTH; //deprecated @@ -312,6 +310,8 @@ public class SharedConfig { public static int messageSeenHintCount; public static int emojiInteractionsHintCount; public static int dayNightThemeSwitchHintCount; + public static boolean forceLessData; + public static int callEncryptionHintDisplayedCount; public static TLRPC.TL_help_appUpdate pendingAppUpdate; public static int pendingAppUpdateBuildVersion; @@ -431,7 +431,6 @@ public class SharedConfig { editor.putInt("badPasscodeTries", badPasscodeTries); editor.putInt("autoLockIn", autoLockIn); editor.putInt("lastPauseTime", lastPauseTime); - editor.putString("lastUpdateVersion2", lastUpdateVersion); editor.putBoolean("useFingerprint", useFingerprint); editor.putBoolean("allowScreenCapture", allowScreenCapture); editor.putString("pushString2", pushString); @@ -511,7 +510,6 @@ public class SharedConfig { autoLockIn = preferences.getInt("autoLockIn", 60 * 60); lastPauseTime = preferences.getInt("lastPauseTime", 0); useFingerprint = preferences.getBoolean("useFingerprint", true); - lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5"); allowScreenCapture = preferences.getBoolean("allowScreenCapture", false); lastLocalId = preferences.getInt("lastLocalId", -210000); pushString = preferences.getString("pushString2", ""); @@ -541,7 +539,7 @@ public class SharedConfig { try { String update = preferences.getString("appUpdate", null); if (update != null) { - pendingAppUpdateBuildVersion = preferences.getInt("appUpdateBuild", BuildVars.BUILD_VERSION); + pendingAppUpdateBuildVersion = preferences.getInt("appUpdateBuild", buildVersion()); byte[] arr = Base64.decode(update, Base64.DEFAULT); if (arr != null) { SerializedData data = new SerializedData(arr); @@ -561,7 +559,7 @@ public class SharedConfig { FileLog.e(e); } if (updateVersion == 0) { - updateVersion = BuildVars.BUILD_VERSION; + updateVersion = buildVersion(); } if (updateVersionString == null) { updateVersionString = BuildVars.BUILD_VERSION_STRING; @@ -651,6 +649,8 @@ public class SharedConfig { payByInvoice = preferences.getBoolean("payByInvoice", false); photoViewerBlur = preferences.getBoolean("photoViewerBlur", true); multipleReactionsPromoShowed = preferences.getBoolean("multipleReactionsPromoShowed", false); + forceLessData = preferences.getBoolean("forceLessData", false); + callEncryptionHintDisplayedCount = preferences.getInt("callEncryptionHintDisplayedCount", 0); loadDebugConfig(preferences); @@ -669,6 +669,15 @@ public class SharedConfig { } } + public static int buildVersion() { + try { + return ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0).versionCode; + } catch (Exception e) { + FileLog.e(e); + return 0; + } + } + public static void updateTabletConfig() { if (fontSizeIsDefault) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); @@ -752,7 +761,7 @@ public class SharedConfig { currentVersion = pInfo.versionCode; } catch (Exception e) { FileLog.e(e); - currentVersion = BuildVars.BUILD_VERSION; + currentVersion = buildVersion(); } return pendingAppUpdateBuildVersion == currentVersion; } @@ -768,7 +777,7 @@ public class SharedConfig { FileLog.e(e); } if (versionCode == 0) { - versionCode = BuildVars.BUILD_VERSION; + versionCode = buildVersion(); } if (updateVersionString == null) { updateVersionString = BuildVars.BUILD_VERSION_STRING; @@ -847,7 +856,6 @@ public class SharedConfig { useFingerprint = true; isWaitingForPasscodeEnter = false; allowScreenCapture = false; - lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; textSelectionHintShows = 0; scheduledOrNoSoundHintShows = 0; scheduledOrNoSoundHintSeenAt = 0; @@ -1071,6 +1079,14 @@ public class SharedConfig { editor.apply(); } + public static void incrementCallEncryptionHintDisplayed(int count) { + callEncryptionHintDisplayedCount += count; + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("callEncryptionHintDisplayedCount", callEncryptionHintDisplayedCount); + editor.apply(); + } + public static void toggleLoopStickers() { LiteMode.toggleFlag(LiteMode.FLAG_ANIMATED_STICKERS_CHAT); } @@ -1529,6 +1545,10 @@ public class SharedConfig { preferences.edit().putInt("emojiInteractionsHintCount", emojiInteractionsHintCount).apply(); } + public static void setForceLessData(boolean value) { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + preferences.edit().putBoolean("forceLessData", forceLessData = value).apply(); + } public static void updateDayNightThemeSwitchHintCount(int count) { dayNightThemeSwitchHintCount = count; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index 5822315ad..4b2bd2657 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -662,7 +662,11 @@ public class TopicsController extends BaseController { TLRPC.TL_channels_toggleViewForumAsMessages request = new TLRPC.TL_channels_toggleViewForumAsMessages(); request.channel_id = getMessagesController().getInputChannel(channelId); request.enabled = enabled; - getConnectionsManager().sendRequest(request, null); + getConnectionsManager().sendRequest(request, (res, err) -> { + if (res != null) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + }); } public void pinTopic(long chatId, int topicId, boolean pin, BaseFragment fragment) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index e2f259b7e..6af2c53cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -144,9 +144,9 @@ public class UserObject { } public static MessagesController.PeerColor getPeerColorForAvatar(int currentAccount, TLRPC.User user) { - if (user != null && user.profile_color != null && user.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { - return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(user.profile_color.color); - } +// if (user != null && user.profile_color != null && user.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { +// return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(user.profile_color.color); +// } return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index b8a7e7d38..5dc4868b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -55,15 +55,17 @@ public class VideoEditedInfo { public byte[] key; public byte[] iv; public MediaController.SavedFilterState filterState; - public String paintPath, blurPath; + public String paintPath, blurPath, messagePath, messageVideoMaskPath, backgroundPath; public ArrayList mediaEntities; public MediaController.CropState cropState; public boolean isPhoto; public boolean isStory; public StoryEntry.HDRInfo hdrInfo; - public ArrayList parts; public Integer gradientTopColor, gradientBottomColor; + public int account; + public boolean isDark; + public long wallpaperPeerId = Long.MIN_VALUE; public boolean forceFragmenting; public boolean alreadyScheduledConverting; @@ -115,6 +117,7 @@ public class VideoEditedInfo { public static final byte TYPE_LOCATION = 3; public static final byte TYPE_REACTION = 4; public static final byte TYPE_ROUND = 5; + public static final byte TYPE_MESSAGE = 6; public byte type; public byte subType; @@ -135,7 +138,9 @@ public class VideoEditedInfo { public int viewHeight; public float roundRadius; - public float scale; + public String segmentedPath = ""; + + public float scale = 1.0f; public float textViewWidth; public float textViewHeight; public float textViewX; @@ -172,50 +177,53 @@ public class VideoEditedInfo { public MediaEntity() { } - public MediaEntity(AbstractSerializedData data, boolean full) { - type = data.readByte(false); - subType = data.readByte(false); - x = data.readFloat(false); - y = data.readFloat(false); - rotation = data.readFloat(false); - width = data.readFloat(false); - height = data.readFloat(false); - text = data.readString(false); - int count = data.readInt32(false); + this(data, full, false); + } + + public MediaEntity(AbstractSerializedData data, boolean full, boolean exception) { + type = data.readByte(exception); + subType = data.readByte(exception); + x = data.readFloat(exception); + y = data.readFloat(exception); + rotation = data.readFloat(exception); + width = data.readFloat(exception); + height = data.readFloat(exception); + text = data.readString(exception); + int count = data.readInt32(exception); for (int i = 0; i < count; ++i) { EmojiEntity entity = new EmojiEntity(); - data.readInt32(false); - entity.readParams(data, false); + data.readInt32(exception); + entity.readParams(data, exception); entities.add(entity); } - color = data.readInt32(false); - fontSize = data.readInt32(false); - viewWidth = data.readInt32(false); - viewHeight = data.readInt32(false); - textAlign = data.readInt32(false); - textTypeface = PaintTypeface.find(textTypefaceKey = data.readString(false)); - scale = data.readFloat(false); - textViewWidth = data.readFloat(false); - textViewHeight = data.readFloat(false); - textViewX = data.readFloat(false); - textViewY = data.readFloat(false); + color = data.readInt32(exception); + fontSize = data.readInt32(exception); + viewWidth = data.readInt32(exception); + viewHeight = data.readInt32(exception); + textAlign = data.readInt32(exception); + textTypeface = PaintTypeface.find(textTypefaceKey = data.readString(exception)); + scale = data.readFloat(exception); + textViewWidth = data.readFloat(exception); + textViewHeight = data.readFloat(exception); + textViewX = data.readFloat(exception); + textViewY = data.readFloat(exception); if (full) { - int magic = data.readInt32(false); + int magic = data.readInt32(exception); if (magic == TLRPC.TL_null.constructor) { document = null; } else { - document = TLRPC.Document.TLdeserialize(data, magic, false); + document = TLRPC.Document.TLdeserialize(data, magic, exception); } } if (type == TYPE_LOCATION) { - density = data.readFloat(false); - mediaArea = TL_stories.MediaArea.TLdeserialize(data, data.readInt32(false), false); - mediaGeo = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + density = data.readFloat(exception); + mediaArea = TL_stories.MediaArea.TLdeserialize(data, data.readInt32(exception), exception); + mediaGeo = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(exception), exception); if (data.remaining() > 0) { - int magic = data.readInt32(false); + int magic = data.readInt32(exception); if (magic == 0xdeadbeef) { - String emoji = data.readString(false); + String emoji = data.readString(exception); if (mediaGeo instanceof TLRPC.TL_messageMediaVenue) { ((TLRPC.TL_messageMediaVenue) mediaGeo).emoji = emoji; } @@ -223,13 +231,16 @@ public class VideoEditedInfo { } } if (type == TYPE_REACTION) { - mediaArea = TL_stories.MediaArea.TLdeserialize(data, data.readInt32(false), false); + mediaArea = TL_stories.MediaArea.TLdeserialize(data, data.readInt32(exception), exception); } if (type == TYPE_ROUND) { - roundOffset = data.readInt64(false); - roundLeft = data.readInt64(false); - roundRight = data.readInt64(false); - roundDuration = data.readInt64(false); + roundOffset = data.readInt64(exception); + roundLeft = data.readInt64(exception); + roundRight = data.readInt64(exception); + roundDuration = data.readInt64(exception); + } + if (type == TYPE_PHOTO) { + segmentedPath = data.readString(exception); } } @@ -293,6 +304,9 @@ public class VideoEditedInfo { data.writeInt64(roundRight); data.writeInt64(roundDuration); } + if (type == TYPE_PHOTO) { + data.writeString(segmentedPath); + } } public MediaEntity copy() { @@ -452,14 +466,7 @@ public class VideoEditedInfo { } else { serializedData.writeByte(0); } - if (parts != null && !parts.isEmpty()) { - serializedData.writeInt32(parts.size()); - for (StoryEntry.Part part : parts) { - part.serializeToStream(serializedData); - } - } else { - serializedData.writeInt32(0); - } + serializedData.writeInt32(0); serializedData.writeBool(isStory); serializedData.writeBool(fromCamera); if (blurPathBytes != null) { @@ -582,11 +589,7 @@ public class VideoEditedInfo { } } if (version >= 6) { - int count = serializedData.readInt32(false); - for (int i = 0; i < count; ++i) { - StoryEntry.Part part = new StoryEntry.Part(); - part.readParams(serializedData, false); - } + serializedData.readInt32(false); } if (version >= 7) { isStory = serializedData.readBool(false); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index 22d8ec1c2..d8b614a00 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -89,7 +89,6 @@ public class MediaCodecVideoConvertor { boolean muted = convertVideoParams.muted; boolean isStory = convertVideoParams.isStory; StoryEntry.HDRInfo hdrInfo = convertVideoParams.hdrInfo; - ArrayList parts = convertVideoParams.parts; FileLog.d("convertVideoInternal original=" + originalWidth + "x" + originalHeight + " result=" + resultWidth + "x" + resultHeight + " " + avatarStartTime); long time = System.currentTimeMillis(); @@ -178,7 +177,7 @@ public class MediaCodecVideoConvertor { inputSurface.makeCurrent(); encoder.start(); - outputSurface = new OutputSurface(savedFilterState, videoPath, paintPath, blurPath, mediaEntities, cropState != null && cropState.useMatrix != null ? cropState : null, resultWidth, resultHeight, originalWidth, originalHeight, rotationValue, framerate, true, gradientTopColor, gradientBottomColor, null, parts); + outputSurface = new OutputSurface(savedFilterState, videoPath, paintPath, blurPath, mediaEntities, cropState != null && cropState.useMatrix != null ? cropState : null, resultWidth, resultHeight, originalWidth, originalHeight, rotationValue, framerate, true, gradientTopColor, gradientBottomColor, null, convertVideoParams); ByteBuffer[] encoderOutputBuffers = null; ByteBuffer[] encoderInputBuffers = null; @@ -493,7 +492,7 @@ public class MediaCodecVideoConvertor { inputSurface.makeCurrent(); encoder.start(); - outputSurface = new OutputSurface(savedFilterState, null, paintPath, blurPath, mediaEntities, cropState, resultWidth, resultHeight, originalWidth, originalHeight, rotationValue, framerate, false, gradientTopColor, gradientBottomColor, hdrInfo, parts); + outputSurface = new OutputSurface(savedFilterState, null, paintPath, blurPath, mediaEntities, cropState, resultWidth, resultHeight, originalWidth, originalHeight, rotationValue, framerate, false, gradientTopColor, gradientBottomColor, hdrInfo, convertVideoParams); if (hdrInfo == null && outputSurface.supportsEXTYUV() && hasHDR) { hdrInfo = new StoryEntry.HDRInfo(); hdrInfo.colorTransfer = colorTransfer; @@ -1333,6 +1332,9 @@ public class MediaCodecVideoConvertor { MediaController.SavedFilterState savedFilterState; String paintPath; String blurPath; + String messagePath; + String messageVideoMaskPath; + String backgroundPath; ArrayList mediaEntities; boolean isPhoto; MediaController.CropState cropState; @@ -1343,8 +1345,10 @@ public class MediaCodecVideoConvertor { boolean muted; boolean isStory; StoryEntry.HDRInfo hdrInfo; - ArrayList parts; public ArrayList soundInfos = new ArrayList(); + int account; + boolean isDark; + long wallpaperPeerId; private ConvertVideoParams() { @@ -1357,16 +1361,8 @@ public class MediaCodecVideoConvertor { int framerate, int bitrate, int originalBitrate, long startTime, long endTime, long avatarStartTime, boolean needCompress, long duration, - MediaController.SavedFilterState savedFilterState, - String paintPath, String blurPath, - ArrayList mediaEntities, - boolean isPhoto, - MediaController.CropState cropState, - boolean isRound, MediaController.VideoConvertorListener callback, - Integer gradientTopColor, Integer gradientBottomColor, - boolean muted, boolean isStory, StoryEntry.HDRInfo hdrInfo, - ArrayList parts) { + VideoEditedInfo info) { ConvertVideoParams params = new ConvertVideoParams(); params.videoPath = videoPath; params.cacheFile = cacheFile; @@ -1384,21 +1380,25 @@ public class MediaCodecVideoConvertor { params.avatarStartTime = avatarStartTime; params.needCompress = needCompress; params.duration = duration; - params.savedFilterState = savedFilterState; - params.paintPath = paintPath; - params.blurPath = blurPath; - params.mediaEntities = mediaEntities; - params.isPhoto = isPhoto; - params.cropState = cropState; - params.isRound = isRound; + params.savedFilterState = info.filterState; + params.paintPath = info.paintPath; + params.blurPath = info.blurPath; + params.mediaEntities = info.mediaEntities; + params.isPhoto = info.isPhoto; + params.cropState = info.cropState; + params.isRound = info.roundVideo; params.callback = callback; - params.gradientTopColor = gradientTopColor; - params.gradientBottomColor = gradientBottomColor; - params.muted = muted; - params.isStory = isStory; - params.hdrInfo = hdrInfo; - params.parts = parts; - + params.gradientTopColor = info.gradientTopColor; + params.gradientBottomColor = info.gradientBottomColor; + params.muted = info.muted; + params.isStory = info.isStory; + params.hdrInfo = info.hdrInfo; + params.isDark = info.isDark; + params.wallpaperPeerId = info.wallpaperPeerId; + params.account = info.account; + params.messagePath = info.messagePath; + params.messageVideoMaskPath = info.messageVideoMaskPath; + params.backgroundPath = info.backgroundPath; return params; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java index 140b797cf..6793076ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java @@ -39,8 +39,8 @@ public class OutputSurface implements SurfaceTexture.OnFrameAvailableListener { private boolean mFrameAvailable; private TextureRenderer mTextureRender; - public OutputSurface(MediaController.SavedFilterState savedFilterState, String imagePath, String paintPath, String blurPath, ArrayList mediaEntities, MediaController.CropState cropState, int w, int h, int originalW, int originalH, int rotation, float fps, boolean photo, Integer gradientTopColor, Integer gradientBottomColor, StoryEntry.HDRInfo hdrInfo, ArrayList parts) { - mTextureRender = new TextureRenderer(savedFilterState, imagePath, paintPath, blurPath, mediaEntities, cropState, w, h, originalW, originalH, rotation, fps, photo, gradientTopColor, gradientBottomColor, hdrInfo, parts); + public OutputSurface(MediaController.SavedFilterState savedFilterState, String imagePath, String paintPath, String blurPath, ArrayList mediaEntities, MediaController.CropState cropState, int w, int h, int originalW, int originalH, int rotation, float fps, boolean photo, Integer gradientTopColor, Integer gradientBottomColor, StoryEntry.HDRInfo hdrInfo, MediaCodecVideoConvertor.ConvertVideoParams params) { + mTextureRender = new TextureRenderer(savedFilterState, imagePath, paintPath, blurPath, mediaEntities, cropState, w, h, originalW, originalH, rotation, fps, photo, gradientTopColor, gradientBottomColor, hdrInfo, params); mTextureRender.surfaceCreated(); mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId()); mSurfaceTexture.setOnFrameAvailableListener(this); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 57f8bff82..fcd99b717 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -21,6 +21,7 @@ import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.opengl.GLES11Ext; import android.opengl.GLES20; import android.opengl.GLES30; @@ -30,6 +31,7 @@ import android.os.Build; import android.text.Layout; import android.text.SpannableString; import android.text.Spanned; +import android.text.TextUtils; import android.text.style.ReplacementSpan; import android.util.Log; import android.util.Pair; @@ -70,6 +72,7 @@ import org.telegram.ui.Components.Paint.Views.LocationMarker; import org.telegram.ui.Components.Paint.Views.PaintTextOptionsView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.Rect; +import org.telegram.ui.Stories.recorder.PreviewView; import org.telegram.ui.Stories.recorder.StoryEntry; import java.io.File; @@ -89,15 +92,11 @@ public class TextureRenderer { private FloatBuffer gradientTextureBuffer; private FloatBuffer textureBuffer; private FloatBuffer renderTextureBuffer; + private FloatBuffer maskTextureBuffer; private FloatBuffer bitmapVerticesBuffer; private FloatBuffer blurVerticesBuffer; - private FloatBuffer partsVerticesBuffer[]; - private FloatBuffer partsTextureBuffer; - private ArrayList parts; - private int[] partsTexture; - private boolean useMatrixForImagePath; float[] bitmapData = { @@ -109,6 +108,9 @@ public class TextureRenderer { private FilterShaders filterShaders; private String paintPath; + private String messagePath; + private String messageVideoMaskPath; + private String backgroundPath; private String blurPath; private String imagePath; private int imageWidth, imageHeight; @@ -118,6 +120,7 @@ public class TextureRenderer { private int originalHeight; private int transformedWidth; private int transformedHeight; + private Drawable backgroundDrawable; private BlurringShader blur; @@ -144,6 +147,35 @@ public class TextureRenderer { " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + "}\n"; + private static final String VERTEX_SHADER_MASK = + "uniform mat4 uMVPMatrix;\n" + + "uniform mat4 uSTMatrix;\n" + + "attribute vec4 aPosition;\n" + + "attribute vec4 aTextureCoord;\n" + + "attribute vec4 mTextureCoord;\n" + + "varying vec2 vTextureCoord;\n" + + "varying vec2 MTextureCoord;\n" + + "void main() {\n" + + " gl_Position = uMVPMatrix * aPosition;\n" + + " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + + " MTextureCoord = (uSTMatrix * mTextureCoord).xy;\n" + + "}\n"; + + private static final String VERTEX_SHADER_MASK_300 = + "#version 320 es\n" + + "uniform mat4 uMVPMatrix;\n" + + "uniform mat4 uSTMatrix;\n" + + "in vec4 aPosition;\n" + + "in vec4 aTextureCoord;\n" + + "in vec4 mTextureCoord;\n" + + "out vec2 vTextureCoord;\n" + + "out vec2 MTextureCoord;\n" + + "void main() {\n" + + " gl_Position = uMVPMatrix * aPosition;\n" + + " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + + " MTextureCoord = (uSTMatrix * mTextureCoord).xy;\n" + + "}\n"; + private static final String FRAGMENT_EXTERNAL_SHADER = "#extension GL_OES_EGL_image_external : require\n" + "precision highp float;\n" + @@ -153,6 +185,17 @@ public class TextureRenderer { " gl_FragColor = texture2D(sTexture, vTextureCoord);" + "}\n"; + private static final String FRAGMENT_EXTERNAL_MASK_SHADER = + "#extension GL_OES_EGL_image_external : require\n" + + "precision highp float;\n" + + "varying vec2 vTextureCoord;\n" + + "varying vec2 MTextureCoord;\n" + + "uniform samplerExternalOES sTexture;\n" + + "uniform sampler2D sMask;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(sTexture, vTextureCoord) * texture2D(sMask, MTextureCoord).a;\n" + + "}\n"; + private static final String FRAGMENT_SHADER = "precision highp float;\n" + "varying vec2 vTextureCoord;\n" + @@ -161,6 +204,16 @@ public class TextureRenderer { " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + "}\n"; + private static final String FRAGMENT_MASK_SHADER = + "precision highp float;\n" + + "varying vec2 vTextureCoord;\n" + + "varying vec2 MTextureCoord;\n" + + "uniform sampler2D sTexture;\n" + + "uniform sampler2D sMask;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(sTexture, vTextureCoord) * texture2D(sMask, MTextureCoord).a;\n" + + "}\n"; + private static final String GRADIENT_FRAGMENT_SHADER = "precision highp float;\n" + "varying vec2 vTextureCoord;\n" + @@ -181,11 +234,14 @@ public class TextureRenderer { private float[] mSTMatrix = new float[16]; private float[] mSTMatrixIdentity = new float[16]; private int mTextureID; + private int videoMaskTexture; private int[] mProgram; private int[] muMVPMatrixHandle; private int[] muSTMatrixHandle; private int[] maPositionHandle; private int[] maTextureHandle; + private int[] mmTextureHandle; + private int[] maskTextureHandle; private int gradientTopColorHandle, gradientBottomColorHandle; private int texSizeHandle; // todo: HDR handles @@ -207,6 +263,11 @@ public class TextureRenderer { private Canvas stickerCanvas; private float videoFps; + private int imagePathIndex = -1; + private int paintPathIndex = -1; + private int messagePathIndex = -1; + private int backgroundPathIndex = -1; + private Bitmap roundBitmap; private Canvas roundCanvas; private final android.graphics.Rect roundSrc = new android.graphics.Rect(); @@ -244,10 +305,9 @@ public class TextureRenderer { Integer gradientTopColor, Integer gradientBottomColor, StoryEntry.HDRInfo hdrInfo, - ArrayList parts + MediaCodecVideoConvertor.ConvertVideoParams params ) { isPhoto = photo; - this.parts = parts; float[] texData = { 0.f, 0.f, @@ -285,6 +345,9 @@ public class TextureRenderer { this.originalHeight = originalHeight; imagePath = image; paintPath = paint; + messagePath = params.messagePath; + messageVideoMaskPath = params.messageVideoMaskPath; + backgroundPath = params.backgroundPath; blurPath = blurtex; mediaEntities = entities; videoFps = fps == 0 ? 30 : fps; @@ -292,21 +355,12 @@ public class TextureRenderer { int count = 0; NUM_EXTERNAL_SHADER = count++; - if (gradientBottomColor != null && gradientTopColor != null) { - NUM_GRADIENT_SHADER = count++; - } - if (filterShaders != null) { - NUM_FILTER_SHADER = count++; - } - mProgram = new int[count]; - muMVPMatrixHandle = new int[count]; - muSTMatrixHandle = new int[count]; - maPositionHandle = new int[count]; - maTextureHandle = new int[count]; Matrix.setIdentityM(mMVPMatrix, 0); int textureRotation = 0; - if (gradientBottomColor != null && gradientTopColor != null) { + if (params != null && params.wallpaperPeerId != Long.MIN_VALUE) { + backgroundDrawable = PreviewView.getBackgroundDrawable(null, params.account, params.wallpaperPeerId, params.isDark); + } else if (gradientBottomColor != null && gradientTopColor != null) { final float[] verticesData = { -1.0f, -1.0f, 1.0f, -1.0f, @@ -325,7 +379,18 @@ public class TextureRenderer { gradientTextureBuffer.put(textureData).position(0); this.gradientTopColor = gradientTopColor; this.gradientBottomColor = gradientBottomColor; + NUM_GRADIENT_SHADER = count++; } + if (filterShaders != null) { + NUM_FILTER_SHADER = count++; + } + mProgram = new int[count]; + muMVPMatrixHandle = new int[count]; + muSTMatrixHandle = new int[count]; + maPositionHandle = new int[count]; + maTextureHandle = new int[count]; + mmTextureHandle = new int[count]; + maskTextureHandle = new int[count]; if (cropState != null) { if (cropState.useMatrix != null) { useMatrixForImagePath = true; @@ -455,35 +520,53 @@ public class TextureRenderer { } renderTextureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); renderTextureBuffer.put(textureData).position(0); + + textureData = new float[]{ + 0.f, 0.f, + 1.f, 0.f, + 0.f, 1.f, + 1.f, 1.f + }; + maskTextureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + maskTextureBuffer.put(textureData).position(0); } public int getTextureId() { return mTextureID; } - private void drawGradient() { - if (NUM_GRADIENT_SHADER < 0) { - return; + private void drawBackground() { + if (NUM_GRADIENT_SHADER >= 0) { + GLES20.glUseProgram(mProgram[NUM_GRADIENT_SHADER]); + + GLES20.glVertexAttribPointer(maPositionHandle[NUM_GRADIENT_SHADER], 2, GLES20.GL_FLOAT, false, 8, gradientVerticesBuffer); + GLES20.glEnableVertexAttribArray(maPositionHandle[NUM_GRADIENT_SHADER]); + GLES20.glVertexAttribPointer(maTextureHandle[NUM_GRADIENT_SHADER], 2, GLES20.GL_FLOAT, false, 8, gradientTextureBuffer); + GLES20.glEnableVertexAttribArray(maTextureHandle[NUM_GRADIENT_SHADER]); + + GLES20.glUniformMatrix4fv(muSTMatrixHandle[NUM_GRADIENT_SHADER], 1, false, mSTMatrix, 0); + GLES20.glUniformMatrix4fv(muMVPMatrixHandle[NUM_GRADIENT_SHADER], 1, false, mMVPMatrix, 0); + + GLES20.glUniform4f(gradientTopColorHandle, Color.red(gradientTopColor) / 255f, Color.green(gradientTopColor) / 255f, Color.blue(gradientTopColor) / 255f, Color.alpha(gradientTopColor) / 255f); + GLES20.glUniform4f(gradientBottomColorHandle, Color.red(gradientBottomColor) / 255f, Color.green(gradientBottomColor) / 255f, Color.blue(gradientBottomColor) / 255f, Color.alpha(gradientBottomColor) / 255f); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + } else if (backgroundPathIndex >= 0) { + GLES20.glUseProgram(simpleShaderProgram); + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + + GLES20.glUniform1i(simpleSourceImageHandle, 0); + GLES20.glEnableVertexAttribArray(simpleInputTexCoordHandle); + GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureBuffer); + GLES20.glEnableVertexAttribArray(simplePositionHandle); + + drawTexture(true, paintTexture[backgroundPathIndex], -10000, -10000, -10000, -10000, 0, false, false, -1); } - GLES20.glUseProgram(mProgram[NUM_GRADIENT_SHADER]); - - GLES20.glVertexAttribPointer(maPositionHandle[NUM_GRADIENT_SHADER], 2, GLES20.GL_FLOAT, false, 8, gradientVerticesBuffer); - GLES20.glEnableVertexAttribArray(maPositionHandle[NUM_GRADIENT_SHADER]); - GLES20.glVertexAttribPointer(maTextureHandle[NUM_GRADIENT_SHADER], 2, GLES20.GL_FLOAT, false, 8, gradientTextureBuffer); - GLES20.glEnableVertexAttribArray(maTextureHandle[NUM_GRADIENT_SHADER]); - - GLES20.glUniformMatrix4fv(muSTMatrixHandle[NUM_GRADIENT_SHADER], 1, false, mSTMatrix, 0); - GLES20.glUniformMatrix4fv(muMVPMatrixHandle[NUM_GRADIENT_SHADER], 1, false, mMVPMatrix, 0); - - GLES20.glUniform4f(gradientTopColorHandle, Color.red(gradientTopColor) / 255f, Color.green(gradientTopColor) / 255f, Color.blue(gradientTopColor) / 255f, Color.alpha(gradientTopColor) / 255f); - GLES20.glUniform4f(gradientBottomColorHandle, Color.red(gradientBottomColor) / 255f, Color.green(gradientBottomColor) / 255f, Color.blue(gradientBottomColor) / 255f, Color.alpha(gradientBottomColor) / 255f); - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } public void drawFrame(SurfaceTexture st, long time) { boolean blurred = false; if (isPhoto) { - drawGradient(); + drawBackground(); } else { st.getTransformMatrix(mSTMatrix); if (BuildVars.LOGS_ENABLED && firstFrame) { @@ -530,16 +613,26 @@ public class TextureRenderer { stMatrix = mSTMatrix; } - drawGradient(); + drawBackground(); GLES20.glUseProgram(mProgram[index]); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(target, texture); + if (messageVideoMaskPath != null && videoMaskTexture != -1) { + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, videoMaskTexture); + GLES20.glUniform1i(maskTextureHandle[index], 1); + } + GLES20.glVertexAttribPointer(maPositionHandle[index], 2, GLES20.GL_FLOAT, false, 8, verticesBuffer); GLES20.glEnableVertexAttribArray(maPositionHandle[index]); GLES20.glVertexAttribPointer(maTextureHandle[index], 2, GLES20.GL_FLOAT, false, 8, renderTextureBuffer); GLES20.glEnableVertexAttribArray(maTextureHandle[index]); + if (messageVideoMaskPath != null && videoMaskTexture != -1) { + GLES20.glVertexAttribPointer(mmTextureHandle[index], 2, GLES20.GL_FLOAT, false, 8, maskTextureBuffer); + GLES20.glEnableVertexAttribArray(mmTextureHandle[index]); + } if (texSizeHandle != 0) { GLES20.glUniform2f(texSizeHandle, transformedWidth, transformedHeight); @@ -590,7 +683,7 @@ public class TextureRenderer { GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } } - if (isPhoto || paintTexture != null || stickerTexture != null || partsTexture != null) { + if (isPhoto || paintTexture != null || stickerTexture != null) { GLES20.glUseProgram(simpleShaderProgram); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); @@ -599,20 +692,14 @@ public class TextureRenderer { GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureBuffer); GLES20.glEnableVertexAttribArray(simplePositionHandle); } - if (paintTexture != null && imagePath != null) { - for (int a = 0; a < 1; a++) { - drawTexture(true, paintTexture[a], -10000, -10000, -10000, -10000, 0, false, useMatrixForImagePath && isPhoto && a == 0, -1); - } + if (imagePathIndex >= 0) { + drawTexture(true, paintTexture[imagePathIndex], -10000, -10000, -10000, -10000, 0, false, useMatrixForImagePath && isPhoto, -1); } - if (partsTexture != null) { - for (int a = 0; a < partsTexture.length; a++) { - drawTexture(true, partsTexture[a], -10000, -10000, -10000, -10000, 0, false, false, a); - } + if (paintPathIndex >= 0) { + drawTexture(true, paintTexture[paintPathIndex], -10000, -10000, -10000, -10000, 0, false, false, -1); } - if (paintTexture != null) { - for (int a = (imagePath != null ? 1 : 0); a < paintTexture.length; a++) { - drawTexture(true, paintTexture[a], -10000, -10000, -10000, -10000, 0, false, useMatrixForImagePath && isPhoto && a == 0, -1); - } + if (messagePathIndex >= 0) { + drawTexture(true, paintTexture[messagePathIndex], -10000, -10000, -10000, -10000, 0, false, false, -1); } if (stickerTexture != null) { for (int a = 0, N = mediaEntities.size(); a < N; a++) { @@ -857,9 +944,9 @@ public class TextureRenderer { } } bitmapVerticesBuffer.put(bitmapData).position(0); - GLES20.glVertexAttribPointer(simplePositionHandle, 2, GLES20.GL_FLOAT, false, 8, matrixIndex >= 0 ? partsVerticesBuffer[matrixIndex] : (useCropMatrix ? verticesBuffer : bitmapVerticesBuffer)); + GLES20.glVertexAttribPointer(simplePositionHandle, 2, GLES20.GL_FLOAT, false, 8, useCropMatrix ? verticesBuffer : bitmapVerticesBuffer); GLES20.glEnableVertexAttribArray(simpleInputTexCoordHandle); - GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, matrixIndex >= 0 ? partsTextureBuffer : (useCropMatrix ? renderTextureBuffer : textureBuffer)); + GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, useCropMatrix ? renderTextureBuffer : textureBuffer); if (bind) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture); } @@ -874,22 +961,27 @@ public class TextureRenderer { @SuppressLint("WrongConstant") public void surfaceCreated() { for (int a = 0; a < mProgram.length; a++) { - String shader = null; + String fragSshader = null; + String vertexShader = VERTEX_SHADER; if (a == NUM_EXTERNAL_SHADER) { - shader = FRAGMENT_EXTERNAL_SHADER; + fragSshader = messageVideoMaskPath != null ? FRAGMENT_EXTERNAL_MASK_SHADER : FRAGMENT_EXTERNAL_SHADER; + vertexShader = messageVideoMaskPath != null ? VERTEX_SHADER_MASK : VERTEX_SHADER; } else if (a == NUM_FILTER_SHADER) { - shader = FRAGMENT_SHADER; + fragSshader = messageVideoMaskPath != null ? FRAGMENT_MASK_SHADER : FRAGMENT_SHADER; + vertexShader = messageVideoMaskPath != null ? VERTEX_SHADER_MASK : VERTEX_SHADER; } else if (a == NUM_GRADIENT_SHADER) { - shader = GRADIENT_FRAGMENT_SHADER; + fragSshader = GRADIENT_FRAGMENT_SHADER; } - if (shader == null) { + if (vertexShader == null || fragSshader == null) { continue; } - mProgram[a] = createProgram(VERTEX_SHADER, shader, false); + mProgram[a] = createProgram(vertexShader, fragSshader, false); maPositionHandle[a] = GLES20.glGetAttribLocation(mProgram[a], "aPosition"); maTextureHandle[a] = GLES20.glGetAttribLocation(mProgram[a], "aTextureCoord"); + mmTextureHandle[a] = GLES20.glGetAttribLocation(mProgram[a], "mTextureCoord"); muMVPMatrixHandle[a] = GLES20.glGetUniformLocation(mProgram[a], "uMVPMatrix"); muSTMatrixHandle[a] = GLES20.glGetUniformLocation(mProgram[a], "uSTMatrix"); + maskTextureHandle[a] = GLES20.glGetUniformLocation(mProgram[a], "sMask"); if (a == NUM_GRADIENT_SHADER) { gradientTopColorHandle = GLES20.glGetUniformLocation(mProgram[a], "gradientTopColor"); gradientBottomColorHandle = GLES20.glGetUniformLocation(mProgram[a], "gradientBottomColor"); @@ -904,6 +996,23 @@ public class TextureRenderer { GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + if (messageVideoMaskPath != null) { + try { + GLES20.glGenTextures(1, textures, 0); + GLES20.glBindTexture(GL10.GL_TEXTURE_2D, videoMaskTexture = textures[0]); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); + Bitmap bitmap = BitmapFactory.decodeFile(messageVideoMaskPath); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + } catch (Exception e) { + FileLog.e(e); + videoMaskTexture = -1; + } + } + if (blurPath != null && cropState != null && cropState.useMatrix != null) { blur = new BlurringShader(); if (!blur.setup(transformedWidth / (float) transformedHeight, true, 0)) { @@ -980,7 +1089,7 @@ public class TextureRenderer { } } } - if (filterShaders != null || imagePath != null || paintPath != null || mediaEntities != null || parts != null) { + if (filterShaders != null || imagePath != null || paintPath != null || messagePath != null || mediaEntities != null) { int vertexShader = FilterShaders.loadShader(GLES20.GL_VERTEX_SHADER, FilterShaders.simpleVertexShaderCode); int fragmentShader = FilterShaders.loadShader(GLES20.GL_FRAGMENT_SHADER, FilterShaders.simpleFragmentShaderCode); if (vertexShader != 0 && fragmentShader != 0) { @@ -1008,24 +1117,41 @@ public class TextureRenderer { filterShaders.create(); filterShaders.setRenderData(null, 0, mTextureID, originalWidth, originalHeight); } - if (imagePath != null || paintPath != null) { - paintTexture = new int[(imagePath != null ? 1 : 0) + (paintPath != null ? 1 : 0)]; + if (imagePath != null || paintPath != null || messagePath != null) { + int texturePathesCount = 0; + if (imagePath != null) { + imagePathIndex = texturePathesCount++; + } + if (paintPath != null) { + paintPathIndex = texturePathesCount++; + } + if (messagePath != null) { + messagePathIndex = texturePathesCount++; + } + if (backgroundPath != null) { + backgroundPathIndex = texturePathesCount++; + } + paintTexture = new int[texturePathesCount]; GLES20.glGenTextures(paintTexture.length, paintTexture, 0); try { for (int a = 0; a < paintTexture.length; a++) { String path; int angle = 0, invert = 0; - if (a == 0 && imagePath != null) { + if (a == imagePathIndex) { path = imagePath; Pair orientation = AndroidUtilities.getImageOrientation(path); angle = orientation.first; invert = orientation.second; - } else { + } else if (a == paintPathIndex) { path = paintPath; + } else if (a == backgroundPathIndex) { + path = backgroundPath; + } else { // messagePathIndex + path = messagePath; } Bitmap bitmap = BitmapFactory.decodeFile(path); if (bitmap != null) { - if (a == 0 && imagePath != null && !useMatrixForImagePath) { + if (a == imagePathIndex && !useMatrixForImagePath) { Bitmap newBitmap = Bitmap.createBitmap(transformedWidth, transformedHeight, Bitmap.Config.ARGB_8888); newBitmap.eraseColor(0xff000000); Canvas canvas = new Canvas(newBitmap); @@ -1045,7 +1171,7 @@ public class TextureRenderer { bitmap = newBitmap; } - if (a == 0 && imagePath != null) { + if (a == imagePathIndex) { imageWidth = bitmap.getWidth(); imageHeight = bitmap.getHeight(); } @@ -1062,56 +1188,7 @@ public class TextureRenderer { FileLog.e(e); } } - if (parts != null && !parts.isEmpty()) { - partsTexture = new int[parts.size()]; - partsVerticesBuffer = new FloatBuffer[parts.size()]; - GLES20.glGenTextures(partsTexture.length, partsTexture, 0); - try { - for (int a = 0; a < partsTexture.length; a++) { - StoryEntry.Part part = parts.get(a); - String path = part.file.getAbsolutePath(); - - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeFile(path, opts); - opts.inJustDecodeBounds = false; - opts.inSampleSize = StoryEntry.calculateInSampleSize(opts, transformedWidth, transformedHeight); - Bitmap bitmap = BitmapFactory.decodeFile(path, opts); - GLES20.glBindTexture(GL10.GL_TEXTURE_2D, partsTexture[a]); - GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); - GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); - GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); - - final float[] verticesData = { - 0, 0, - part.width, 0, - 0, part.height, - part.width, part.height - }; - part.matrix.mapPoints(verticesData); - for (int i = 0; i < 4; i++) { - verticesData[i * 2] = verticesData[i * 2] / transformedWidth * 2f - 1f; - verticesData[i * 2 + 1] = 1f - verticesData[i * 2 + 1] / transformedHeight * 2f; - } - partsVerticesBuffer[a] = ByteBuffer.allocateDirect(verticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); - partsVerticesBuffer[a].put(verticesData).position(0); - } - } catch (Throwable e2) { - FileLog.e(e2); - } - - final float[] textureData = { - 0, 0, - 1f, 0, - 0, 1f, - 1f, 1f - }; - partsTextureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); - partsTextureBuffer.put(textureData).position(0); - } - if (mediaEntities != null) { + if (mediaEntities != null || backgroundDrawable != null) { try { stickerBitmap = Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888); stickerTexture = new int[1]; @@ -1335,17 +1412,21 @@ public class TextureRenderer { entity.firstSeek = true; } } else { + String path = entity.text; + if (!TextUtils.isEmpty(entity.segmentedPath) && (entity.subType & 16) != 0) { + path = entity.segmentedPath; + } if (Build.VERSION.SDK_INT >= 19) { BitmapFactory.Options opts = new BitmapFactory.Options(); if (entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO) { opts.inMutable = true; } - entity.bitmap = BitmapFactory.decodeFile(entity.text, opts); + entity.bitmap = BitmapFactory.decodeFile(path, opts); } else { try { - File path = new File(entity.text); - RandomAccessFile file = new RandomAccessFile(path, "r"); - ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, path.length()); + File filePath = new File(path); + RandomAccessFile file = new RandomAccessFile(filePath, "r"); + ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, filePath.length()); BitmapFactory.Options bmOptions = new BitmapFactory.Options(); bmOptions.inJustDecodeBounds = true; Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true); @@ -1461,8 +1542,14 @@ public class TextureRenderer { } public void changeFragmentShader(String fragmentExternalShader, String fragmentShader, boolean is300) { + String vertexCode; + if (messageVideoMaskPath != null) { + vertexCode = is300 ? VERTEX_SHADER_MASK_300 : VERTEX_SHADER_MASK; + } else { + vertexCode = is300 ? VERTEX_SHADER_300 : VERTEX_SHADER; + } if (NUM_EXTERNAL_SHADER >= 0 && NUM_EXTERNAL_SHADER < mProgram.length) { - int newProgram = createProgram(is300 ? VERTEX_SHADER_300 : VERTEX_SHADER, fragmentExternalShader, is300); + int newProgram = createProgram(vertexCode, fragmentExternalShader, is300); if (newProgram != 0) { GLES20.glDeleteProgram(mProgram[NUM_EXTERNAL_SHADER]); mProgram[NUM_EXTERNAL_SHADER] = newProgram; @@ -1471,7 +1558,7 @@ public class TextureRenderer { } } if (NUM_FILTER_SHADER >= 0 && NUM_FILTER_SHADER < mProgram.length) { - int newProgram = createProgram(is300 ? VERTEX_SHADER_300 : VERTEX_SHADER, fragmentShader, is300); + int newProgram = createProgram(vertexCode, fragmentShader, is300); if (newProgram != 0) { GLES20.glDeleteProgram(mProgram[NUM_FILTER_SHADER]); mProgram[NUM_FILTER_SHADER] = newProgram; 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 84bf20c0b..ebbf0456b 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -77,8 +77,8 @@ import android.telephony.TelephonyManager; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.LruCache; +import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; @@ -236,6 +236,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa private BluetoothAdapter btAdapter; private Instance.TrafficStats prevTrafficStats; private boolean isBtHeadsetConnected; + private volatile boolean isCallEnded; private Runnable updateNotificationRunnable; @@ -1115,6 +1116,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa tgVoip[CAPTURE_DEVICE_CAMERA].switchCamera(!isFrontFaceCamera); } + public boolean isSwitchingCamera() { + return switchingCamera; + } + public void createCaptureDevice(boolean screencast) { int index = screencast ? CAPTURE_DEVICE_SCREEN : CAPTURE_DEVICE_CAMERA; int deviceType; @@ -1598,6 +1603,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } } + public void sendCallRating(int rating) { + VoIPHelper.sendCallRating(privateCall.id, privateCall.access_hash, currentAccount, rating); + } + public byte[] getEncryptionKey() { return authKey; } @@ -2711,16 +2720,38 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } public void toggleSpeakerphoneOrShowRouteSheet(Context context, boolean fromOverlayWindow) { + toggleSpeakerphoneOrShowRouteSheet(context, fromOverlayWindow, null); + } + + public void switchToSpeaker() { + AndroidUtilities.runOnUIThread(() -> { + VoipAudioManager vam = VoipAudioManager.get(); + if ((isBluetoothHeadsetConnected() && hasEarpiece()) || isHeadsetPlugged || isSpeakerphoneOn()) { + return; + } + vam.setSpeakerphoneOn(true); + vam.isBluetoothAndSpeakerOnAsync((isBluetoothOn, isSpeakerOn) -> { + updateOutputGainControlState(); + for (StateListener l : stateListeners) { + l.onAudioSettingsChanged(); + } + }); + }, 500); + } + + public void toggleSpeakerphoneOrShowRouteSheet(Context context, boolean fromOverlayWindow, Integer selectedPos) { if (isBluetoothHeadsetConnected() && hasEarpiece()) { BottomSheet.Builder builder = new BottomSheet.Builder(context) .setTitle(LocaleController.getString("VoipOutputDevices", R.string.VoipOutputDevices), true) + .selectedPos(selectedPos) + .setCellType(selectedPos != null ? BottomSheet.Builder.CELL_TYPE_CALL : 0) .setItems(new CharSequence[]{ LocaleController.getString("VoipAudioRoutingSpeaker", R.string.VoipAudioRoutingSpeaker), isHeadsetPlugged ? LocaleController.getString("VoipAudioRoutingHeadset", R.string.VoipAudioRoutingHeadset) : LocaleController.getString("VoipAudioRoutingEarpiece", R.string.VoipAudioRoutingEarpiece), currentBluetoothDeviceName != null ? currentBluetoothDeviceName : LocaleController.getString("VoipAudioRoutingBluetooth", R.string.VoipAudioRoutingBluetooth)}, - new int[]{R.drawable.calls_menu_speaker, - isHeadsetPlugged ? R.drawable.calls_menu_headset : R.drawable.calls_menu_phone, - R.drawable.calls_menu_bluetooth}, (dialog, which) -> { + new int[]{R.drawable.msg_call_speaker, + isHeadsetPlugged ? R.drawable.calls_menu_headset : R.drawable.msg_call_earpiece, + R.drawable.msg_call_bluetooth}, (dialog, which) -> { if (getSharedInstance() == null) { return; } @@ -2728,6 +2759,15 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa }); BottomSheet bottomSheet = builder.create(); + bottomSheet.setOnShowListener(dialog -> { + for (int i = 0; i < bottomSheet.getItemViews().size(); i++) { + bottomSheet.setItemColor(i, Theme.getColor(Theme.key_dialogTextBlack), Theme.getColor(Theme.key_dialogTextBlack)); + } + if (selectedPos != null) { + int selectedColor = Theme.getColor(Theme.key_dialogTextLink); + bottomSheet.setItemColor(selectedPos, selectedColor, selectedColor); + } + }); if (fromOverlayWindow) { if (Build.VERSION.SDK_INT >= 26) { bottomSheet.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); @@ -2752,7 +2792,13 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } else { am.setBluetoothScoOn(!am.isBluetoothScoOn()); } - updateOutputGainControlState(); + vam.isBluetoothAndSpeakerOnAsync((isBluetoothOn, isSpeakerOn) -> { + updateOutputGainControlState(); + for (StateListener l : stateListeners) { + l.onAudioSettingsChanged(); + } + }); + return; } else { speakerphoneStateToSet = !speakerphoneStateToSet; } @@ -3482,6 +3528,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa return ret; } + public boolean hasRate() { + return needRateCall || forceRating; + } + private void onTgVoipStop(Instance.FinalState finalState) { if (user == null) { return; @@ -3493,11 +3543,6 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa e.printStackTrace(); } } - - if (needRateCall || forceRating || finalState.isRatingSuggested) { - startRatingActivity(); - needRateCall = false; - } if (needSendDebugLog && finalState.debugLog != null) { TLRPC.TL_phone_saveCallDebug req = new TLRPC.TL_phone_saveCallDebug(); req.debug = new TLRPC.TL_dataJSON(); @@ -3753,6 +3798,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } else { audioRouteToSet = AUDIO_ROUTE_EARPIECE; } + if (lastSensorEvent != null) { + //For the case when the phone was put to the ear before configureDeviceForCall. + onSensorChanged(lastSensorEvent); + } } updateOutputGainControlState(); audioConfigured = true; @@ -3787,9 +3836,12 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } } + private SensorEvent lastSensorEvent; + @SuppressLint("NewApi") @Override public void onSensorChanged(SensorEvent event) { + lastSensorEvent = event; if (unmutedByHold || remoteVideoState == Instance.VIDEO_STATE_ACTIVE || videoState[CAPTURE_DEVICE_CAMERA] == Instance.VIDEO_STATE_ACTIVE) { return; } @@ -3801,6 +3853,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } boolean newIsNear = event.values[0] < Math.min(event.sensor.getMaximumRange(), 3); checkIsNear(newIsNear); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.nearEarEvent, newIsNear); } } @@ -4255,9 +4308,9 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa if (groupCall == null && !wasEstablished) { wasEstablished = true; if (!isProximityNear && !privateCall.video) { - Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); - if (vibrator.hasVibrator()) { - vibrator.vibrate(100); + try { + LaunchActivity.getLastFragment().getFragmentView().performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { } } AndroidUtilities.runOnUIThread(new Runnable() { @@ -4276,7 +4329,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa } } } - if (newState == STATE_RECONNECTING) { + if (newState == STATE_RECONNECTING && !isCallEnded) { Utilities.globalQueue.postRunnable(() -> { if (spPlayId != 0) { soundPool.stop(spPlayId); @@ -4324,6 +4377,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa if (BuildVars.LOGS_ENABLED) { FileLog.d("Call " + getCallID() + " ended"); } + isCallEnded = true; if (groupCall != null && (!playedConnectedSound || onDestroyRunnable != null)) { needPlayEndSound = false; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoipAudioManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoipAudioManager.java index e96edb73e..b2b93bea1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoipAudioManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoipAudioManager.java @@ -4,6 +4,8 @@ import static android.content.Context.AUDIO_SERVICE; import android.media.AudioManager; + +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Utilities; @@ -47,6 +49,15 @@ public class VoipAudioManager { return isSpeakerphoneOn; } + public void isBluetoothAndSpeakerOnAsync(Utilities.Callback2 onDone) { + Utilities.globalQueue.postRunnable(() -> { + AudioManager audioManager = getAudioManager(); + boolean isBluetoothScoOn = audioManager.isBluetoothScoOn(); + boolean isSpeakerphoneOn = audioManager.isSpeakerphoneOn(); + AndroidUtilities.runOnUIThread(() -> onDone.run(isBluetoothScoOn, isSpeakerphoneOn)); + }); + } + private AudioManager getAudioManager() { return (AudioManager) ApplicationLoader.applicationContext.getSystemService(AUDIO_SERVICE); } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 8a50fb737..5f373304c 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -245,7 +245,7 @@ public class ConnectionsManager extends BaseController { if (getUserConfig().getCurrentUser() != null) { userPremium = getUserConfig().getCurrentUser().premium; } - init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, systemLangCode, configPath, FileLog.getNetworkLogPath(), pushString, fingerprint, timezoneOffset, getUserConfig().getClientUserId(), userPremium, enablePushConnection); + init(SharedConfig.buildVersion(), TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, systemLangCode, configPath, FileLog.getNetworkLogPath(), pushString, fingerprint, timezoneOffset, getUserConfig().getClientUserId(), userPremium, enablePushConnection); } private String getRegId() { diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index f4a1d7273..b6fdda8a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -17,6 +17,7 @@ import android.text.TextUtils; import androidx.annotation.Nullable; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -75,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 = 167; + public static final int LAYER = 170; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -8651,6 +8652,9 @@ public class TLRPC { flags = stream.readInt32(exception); nopremium = (flags & 8) != 0; spoiler = (flags & 16) != 0; + video = (flags & 64) != 0; + round = (flags & 128) != 0; + voice = (flags & 256) != 0; if ((flags & 1) != 0) { document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -8666,6 +8670,9 @@ public class TLRPC { stream.writeInt32(constructor); flags = nopremium ? (flags | 8) : (flags &~ 8); flags = spoiler ? (flags | 16) : (flags &~ 16); + flags = video ? (flags | 64) : (flags &~ 64); + flags = round ? (flags | 128) : (flags &~ 128); + flags = voice ? (flags | 256) : (flags &~ 256); stream.writeInt32(flags); if ((flags & 1) != 0) { document.serializeToStream(stream); @@ -12303,7 +12310,7 @@ public class TLRPC { } } } - + public static class WebPageAttribute extends TLObject { public int flags; @@ -13088,6 +13095,7 @@ public class TLRPC { public boolean view_forum_as_messages; public ChatReactions available_reactions; public TL_stories.PeerStories stories; + public WallPaper wallpaper; public long inviterId; //custom public int invitesCount; //custom @@ -13098,9 +13106,12 @@ public class TLRPC { case 0xc9d31138: result = new TL_chatFull(); break; - case 0x723027bd: + case TL_channelFull.constructor: result = new TL_channelFull(); break; + case TL_channelFull_layer167.constructor: + result = new TL_channelFull_layer167(); + break; case 0xf2355507: result = new TL_channelFull_layer162(); break; @@ -15549,6 +15560,284 @@ public class TLRPC { } public static class TL_channelFull extends ChatFull { + public static final int constructor = 0xf2bcb6f; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + can_set_stickers = (flags & 128) != 0; + hidden_prehistory = (flags & 1024) != 0; + can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; + flags2 = stream.readInt32(exception); + can_delete_channel = (flags2 & 1) != 0; + antispam = (flags2 & 2) != 0; + participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; + stories_pinned_available = (flags2 & 32) != 0; + view_forum_as_messages = (flags2 & 64) != 0; + id = stream.readInt64(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + banned_count = stream.readInt32(exception); + } + if ((flags & 8192) != 0) { + online_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + read_outbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8388608) != 0) { + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), 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++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt64(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + stickerset = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + available_min_id = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + folder_id = stream.readInt32(exception); + } + if ((flags & 16384) != 0) { + linked_chat_id = stream.readInt64(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + slowmode_seconds = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + slowmode_next_send_date = stream.readInt32(exception); + } + if ((flags & 4096) != 0) { + stats_dc = stream.readInt32(exception); + } + pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16777216) != 0) { + ttl_period = stream.readInt32(exception); + } + if ((flags & 33554432) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + pending_suggestions.add(stream.readString(exception)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 134217728) != 0) { + theme_emoticon = stream.readString(exception); + } + if ((flags & 268435456) != 0) { + requests_pending = stream.readInt32(exception); + } + if ((flags & 268435456) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_requesters.add(stream.readInt64(exception)); + } + } + if ((flags & 536870912) != 0) { + default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 1073741824) != 0) { + available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 16) != 0) { + stories = TL_stories.PeerStories.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 128) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + flags = can_set_stickers ? (flags | 128) : (flags &~ 128); + flags = hidden_prehistory ? (flags | 1024) : (flags &~ 1024); + flags = can_set_location ? (flags | 65536) : (flags &~ 65536); + flags = has_scheduled ? (flags | 524288) : (flags &~ 524288); + flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); + flags = blocked ? (flags | 4194304) : (flags &~ 4194304); + stream.writeInt32(flags); + flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); + flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); + flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); + flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); + flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); + flags2 = view_forum_as_messages ? (flags2 | 64) : (flags2 &~ 64); + stream.writeInt32(flags2); + stream.writeInt64(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(banned_count); + } + if ((flags & 8192) != 0) { + stream.writeInt32(online_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(read_outbox_max_id); + stream.writeInt32(unread_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + if ((flags & 8388608) != 0) { + exported_invite.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt64(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + if ((flags & 256) != 0) { + stickerset.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeInt32(available_min_id); + } + if ((flags & 2048) != 0) { + stream.writeInt32(folder_id); + } + if ((flags & 16384) != 0) { + stream.writeInt64(linked_chat_id); + } + if ((flags & 32768) != 0) { + location.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(slowmode_seconds); + } + if ((flags & 262144) != 0) { + stream.writeInt32(slowmode_next_send_date); + } + if ((flags & 4096) != 0) { + stream.writeInt32(stats_dc); + } + stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } + if ((flags & 16777216) != 0) { + stream.writeInt32(ttl_period); + } + if ((flags & 33554432) != 0) { + stream.writeInt32(0x1cb5c415); + count = pending_suggestions.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(pending_suggestions.get(a)); + } + } + if ((flags & 67108864) != 0) { + groupcall_default_join_as.serializeToStream(stream); + } + if ((flags & 134217728) != 0) { + stream.writeString(theme_emoticon); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(requests_pending); + } + if ((flags & 268435456) != 0) { + stream.writeInt32(0x1cb5c415); + count = recent_requesters.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_requesters.get(a)); + } + } + if ((flags & 536870912) != 0) { + default_send_as.serializeToStream(stream); + } + if ((flags & 1073741824) != 0) { + available_reactions.serializeToStream(stream); + } + if ((flags2 & 16) != 0) { + stories.serializeToStream(stream); + } + if ((flags2 & 128) != 0) { + wallpaper.serializeToStream(stream); + } + } + } + + public static class TL_channelFull_layer167 extends TL_channelFull { public static final int constructor = 0x723027bd; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -19971,7 +20260,10 @@ public class TLRPC { case 0x13767230: result = new TL_keyboardButtonWebView(); break; - case 0xd0b468c: + case TL_keyboardButtonRequestPeer_layer168.constructor: + result = new TL_keyboardButtonRequestPeer_layer168(); + break; + case TL_keyboardButtonRequestPeer.constructor: result = new TL_keyboardButtonRequestPeer(); break; } @@ -24156,9 +24448,15 @@ public class TLRPC { stream.writeInt32(stories_max_id); } if ((flags2 & 256) != 0) { + if (color == null) { + color = new TL_peerColor(); + } color.serializeToStream(stream); } if ((flags2 & 512) != 0) { + if (profile_color == null) { + profile_color = new TL_peerColor(); + } profile_color.serializeToStream(stream); } } @@ -26321,9 +26619,12 @@ public class TLRPC { case 0x55555550: result = new TL_messageActionUserJoined(); break; - case 0xd2cfdb0e: + case TL_messageActionGiftCode.constructor: result = new TL_messageActionGiftCode(); break; + case TL_messageActionGiftCode_layer167.constructor: + result = new TL_messageActionGiftCode_layer167(); + break; case 0xb18a431c: result = new TL_messageActionTopicEdit_layer149(); break; @@ -26420,7 +26721,10 @@ public class TLRPC { case 0xc83d6aec: result = new TL_messageActionGiftPremium(); break; - case 0xfe77345d: + case TL_messageActionRequestedPeer_layer168.constructor: + result = new TL_messageActionRequestedPeer_layer168(); + break; + case TL_messageActionRequestedPeer.constructor: result = new TL_messageActionRequestedPeer(); break; } @@ -33055,6 +33359,9 @@ public class TLRPC { case 0x44c1f8e9: result = new TL_inputStickerSetEmojiDefaultTopicIcons(); break; + case TL_inputStickerSetEmojiChannelDefaultStatuses.constructor: + result = new TL_inputStickerSetEmojiChannelDefaultStatuses(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in InputStickerSet", constructor)); @@ -33075,6 +33382,15 @@ public class TLRPC { } } + public static class TL_inputStickerSetEmojiChannelDefaultStatuses extends InputStickerSet { + public static final int constructor = 0x49748553; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_inputStickerSetEmojiDefaultStatuses extends InputStickerSet { public static final int constructor = 0x29d0f5ee; @@ -34068,6 +34384,12 @@ public class TLRPC { case TL_updatePeerWallpaper.constructor: result = new TL_updatePeerWallpaper(); break; + case TL_updateSavedDialogPinned.constructor: + result = new TL_updateSavedDialogPinned(); + break; + case TL_updatePinnedSavedDialogs.constructor: + result = new TL_updatePinnedSavedDialogs(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); @@ -35252,7 +35574,7 @@ public class TLRPC { public long user_id; public EmojiStatus emoji_status; - + public void readParams(AbstractSerializedData stream, boolean exception) { user_id = stream.readInt64(exception); emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -35459,10 +35781,10 @@ public class TLRPC { draft.serializeToStream(stream); } } - + public static class TL_updateNewAuthorization extends Update { public static final int constructor = 0x8951abef; - + public int flags; public boolean unconfirmed; public long hash; @@ -36084,7 +36406,7 @@ public class TLRPC { stream.writeInt32(constructor); } } - + public static class TL_updateRecentEmojiStatuses extends Update { public static final int constructor = 0x30f443db; @@ -42648,17 +42970,21 @@ public class TLRPC { public int fourth_background_color; public int intensity; public int rotation; + public String emoticon; public static WallPaperSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { WallPaperSettings result = null; switch (constructor) { - case 0xa12f40b8: + case TL_wallPaperSettings_layer106.constructor: result = new TL_wallPaperSettings_layer106(); break; - case 0x5086cf8: + case TL_wallPaperSettings_layer128.constructor: result = new TL_wallPaperSettings_layer128(); break; - case 0x1dc1bca4: + case TL_wallPaperSettings_layer167.constructor: + result = new TL_wallPaperSettings_layer167(); + break; + case TL_wallPaperSettings.constructor: result = new TL_wallPaperSettings(); break; } @@ -42745,6 +43071,66 @@ public class TLRPC { } public static class TL_wallPaperSettings extends WallPaperSettings { + public static final int constructor = 0x372efcd0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blur = (flags & 2) != 0; + motion = (flags & 4) != 0; + if ((flags & 1) != 0) { + background_color = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + second_background_color = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + third_background_color = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + fourth_background_color = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + intensity = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + rotation = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + emoticon = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blur ? (flags | 2) : (flags &~ 2); + flags = motion ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(background_color); + } + if ((flags & 16) != 0) { + stream.writeInt32(second_background_color); + } + if ((flags & 32) != 0) { + stream.writeInt32(third_background_color); + } + if ((flags & 64) != 0) { + stream.writeInt32(fourth_background_color); + } + if ((flags & 8) != 0) { + stream.writeInt32(intensity); + } + if ((flags & 16) != 0) { + stream.writeInt32(rotation); + } + if ((flags & 128) != 0) { + stream.writeString(emoticon); + } + } + } + + public static class TL_wallPaperSettings_layer167 extends TL_wallPaperSettings { public static final int constructor = 0x1dc1bca4; @@ -44476,6 +44862,18 @@ public class TLRPC { case 0x445fc434: result = new TL_channelAdminLogEventActionChangeBackgroundEmoji(); break; + case TL_channelAdminLogEventActionChangePeerColor.constructor: + result = new TL_channelAdminLogEventActionChangePeerColor(); + break; + case TL_channelAdminLogEventActionChangeProfilePeerColor.constructor: + result = new TL_channelAdminLogEventActionChangeProfilePeerColor(); + break; + case TL_channelAdminLogEventActionChangeWallpaper.constructor: + result = new TL_channelAdminLogEventActionChangeWallpaper(); + break; + case TL_channelAdminLogEventActionChangeEmojiStatus.constructor: + result = new TL_channelAdminLogEventActionChangeEmojiStatus(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in ChannelAdminLogEventAction", constructor)); @@ -45087,6 +45485,24 @@ public class TLRPC { } } + public static class TL_channelAdminLogEventActionChangeEmojiStatus extends ChannelAdminLogEventAction { + public static final int constructor = 0x3ea9feb1; + + public EmojiStatus prev_value; + public EmojiStatus new_value; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_value = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + new_value = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + prev_value.serializeToStream(stream); + new_value.serializeToStream(stream); + } + } + public static class TL_channelAdminLogEventActionPinTopic extends ChannelAdminLogEventAction { public static final int constructor = 0x5d8d353b; @@ -45228,10 +45644,10 @@ public class TLRPC { public static class TL_channelAdminLogEventActionChangeColor extends ChannelAdminLogEventAction { public static final int constructor = 0x3c2b247b; - + public int prev_value; public int new_value; - + public void readParams(AbstractSerializedData stream, boolean exception) { prev_value = stream.readInt32(exception); new_value = stream.readInt32(exception); @@ -45262,6 +45678,60 @@ public class TLRPC { } } + public static class TL_channelAdminLogEventActionChangePeerColor extends ChannelAdminLogEventAction { + public static final int constructor = 0x5796e780; + + public TL_peerColor prev_value; + public TL_peerColor new_value; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_value = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + new_value = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + prev_value.serializeToStream(stream); + new_value.serializeToStream(stream); + } + } + + public static class TL_channelAdminLogEventActionChangeProfilePeerColor extends ChannelAdminLogEventAction { + public static final int constructor = 0x5e477b25; + + public TL_peerColor prev_value; + public TL_peerColor new_value; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_value = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + new_value = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + prev_value.serializeToStream(stream); + new_value.serializeToStream(stream); + } + } + + public static class TL_channelAdminLogEventActionChangeWallpaper extends ChannelAdminLogEventAction { + public static final int constructor = 0x31bb5d52; + + public WallPaper prev_value; + public WallPaper new_value; + + public void readParams(AbstractSerializedData stream, boolean exception) { + prev_value = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + new_value = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + prev_value.serializeToStream(stream); + new_value.serializeToStream(stream); + } + } + public static class TL_channelAdminLogEventActionToggleAntiSpam extends ChannelAdminLogEventAction { public static final int constructor = 0x64f36dfc; @@ -45715,6 +46185,9 @@ public class TLRPC { public boolean stories_unavailable; public int stories_max_id; public TL_peerColor color; + public TL_peerColor profile_color; + public EmojiStatus emoji_status; + public int level; public ArrayList usernames = new ArrayList<>(); @@ -45740,6 +46213,15 @@ public class TLRPC { case TL_channel.constructor: result = new TL_channel(); break; + case TL_channel_layer167_3.constructor: + result = new TL_channel_layer167_3(); + break; + case TL_channel_layer167_2.constructor: + result = new TL_channel_layer167_2(); + break; + case TL_channel_layer167.constructor: + result = new TL_channel_layer167(); + break; case TL_channel_layer166.constructor: result = new TL_channel_layer166(); break; @@ -46183,7 +46665,544 @@ public class TLRPC { } } + public static class TL_channel_layer167_2 extends TL_channel { + public static final int constructor = 0xa636a3e2; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + left = (flags & 4) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + scam = (flags & 524288) != 0; + has_link = (flags & 1048576) != 0; + has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; + call_active = (flags & 8388608) != 0; + call_not_empty = (flags & 16777216) != 0; + fake = (flags & 33554432) != 0; + gigagroup = (flags & 67108864) != 0; + noforwards = (flags & 134217728) != 0; + join_to_send = (flags & 268435456) != 0; + join_request = (flags & 536870912) != 0; + forum = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; + stories_unavailable = (flags2 & 8) != 0; + id = stream.readInt64(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + if ((flags & 512) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 256) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = left ? (flags | 4) : (flags &~ 4); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + flags = scam ? (flags | 524288) : (flags &~ 524288); + flags = has_link ? (flags | 1048576) : (flags &~ 1048576); + flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); + flags = call_active ? (flags | 8388608) : (flags &~ 8388608); + flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); + flags = fake ? (flags | 33554432) : (flags &~ 33554432); + flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); + flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); + flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); + flags = join_request ? (flags | 536870912) : (flags &~ 536870912); + flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); + stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); + } + if ((flags2 & 256) != 0) { + profile_color.serializeToStream(stream); + } + } + } + + public static class TL_channel_layer167_3 extends TL_channel { + public static final int constructor = 0xdb12acb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + left = (flags & 4) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + scam = (flags & 524288) != 0; + has_link = (flags & 1048576) != 0; + has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; + call_active = (flags & 8388608) != 0; + call_not_empty = (flags & 16777216) != 0; + fake = (flags & 33554432) != 0; + gigagroup = (flags & 67108864) != 0; + noforwards = (flags & 134217728) != 0; + join_to_send = (flags & 268435456) != 0; + join_request = (flags & 536870912) != 0; + forum = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; + stories_unavailable = (flags2 & 8) != 0; + id = stream.readInt64(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + if ((flags & 512) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 256) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 512) != 0) { + emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = left ? (flags | 4) : (flags &~ 4); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + flags = scam ? (flags | 524288) : (flags &~ 524288); + flags = has_link ? (flags | 1048576) : (flags &~ 1048576); + flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); + flags = call_active ? (flags | 8388608) : (flags &~ 8388608); + flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); + flags = fake ? (flags | 33554432) : (flags &~ 33554432); + flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); + flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); + flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); + flags = join_request ? (flags | 536870912) : (flags &~ 536870912); + flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); + stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); + } + if ((flags2 & 256) != 0) { + profile_color.serializeToStream(stream); + } + if ((flags2 & 512) != 0) { + emoji_status.serializeToStream(stream); + } + } + } + public static class TL_channel extends Chat { + public static final int constructor = 0xaadfc8f; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + left = (flags & 4) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + scam = (flags & 524288) != 0; + has_link = (flags & 1048576) != 0; + has_geo = (flags & 2097152) != 0; + slowmode_enabled = (flags & 4194304) != 0; + call_active = (flags & 8388608) != 0; + call_not_empty = (flags & 16777216) != 0; + fake = (flags & 33554432) != 0; + gigagroup = (flags & 67108864) != 0; + noforwards = (flags & 134217728) != 0; + join_to_send = (flags & 268435456) != 0; + join_request = (flags & 536870912) != 0; + forum = (flags & 1073741824) != 0; + flags2 = stream.readInt32(exception); + stories_hidden = (flags2 & 2) != 0; + stories_hidden_min = (flags2 & 4) != 0; + stories_unavailable = (flags2 & 8) != 0; + id = stream.readInt64(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + if ((flags & 512) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 256) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 512) != 0) { + emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags2 & 1024) != 0) { + level = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = left ? (flags | 4) : (flags &~ 4); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + flags = scam ? (flags | 524288) : (flags &~ 524288); + flags = has_link ? (flags | 1048576) : (flags &~ 1048576); + flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); + flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); + flags = call_active ? (flags | 8388608) : (flags &~ 8388608); + flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); + flags = fake ? (flags | 33554432) : (flags &~ 33554432); + flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); + flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); + flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); + flags = join_request ? (flags | 536870912) : (flags &~ 536870912); + flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); + stream.writeInt32(flags); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); + stream.writeInt32(flags2); + stream.writeInt64(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); + } + if ((flags2 & 256) != 0) { + profile_color.serializeToStream(stream); + } + if ((flags2 & 512) != 0) { + emoji_status.serializeToStream(stream); + } + if ((flags2 & 1024) != 0) { + stream.writeInt32(level); + } + } + } + + public static class TL_channel_layer167 extends TL_channel { public static final int constructor = 0x8e87ccd8; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -46519,10 +47538,10 @@ public class TLRPC { stream.writeInt32(stories_max_id); } if ((flags2 & 64) != 0) { - stream.writeInt32(color.color); + stream.writeInt32(color == null ? (int) (id % 7) : color.color); } if ((flags2 & 32) != 0) { - stream.writeInt64(color.background_emoji_id); + stream.writeInt64(color == null ? 0 : color.background_emoji_id); } } } @@ -46615,11 +47634,11 @@ public class TLRPC { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } - color = new TL_peerColor(); - color.color = stream.readInt32(exception); - if ((flags2 & 32) != 0) { - color.background_emoji_id = stream.readInt64(exception); - } +// color = new TL_peerColor(); +// color.color = stream.readInt32(exception); +// if ((flags2 & 32) != 0) { +// color.background_emoji_id = stream.readInt64(exception); +// } } public void serializeToStream(AbstractSerializedData stream) { @@ -46690,10 +47709,10 @@ public class TLRPC { if ((flags2 & 16) != 0) { stream.writeInt32(stories_max_id); } - stream.writeInt32(color == null ? (int) (id % 7) : color.color); - if ((flags2 & 32) != 0) { - stream.writeInt64(color == null ? 0 : color.background_emoji_id); - } +// stream.writeInt32(color == null ? (int) (id % 7) : color.color); +// if ((flags2 & 32) != 0) { +// stream.writeInt64(color == null ? 0 : color.background_emoji_id); +// } } } @@ -47685,6 +48704,7 @@ public class TLRPC { public boolean videos; public boolean emojis; public boolean text_color; + public boolean channel_emoji_status; public long id; public long access_hash; public String title; @@ -47768,6 +48788,7 @@ public class TLRPC { videos = (flags & 64) != 0; emojis = (flags & 128) != 0; text_color = (flags & 512) != 0; + channel_emoji_status = (flags & 1024) != 0; if ((flags & 1) != 0) { installed_date = stream.readInt32(exception); } @@ -47814,6 +48835,7 @@ public class TLRPC { flags = videos ? (flags | 64) : (flags &~ 64); flags = emojis ? (flags | 128) : (flags &~ 128); flags = text_color ? (flags | 512) : (flags &~ 512); + flags = channel_emoji_status ? (flags | 1024) : (flags &~ 1024); stream.writeInt32(flags); if ((flags & 1) != 0) { stream.writeInt32(installed_date); @@ -48912,6 +49934,7 @@ public class TLRPC { public int flags; public boolean imported; + public boolean saved_out; public Peer from_id; public String from_name; public int date; @@ -48919,6 +49942,9 @@ public class TLRPC { public String post_author; public Peer saved_from_peer; public int saved_from_msg_id; + public Peer saved_from_id; + public String saved_from_name; + public int saved_date; public String psa_type; public static MessageFwdHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -48936,9 +49962,12 @@ public class TLRPC { case 0xfadff4ac: result = new TL_messageFwdHeader_layer72(); break; - case 0x5f777dce: + case TL_messageFwdHeader.constructor: result = new TL_messageFwdHeader(); break; + case TL_messageFwdHeader_layer169.constructor: + result = new TL_messageFwdHeader_layer169(); + break; case 0x559ebe6d: result = new TL_messageFwdHeader_layer96(); break; @@ -48990,6 +50019,85 @@ public class TLRPC { } public static class TL_messageFwdHeader extends MessageFwdHeader { + public static final int constructor = 0x4e4df4bb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + imported = (flags & 128) != 0; + saved_out = (flags & 2048) != 0; + if ((flags & 1) != 0) { + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + from_name = stream.readString(exception); + } + date = stream.readInt32(exception); + if ((flags & 4) != 0) { + channel_post = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + post_author = stream.readString(exception); + } + if ((flags & 16) != 0) { + saved_from_peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16) != 0) { + saved_from_msg_id = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + saved_from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 512) != 0) { + saved_from_name = stream.readString(exception); + } + if ((flags & 1024) != 0) { + saved_date = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + psa_type = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = imported ? (flags | 128) : (flags &~ 128); + flags = saved_out ? (flags | 2048) : (flags &~ 2048); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + from_id.serializeToStream(stream); + } + if ((flags & 32) != 0) { + stream.writeString(from_name); + } + stream.writeInt32(date); + if ((flags & 4) != 0) { + stream.writeInt32(channel_post); + } + if ((flags & 8) != 0) { + stream.writeString(post_author); + } + if ((flags & 16) != 0) { + saved_from_peer.serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt32(saved_from_msg_id); + } + if ((flags & 256) != 0) { + saved_from_id.serializeToStream(stream); + } + if ((flags & 512) != 0) { + stream.writeString(saved_from_name); + } + if ((flags & 1024) != 0) { + stream.writeInt32(saved_date); + } + if ((flags & 64) != 0) { + stream.writeString(psa_type); + } + } + } + + public static class TL_messageFwdHeader_layer169 extends TL_messageFwdHeader { public static final int constructor = 0x5f777dce; @@ -50193,7 +51301,7 @@ public class TLRPC { } public static abstract class ReactionCount extends TLObject { - + public int flags; public int chosen_order; public boolean chosen; //custom @@ -55479,12 +56587,13 @@ public class TLRPC { } public static class TL_messages_search extends TLObject { - public static final int constructor = 0xa0fda762; + public static final int constructor = 0xa7b4e929; public int flags; public InputPeer peer; public String q; public InputPeer from_id; + public InputPeer saved_peer_id; public int top_msg_id; public MessagesFilter filter; public int min_date; @@ -55508,6 +56617,9 @@ public class TLRPC { if ((flags & 1) != 0) { from_id.serializeToStream(stream); } + if ((flags & 4) != 0) { + saved_peer_id.serializeToStream(stream); + } if ((flags & 2) != 0) { stream.writeInt32(top_msg_id); } @@ -55741,6 +56853,33 @@ public class TLRPC { } } + public static class TL_messages_deleteSavedHistory extends TLObject { + public static final int constructor = 0x6e98102b; + + public int flags; + public InputPeer peer; + public int max_id; + public int min_date; + public int max_date; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedHistory.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(max_id); + if ((flags & 4) != 0) { + stream.writeInt32(min_date); + } + if ((flags & 8) != 0) { + stream.writeInt32(max_date); + } + } + } + public static class TL_channels_togglePreHistoryHidden extends TLObject { public static final int constructor = 0xeabbb94c; @@ -56368,9 +57507,11 @@ public class TLRPC { } public static class TL_messages_getSearchResultsCalendar extends TLObject { - public static final int constructor = 0x49f0bde9; + public static final int constructor = 0x6aa3f6bd; + public int flags; public InputPeer peer; + public InputPeer saved_peer_id; public MessagesFilter filter; public int offset_id; public int offset_date; @@ -56381,8 +57522,12 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); peer.serializeToStream(stream); filter.serializeToStream(stream); + if ((flags & 4) != 0) { + saved_peer_id.serializeToStream(stream); + } stream.writeInt32(offset_id); stream.writeInt32(offset_date); } @@ -57825,6 +58970,21 @@ public class TLRPC { } } + public static class TL_account_getChannelDefaultEmojiStatuses extends TLObject { + public static final int constructor = 0x7727a7d5; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_EmojiStatuses.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + public static class TL_account_getDefaultEmojiStatuses extends TLObject { public static final int constructor = 0xd6753386; @@ -59342,10 +60502,11 @@ public class TLRPC { } public static class TL_messages_getSearchCounters extends TLObject { - public static final int constructor = 0xae7cc1; + public static final int constructor = 0x1bbcf300; public int flags; public InputPeer peer; + public InputPeer saved_peer_id; public int top_msg_id; public ArrayList filters = new ArrayList<>(); @@ -59366,6 +60527,9 @@ public class TLRPC { stream.writeInt32(constructor); stream.writeInt32(flags); peer.serializeToStream(stream); + if ((flags & 2) != 0) { + saved_peer_id.serializeToStream(stream); + } if ((flags & 1) != 0) { stream.writeInt32(top_msg_id); } @@ -62492,16 +63656,16 @@ public class TLRPC { public static InputStorePaymentPurpose TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { InputStorePaymentPurpose result = null; switch (constructor) { - case 0x616f7fe8: + case TL_inputStorePaymentGiftPremium.constructor: result = new TL_inputStorePaymentGiftPremium(); break; - case 0xa3805f3f: + case TL_inputStorePaymentPremiumGiftCode.constructor: result = new TL_inputStorePaymentPremiumGiftCode(); break; - case 0xa6751e66: + case TL_inputStorePaymentPremiumSubscription.constructor: result = new TL_inputStorePaymentPremiumSubscription(); break; - case 0x7c9375e6: + case TL_inputStorePaymentPremiumGiveaway.constructor: result = new TL_inputStorePaymentPremiumGiveaway(); break; } @@ -62803,26 +63967,22 @@ public class TLRPC { } public static class TL_stats_getMessagePublicForwards extends TLObject { - public static final int constructor = 0x5630281b; + public static final int constructor = 0x5f150144; public InputChannel channel; public int msg_id; - public int offset_rate; - public InputPeer offset_peer; - public int offset_id; + public String offset; public int limit; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return messages_Messages.TLdeserialize(stream, constructor, exception); + return TL_stats_publicForwards.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); channel.serializeToStream(stream); stream.writeInt32(msg_id); - stream.writeInt32(offset_rate); - offset_peer.serializeToStream(stream); - stream.writeInt32(offset_id); + stream.writeString(offset); stream.writeInt32(limit); } } @@ -63309,6 +64469,9 @@ public class TLRPC { public boolean force_small_media; public boolean manual; public boolean safe; + public boolean video; + public boolean round; + public boolean voice; public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { MessageMedia result = null; @@ -63382,9 +64545,15 @@ public class TLRPC { case 0x4bd6e798: result = new TL_messageMediaPoll(); break; - case 0x58260664: + case TL_messageMediaGiveawayResults.constructor: + result = new TL_messageMediaGiveawayResults(); + break; + case TL_messageMediaGiveaway.constructor: result = new TL_messageMediaGiveaway(); break; + case TL_messageMediaGiveaway_layer167.constructor: + result = new TL_messageMediaGiveaway_layer167(); + break; case 0xb5223b0f: result = new TL_messageMediaPhoto_layer74(); break; @@ -63496,6 +64665,14 @@ public class TLRPC { } return result; } + + public Boolean documentExists; + public Document getDocument() { + if (alt_document != null && ApplicationLoader.useLessData()) { + return alt_document; + } + return document; + } } //MessageMedia end @@ -63831,6 +65008,7 @@ public class TLRPC { public int id; public Peer from_id; public Peer peer_id; + public Peer saved_peer_id; public int date; public int expire_date; public MessageAction action; @@ -63979,9 +65157,12 @@ public class TLRPC { case 0x85d6cbe2: result = new TL_message_layer135(); break; - case 0x38116ee0: + case TL_message.constructor: result = new TL_message(); break; + case TL_message_layer169.constructor: + result = new TL_message_layer169(); + break; case 0x9e19a1f6: result = new TL_messageService_layer118(); break; @@ -64682,6 +65863,196 @@ public class TLRPC { } public static class TL_message extends Message { + public static final int constructor = 0x76bec211; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + from_scheduled = (flags & 262144) != 0; + legacy = (flags & 524288) != 0; + edit_hide = (flags & 2097152) != 0; + pinned = (flags & 16777216) != 0; + noforwards = (flags & 67108864) != 0; + invert_media = (flags & 134217728) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 268435456) != 0) { + saved_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + fwd_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt64(exception); + } + if ((flags & 8) != 0) { + reply_to = MessageReplyHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (media != null) { + ttl = media.ttl_seconds; + } + if (media != null && !TextUtils.isEmpty(media.captionLegacy)) { + message = media.captionLegacy; + } + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if ((flags & 1024) != 0) { + forwards = stream.readInt32(exception); + } + if ((flags & 8388608) != 0) { + replies = MessageReplies.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + edit_date = stream.readInt32(exception); + } + if ((flags & 65536) != 0) { + post_author = stream.readString(exception); + } + if ((flags & 131072) != 0) { + grouped_id = stream.readInt64(exception); + } + if ((flags & 1048576) != 0) { + reactions = MessageReactions.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4194304) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 33554432) != 0) { + ttl_period = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + flags = from_scheduled ? (flags | 262144) : (flags &~ 262144); + flags = legacy ? (flags | 524288) : (flags &~ 524288); + flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); + flags = pinned ? (flags | 16777216) : (flags &~ 16777216); + flags = noforwards ? (flags | 67108864) : (flags &~ 67108864); + flags = invert_media ? (flags | 134217728) : (flags &~ 134217728); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + from_id.serializeToStream(stream); + } + peer_id.serializeToStream(stream); + if ((flags & 268435456) != 0) { + saved_peer_id.serializeToStream(stream); + } + if ((flags & 4) != 0) { + fwd_from.serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeInt64(via_bot_id); + } + if ((flags & 8) != 0) { + reply_to.serializeToStream(stream); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + if ((flags & 1024) != 0) { + stream.writeInt32(forwards); + } + if ((flags & 8388608) != 0) { + replies.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + stream.writeInt32(edit_date); + } + if ((flags & 65536) != 0) { + stream.writeString(post_author); + } + if ((flags & 131072) != 0) { + stream.writeInt64(grouped_id); + } + if ((flags & 1048576) != 0) { + reactions.serializeToStream(stream); + } + if ((flags & 4194304) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 33554432) != 0) { + stream.writeInt32(ttl_period); + } + writeAttachPath(stream); + } + } + + public static class TL_message_layer169 extends TL_message { public static final int constructor = 0x38116ee0; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -67006,7 +68377,7 @@ public class TLRPC { public int pinnedNum; //custom public boolean isFolder; //custom - public static Dialog TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + public static Dialog TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Dialog result = null; switch (constructor) { case 0xd58a08c6: @@ -67850,9 +69221,11 @@ public class TLRPC { } public static class TL_messages_getSearchResultsPositions extends TLObject { - public static final int constructor = 0x6e9583a3; + public static final int constructor = 0x9c7f2f10; + public int flags; public InputPeer peer; + public InputPeer saved_peer_id; public MessagesFilter filter; public int offset_id; public int limit; @@ -67863,7 +69236,11 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); peer.serializeToStream(stream); + if ((flags & 4) != 0) { + saved_peer_id.serializeToStream(stream); + } filter.serializeToStream(stream); stream.writeInt32(offset_id); stream.writeInt32(limit); @@ -68405,11 +69782,9 @@ public class TLRPC { } } - public static class TL_keyboardButtonRequestPeer extends KeyboardButton { + public static class TL_keyboardButtonRequestPeer_layer168 extends TL_keyboardButtonRequestPeer { public static final int constructor = 0xd0b468c; - public RequestPeerType peer_type; - public void readParams(AbstractSerializedData stream, boolean exception) { text = stream.readString(exception); button_id = stream.readInt32(exception); @@ -68424,6 +69799,28 @@ public class TLRPC { } } + public static class TL_keyboardButtonRequestPeer extends KeyboardButton { + public static final int constructor = 0x53d7bfd8; + + public RequestPeerType peer_type; + public int max_quantity; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + button_id = stream.readInt32(exception); + peer_type = RequestPeerType.TLdeserialize(stream, stream.readInt32(exception), exception); + max_quantity = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(button_id); + peer_type.serializeToStream(stream); + stream.writeInt32(max_quantity); + } + } + public static class TL_messages_getAttachMenuBots extends TLObject { public static final int constructor = 0x16fcc2cb; @@ -70781,10 +72178,10 @@ public class TLRPC { stream.writeBool(enabled); } } - + public static class TL_channels_clickSponsoredMessage extends TLObject { public static final int constructor = 0x18afbc93; - + public InputChannel channel; public byte[] random_id; @@ -70856,12 +72253,12 @@ public class TLRPC { } public static class TL_messages_sendBotRequestedPeer extends TLObject { - public static final int constructor = 0xfe38d01b; + public static final int constructor = 0x91b2d060; public InputPeer peer; public int msg_id; public int button_id; - public InputPeer requested_peer; + public ArrayList requested_peers = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -70872,7 +72269,12 @@ public class TLRPC { peer.serializeToStream(stream); stream.writeInt32(msg_id); stream.writeInt32(button_id); - requested_peer.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = requested_peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + requested_peers.get(a).serializeToStream(stream); + } } } @@ -70929,15 +72331,18 @@ public class TLRPC { } } - public static class TL_messageActionRequestedPeer extends MessageAction { + public static class TL_messageActionRequestedPeer_layer168 extends TL_messageActionRequestedPeer { public static final int constructor = 0xfe77345d; - public int button_id; public TLRPC.Peer peer; public void readParams(AbstractSerializedData stream, boolean exception) { button_id = stream.readInt32(exception); peer = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (peer == null) { + return; + } + peers.add(peer); } public void serializeToStream(AbstractSerializedData stream) { @@ -70947,6 +72352,43 @@ public class TLRPC { } } + public static class TL_messageActionRequestedPeer extends MessageAction { + public static final int constructor = 0x31518e9b; + + public int button_id; + public ArrayList peers = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + button_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Peer object = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + peers.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(button_id); + stream.writeInt32(0x1cb5c415); + int count = peers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + peers.get(a).serializeToStream(stream); + } + } + } + public static class TL_photos_uploadContactProfilePhoto extends TLObject { public static final int constructor = 0xe14c4a71; @@ -71078,10 +72520,26 @@ public class TLRPC { } } + public static class TL_account_getChannelRestrictedStatusEmojis extends TLObject { + public static final int constructor = 0x35a9e0d5; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + public static class TL_channels_updateColor extends TLObject { - public static final int constructor = 0x621a201f; + public static final int constructor = 0xd8aa3671; public int flags; + public boolean for_profile; public InputChannel channel; public int color; public long background_emoji_id; @@ -71092,9 +72550,12 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_profile ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); channel.serializeToStream(stream); - stream.writeInt32(color); + if ((flags & 4) != 0) { + stream.writeInt32(color); + } if ((flags & 1) != 0) { stream.writeInt64(background_emoji_id); } @@ -71143,7 +72604,7 @@ public class TLRPC { public static class TL_updateChannelViewForumAsMessages extends Update { public static final int constructor = 0x7b68920; - + public long channel_id; public boolean enabled; @@ -71159,6 +72620,64 @@ public class TLRPC { } } + public static class TL_updatePinnedSavedDialogs extends Update { + public static final int constructor = 0x686c85a6; + + public int flags; + public ArrayList order = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + order.add(DialogPeer.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + order.get(i).serializeToStream(stream); + } + } + } + } + + public static class TL_updateSavedDialogPinned extends Update { + public static final int constructor = 0xaeaf9e74; + + public int flags; + public boolean pinned; + public DialogPeer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 1) != 0; + peer = DialogPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + } + } + public static class TL_updatePeerWallpaper extends Update { public static final int constructor = 0xae3f101d; @@ -71222,12 +72741,12 @@ public class TLRPC { public static class TL_contacts_setBlocked extends TLObject { public static final int constructor = 0x94c65c76; - + public int flags; public boolean my_stories_from; public ArrayList id = new ArrayList<>(); public int limit; - + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Bool.TLdeserialize(stream, constructor, exception); } @@ -71249,7 +72768,7 @@ public class TLRPC { public static final int constructor = 0xba6705f0; public ArrayList id = new ArrayList<>(); - + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Bool.TLdeserialize(stream, constructor, exception); } @@ -71637,14 +73156,64 @@ public class TLRPC { } public static class TL_messageActionGiftCode extends MessageAction { - public static int constructor = 0xd2cfdb0e; + public static final int constructor = 0x678c2e09; public boolean via_giveaway; public boolean unclaimed; public Peer boost_peer; - public int months; public String slug; + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + via_giveaway = (flags & 1) != 0; + unclaimed = (flags & 4) != 0; + if ((flags & 2) != 0) { + boost_peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + months = stream.readInt32(exception); + slug = stream.readString(exception); + if ((flags & 4) != 0) { + currency = stream.readString(exception); + } + if ((flags & 4) != 0) { + amount = stream.readInt64(exception); + } + if ((flags & 8) != 0) { + cryptoCurrency = stream.readString(exception); + } + if ((flags & 8) != 0) { + cryptoAmount = stream.readInt64(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = via_giveaway ? (flags | 1) : (flags &~ 1); + flags = unclaimed ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 2) != 0) { + boost_peer.serializeToStream(stream); + } + stream.writeInt32(months); + stream.writeString(slug); + if ((flags & 4) != 0) { + stream.writeString(currency); + } + if ((flags & 4) != 0) { + stream.writeInt64(amount); + } + if ((flags & 8) != 0) { + stream.writeString(cryptoCurrency); + } + if ((flags & 8) != 0) { + stream.writeInt64(cryptoAmount); + } + } + } + + public static class TL_messageActionGiftCode_layer167 extends TL_messageActionGiftCode { + public static final int constructor = 0xd2cfdb0e; + public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); via_giveaway = (flags & 1) != 0; @@ -71670,7 +73239,7 @@ public class TLRPC { } public static class TL_inputStorePaymentPremiumGiftCode extends InputStorePaymentPurpose { - public static int constructor = 0xa3805f3f; + public static final int constructor = 0xa3805f3f; public int flags; public ArrayList users = new ArrayList<>(); @@ -71720,13 +73289,15 @@ public class TLRPC { } public static class TL_inputStorePaymentPremiumGiveaway extends InputStorePaymentPurpose { - public static int constructor = 0x7c9375e6; + public static final int constructor = 0x160544ca; public int flags; public boolean only_new_subscribers; + public boolean winners_are_visible; public InputPeer boost_peer; public ArrayList additional_peers = new ArrayList<>(); public ArrayList countries_iso2 = new ArrayList<>(); + public String prize_description; public long random_id; public int until_date; public String currency; @@ -71735,6 +73306,7 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); only_new_subscribers = (flags & 1) != 0; + winners_are_visible = (flags & 8) != 0; boost_peer = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 2) != 0) { int magic = stream.readInt32(exception); @@ -71766,6 +73338,9 @@ public class TLRPC { countries_iso2.add(stream.readString(exception)); } } + if ((flags & 16) != 0) { + prize_description = stream.readString(exception); + } random_id = stream.readInt64(exception); until_date = stream.readInt32(exception); currency = stream.readString(exception); @@ -71775,6 +73350,7 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = only_new_subscribers ? (flags | 1) : (flags &~ 1); + flags = winners_are_visible ? (flags | 8) : (flags &~ 8); stream.writeInt32(flags); boost_peer.serializeToStream(stream); if ((flags & 2) != 0) { @@ -71793,6 +73369,9 @@ public class TLRPC { stream.writeString(countries_iso2.get(a)); } } + if ((flags & 16) != 0) { + stream.writeString(prize_description); + } stream.writeInt64(random_id); stream.writeInt32(until_date); stream.writeString(currency); @@ -71818,16 +73397,155 @@ public class TLRPC { } } - public static class TL_messageMediaGiveaway extends MessageMedia { - public static int constructor = 0x58260664; + public static class TL_messageMediaGiveawayResults extends MessageMedia { + public static final int constructor = 0xc6991068; public boolean only_new_subscribers; + public boolean refunded; + public long channel_id; + public int additional_peers_count; + public int launch_msg_id; + public int winners_count; + public int unclaimed_count; + public ArrayList winners = new ArrayList<>(); + public int months; + public String prize_description; + public int until_date; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + only_new_subscribers = (flags & 1) != 0; + refunded = (flags & 4) != 0; + channel_id = stream.readInt64(exception); + if ((flags & 8) != 0) { + additional_peers_count = stream.readInt32(exception); + } + launch_msg_id = stream.readInt32(exception); + winners_count = stream.readInt32(exception); + unclaimed_count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + winners.add(stream.readInt64(exception)); + } + months = stream.readInt32(exception); + if ((flags & 2) != 0) { + prize_description = stream.readString(exception); + } + until_date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = only_new_subscribers ? (flags | 1) : (flags &~ 1); + flags = refunded ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + stream.writeInt64(channel_id); + if ((flags & 8) != 0) { + stream.writeInt32(additional_peers_count); + } + stream.writeInt32(launch_msg_id); + stream.writeInt32(winners_count); + stream.writeInt32(unclaimed_count); + stream.writeInt32(0x1cb5c415); + int count = winners.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(winners.get(a)); + } + stream.writeInt32(months); + if ((flags & 2) != 0) { + stream.writeString(prize_description); + } + stream.writeInt32(until_date); + } + } + + public static class TL_messageMediaGiveaway extends MessageMedia { + public static final int constructor = 0xdaad85b0; + + public boolean only_new_subscribers; + public boolean winners_are_visible; public ArrayList channels = new ArrayList<>(); public ArrayList countries_iso2 = new ArrayList<>(); + public String prize_description; public int quantity; public int months; public int until_date; + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + only_new_subscribers = (flags & 1) != 0; + winners_are_visible = (flags & 4) != 0; + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + channels.add(stream.readInt64(exception)); + } + if ((flags & 2) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + countries_iso2.add(stream.readString(exception)); + } + } + if ((flags & 8) != 0) { + prize_description = stream.readString(exception); + } + quantity = stream.readInt32(exception); + months = stream.readInt32(exception); + until_date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = only_new_subscribers ? (flags | 1) : (flags &~ 1); + flags = winners_are_visible ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + int count = channels.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(channels.get(a)); + } + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + count = countries_iso2.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(countries_iso2.get(a)); + } + } + if ((flags & 8) != 0) { + stream.writeString(prize_description); + } + stream.writeInt32(quantity); + stream.writeInt32(months); + stream.writeInt32(until_date); + } + } + + public static class TL_messageMediaGiveaway_layer167 extends TL_messageMediaGiveaway { + public static final int constructor = 0x58260664; + public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); only_new_subscribers = (flags & 1) != 0; @@ -71997,7 +73715,7 @@ public class TLRPC { } public static class TL_payments_giveawayInfoResults extends payments_GiveawayInfo { - public static int constructor = 0xcd5570; + public static final int constructor = 0xcd5570; public int flags; public boolean winner; @@ -72037,7 +73755,7 @@ public class TLRPC { } public static class TL_payments_giveawayInfo extends payments_GiveawayInfo { - public static int constructor = 0x4367daa0; + public static final int constructor = 0x4367daa0; public int flags; public boolean participating; @@ -72086,10 +73804,10 @@ public class TLRPC { public static payments_GiveawayInfo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { payments_GiveawayInfo result = null; switch (constructor) { - case 0xcd5570: + case TL_payments_giveawayInfoResults.constructor: result = new TL_payments_giveawayInfoResults(); break; - case 0x4367daa0: + case TL_payments_giveawayInfo.constructor: result = new TL_payments_giveawayInfo(); break; } @@ -72121,7 +73839,7 @@ public class TLRPC { } public static class TL_payments_checkedGiftCode extends TLObject { - public static int constructor = 0xb722f158; + public static final int constructor = 0x284a1096; public static final long NO_USER_ID = -1L; //custom public int flags; @@ -72152,7 +73870,9 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); via_giveaway = (flags & 4) != 0; - from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 16) != 0) { + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } if ((flags & 8) != 0) { giveaway_msg_id = stream.readInt32(exception); } @@ -72198,9 +73918,11 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = via_giveaway ? (flags | 4) : (flags &~ 4); + flags = via_giveaway ? (flags | 4) : (flags & ~4); stream.writeInt32(flags); - from_id.serializeToStream(stream); + if ((flags & 16) != 0) { + from_id.serializeToStream(stream); + } if ((flags & 8) != 0) { stream.writeInt32(giveaway_msg_id); } @@ -72256,7 +73978,7 @@ public class TLRPC { public static class TL_messageActionGiveawayResults extends MessageAction { public static int constructor = 0x2a9fadc5; - + public int winners_count; public int unclaimed_count; @@ -72273,6 +73995,25 @@ public class TLRPC { } } + public static class TL_channels_updateEmojiStatus extends TLObject { + public static int constructor = 0xf0d3e6a8; + + public InputChannel channel; + public EmojiStatus emoji_status; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + emoji_status.serializeToStream(stream); + } + } + public static class TL_channels_getChannelRecommendations extends TLObject { public static int constructor = 0x83b70d97; @@ -72282,7 +74023,7 @@ public class TLRPC { public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return messages_Chats.TLdeserialize(stream, constructor, exception); } - + public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); channel.serializeToStream(stream); @@ -72348,7 +74089,7 @@ public class TLRPC { } } } - + public static class help_PeerColorSet extends TLObject { public static help_PeerColorSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { help_PeerColorSet result = null; @@ -72473,13 +74214,14 @@ public class TLRPC { } public static class TL_help_peerColorOption extends TLObject { - public static final int constructor = 0x135bd42f; - + public static final int constructor = 0xef8430ab; + public int flags; public boolean hidden; public int color_id; public help_PeerColorSet colors; public help_PeerColorSet dark_colors; + public int channel_min_level; public static TL_help_peerColorOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_help_peerColorOption.constructor != constructor) { @@ -72505,6 +74247,9 @@ public class TLRPC { if ((flags & 4) != 0) { dark_colors = help_PeerColorSet.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 8) != 0) { + channel_min_level = stream.readInt32(exception); + } } @Override @@ -72519,6 +74264,9 @@ public class TLRPC { if ((flags & 4) != 0) { dark_colors.serializeToStream(stream); } + if ((flags & 8) != 0) { + stream.writeInt32(channel_min_level); + } } } @@ -72542,7 +74290,7 @@ public class TLRPC { return result; } } - + public static class TL_help_peerColorsNotModified extends help_PeerColors { public static final int constructor = 0x2ba1f5ce; @@ -72594,7 +74342,7 @@ public class TLRPC { public static class TL_help_getPeerColors extends TLObject { public static final int constructor = 0xda80f42f; - + public int hash; @Override @@ -72626,6 +74374,382 @@ public class TLRPC { } } + public static class TL_savedDialog extends TLObject { + public static final int constructor = 0xbd87cb6c; + + public int flags; + public boolean pinned; + public Peer peer; + public int top_message; + + public static TL_savedDialog TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_savedDialog.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_savedDialog", constructor)); + } else { + return null; + } + } + TL_savedDialog result = new TL_savedDialog(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 4) != 0; + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + top_message = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(top_message); + } + } + + public static class messages_SavedDialogs extends TLObject { + public static messages_SavedDialogs TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_SavedDialogs result = null; + switch (constructor) { + case TL_messages_savedDialogs.constructor: + result = new TL_messages_savedDialogs(); + break; + case TL_messages_savedDialogsSlice.constructor: + result = new TL_messages_savedDialogsSlice(); + break; + case TL_messages_savedDialogsNotModified.constructor: + result = new TL_messages_savedDialogsNotModified(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_SavedDialogs", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_savedDialogs extends messages_SavedDialogs { + public static final int constructor = 0xf83ae221; + + public ArrayList dialogs = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + dialogs.add(TL_savedDialog.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + messages.add(Message.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + chats.add(Chat.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(User.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = dialogs.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + dialogs.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + messages.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + users.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + chats.get(i).serializeToStream(stream); + } + } + } + + public static class TL_messages_savedDialogsSlice extends messages_SavedDialogs { + public static final int constructor = 0x44ba9dd9; + + public int count; + public ArrayList dialogs = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + dialogs.add(TL_savedDialog.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + messages.add(Message.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + chats.add(Chat.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + users.add(User.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = dialogs.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + dialogs.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + messages.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + users.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + chats.get(i).serializeToStream(stream); + } + } + } + + public static class TL_messages_savedDialogsNotModified extends messages_SavedDialogs { + public static final int constructor = 0xc01f6fe8; + + public int count; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + } + } + + public static class TL_messages_getPinnedSavedDialogs extends TLObject { + public static final int constructor = 0xd63d94e0; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SavedDialogs.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_getSavedDialogs extends TLObject { + public static final int constructor = 0x5381d21a; + + public int flags; + public boolean exclude_pinned; + public int offset_date; + public int offset_id; + public InputPeer offset_peer; + public int limit; + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SavedDialogs.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = exclude_pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(offset_date); + stream.writeInt32(offset_id); + offset_peer.serializeToStream(stream); + stream.writeInt32(limit); + stream.writeInt64(hash); + } + } + + public static class TL_messages_getSavedHistory extends TLObject { + public static final int constructor = 0x3d9a414d; + + public InputPeer peer; + public int offset_id; + public int offset_date; + public int add_offset; + public int limit; + public int max_id; + public int min_id; + public long hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(offset_date); + stream.writeInt32(add_offset); + stream.writeInt32(limit); + stream.writeInt32(max_id); + stream.writeInt32(min_id); + stream.writeInt64(hash); + } + } + + public static class TL_messages_toggleSavedDialogPin extends TLObject { + public static final int constructor = 0xac81bbde; + + public int flags; + public boolean pinned; + public InputDialogPeer peer; + + @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); + flags = pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + } + } + + public static class TL_messages_reorderPinnedSavedDialogs extends TLObject { + public static final int constructor = 0x8b716587; + + public int flags; + public boolean force; + public ArrayList order = new ArrayList<>(); + + @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); + flags = force ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + order.get(i).serializeToStream(stream); + } + } + } + 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/tgnet/tl/TL_stories.java b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java index f2d7899d2..2aa0bf5de 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java @@ -1,5 +1,6 @@ package org.telegram.tgnet.tl; +import org.telegram.messenger.DialogObject; import org.telegram.tgnet.AbstractSerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -78,8 +79,7 @@ public class TL_stories { } } - public static class TL_storyView extends TLObject { - public static final int constructor = 0xb0bdeac5; + public static class StoryView extends TLObject { public int flags; public boolean blocked; @@ -87,19 +87,35 @@ public class TL_stories { public long user_id; public int date; public TLRPC.Reaction reaction; + public TLRPC.Message message; + public TLRPC.Peer peer_id; + public StoryItem story; - public static TL_storyView TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_storyView.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_storyView", constructor)); - } else { - return null; - } + public static StoryView TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryView result = null; + switch (constructor) { + case TL_storyView.constructor: + result = new TL_storyView(); + break; + case TL_storyViewPublicForward.constructor: + result = new TL_storyViewPublicForward(); + break; + case TL_storyViewPublicRepost.constructor: + result = new TL_storyViewPublicRepost(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryView", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_storyView result = new TL_storyView(); - result.readParams(stream, exception); return result; } + } + + public static class TL_storyView extends StoryView { + public static final int constructor = 0xb0bdeac5; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -125,6 +141,46 @@ public class TL_stories { } } + public static class TL_storyViewPublicForward extends StoryView { + public static final int constructor = 0x9083670b; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + blocked_my_stories_from = (flags & 2) != 0; + message = TLRPC.Message.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = blocked_my_stories_from ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + message.serializeToStream(stream); + } + } + + public static class TL_storyViewPublicRepost extends StoryView { + public static final int constructor = 0xbd74cf49; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + blocked_my_stories_from = (flags & 2) != 0; + peer_id = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = blocked_my_stories_from ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + peer_id.serializeToStream(stream); + story.serializeToStream(stream); + } + } + public static abstract class PeerStories extends TLObject { public int flags; @@ -862,28 +918,131 @@ public class TL_stories { } } - public static class TL_stories_storyViewsList extends TLObject { - public static final int constructor = 0x46e9b9ec; + public static class StoryViewsList extends TLObject { public int flags; public int count; + public int views_count; + public int forwards_count; public int reactions_count; - public ArrayList views = new ArrayList<>(); + public ArrayList views = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); public ArrayList users = new ArrayList<>(); public String next_offset = ""; - public static TL_stories_storyViewsList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_stories_storyViewsList.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_stories_storyViewsList", constructor)); - } else { - return null; - } + public static StoryViewsList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryViewsList result = null; + switch (constructor) { + case TL_storyViewsList.constructor: + result = new TL_storyViewsList(); + break; + case TL_storyViewsList_layer167.constructor: + result = new TL_storyViewsList_layer167(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryViewsList", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_stories_storyViewsList result = new TL_stories_storyViewsList(); - result.readParams(stream, exception); return result; } + } + + public static class TL_storyViewsList extends StoryViewsList { + public static final int constructor = 0x59d78fc5; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + count = stream.readInt32(exception); + views_count = stream.readInt32(exception); + forwards_count = stream.readInt32(exception); + reactions_count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + StoryView object = StoryView.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + views.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.Chat object = TLRPC.Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.User object = TLRPC.User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(count); + stream.writeInt32(views_count); + stream.writeInt32(forwards_count); + stream.writeInt32(reactions_count); + stream.writeInt32(0x1cb5c415); + int count = views.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + views.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } + } + } + + + public static class TL_storyViewsList_layer167 extends StoryViewsList { + public static final int constructor = 0x46e9b9ec; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -898,7 +1057,7 @@ public class TL_stories { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - TL_storyView object = TL_storyView.TLdeserialize(stream, stream.readInt32(exception), exception); + StoryView object = StoryView.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } @@ -975,6 +1134,7 @@ public class TL_stories { public int flags; public boolean just_contacts; public boolean reactions_first; + public boolean forwards_first; public TLRPC.InputPeer peer; public String q; public int id; @@ -982,13 +1142,14 @@ public class TL_stories { public int limit; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_stories_storyViewsList.TLdeserialize(stream, constructor, exception); + return StoryViewsList.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = just_contacts ? (flags | 1) : (flags &~ 1); flags = reactions_first ? (flags | 4) : (flags &~ 4); + flags = forwards_first ? (flags | 8) : (flags &~ 8); stream.writeInt32(flags); peer.serializeToStream(stream); if ((flags & 2) != 0) { @@ -2543,9 +2704,15 @@ public class TL_stories { case TL_inputMediaAreaVenue.constructor: result = new TL_inputMediaAreaVenue(); break; + case TL_inputMediaAreaChannelPost.constructor: + result = new TL_inputMediaAreaChannelPost(); + break; case TL_mediaAreaSuggestedReaction.constructor: result = new TL_mediaAreaSuggestedReaction(); break; + case TL_mediaAreaChannelPost.constructor: + result = new TL_mediaAreaChannelPost(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in MediaArea", constructor)); @@ -2578,6 +2745,26 @@ public class TL_stories { } } + public static class TL_mediaAreaChannelPost extends MediaArea { + public static final int constructor = 0x770416af; + + public long channel_id; + public int msg_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + channel_id = stream.readInt64(exception); + msg_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + coordinates.serializeToStream(stream); + stream.writeInt64(channel_id); + stream.writeInt32(msg_id); + } + } + public static class TL_mediaAreaVenue extends MediaArea { public static final int constructor = 0xbe82db9c; @@ -2634,6 +2821,28 @@ public class TL_stories { } } + public static class TL_inputMediaAreaChannelPost extends MediaArea { + public static final int constructor = 0x2271f2bf; + + public TLRPC.InputChannel channel; + public int msg_id; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + channel = TLRPC.InputChannel.TLdeserialize(stream, stream.readInt32(exception), exception); + msg_id = stream.readInt32(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + coordinates.serializeToStream(stream); + channel.serializeToStream(stream); + stream.writeInt32(msg_id); + } + } + public static class TL_mediaAreaGeoPoint extends MediaArea { public static final int constructor = 0xdf8b3b22; @@ -2741,4 +2950,229 @@ public class TL_stories { stream.writeInt32(id); } } + + public static class StoryReaction extends TLObject { + + public TLRPC.Peer peer_id; + public StoryItem story; + public TLRPC.Message message; + + public static StoryReaction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryReaction result = null; + switch (constructor) { + case TL_storyReaction.constructor: + result = new TL_storyReaction(); + break; + case TL_storyReactionPublicForward.constructor: + result = new TL_storyReactionPublicForward(); + break; + case TL_storyReactionPublicRepost.constructor: + result = new TL_storyReactionPublicRepost(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryReaction", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_storyReactionPublicForward extends StoryReaction { + public final static int constructor = 0xbbab2643; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + message = TLRPC.Message.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + } + } + + public static class TL_storyReactionPublicRepost extends StoryReaction { + public final static int constructor = 0xcfcd0f13; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + peer_id = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + if (story != null) { + story.dialogId = DialogObject.getPeerDialogId(peer_id); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer_id.serializeToStream(stream); + story.serializeToStream(stream); + } + } + + public static class TL_storyReaction extends StoryReaction { + public final static int constructor = 0x6090d6d5; + + public int date; + public TLRPC.Reaction reaction; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + peer_id = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + reaction = TLRPC.Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer_id.serializeToStream(stream); + stream.writeInt32(date); + reaction.serializeToStream(stream); + } + } + + public static class TL_storyReactionsList extends TLObject { + public final static int constructor = 0xaa5f789c; + + public int flags; + public int count; + public ArrayList reactions = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public String next_offset; + + public static TL_storyReactionsList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_storyReactionsList.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_storyReactionsList", constructor)); + } else { + return null; + } + } + TL_storyReactionsList result = new TL_storyReactionsList(); + result.readParams(stream, exception); + return result; + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = reactions.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + reactions.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + chats.get(i).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + users.get(i).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + StoryReaction object = StoryReaction.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + reactions.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.Chat object = TLRPC.Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.User object = TLRPC.User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } + } + } + + public static class TL_getStoryReactionsList extends TLObject { + public final static int constructor = 0xb9b2881f; + + public int flags; + public boolean forwards_first; + public TLRPC.InputPeer peer; + public int id; + public TLRPC.Reaction reaction; + public String offset; + public int limit; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_storyReactionsList.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = forwards_first ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + if ((flags & 1) != 0) { + reaction.serializeToStream(stream); + } + if ((flags & 2) != 0) { + stream.writeString(offset); + } + stream.writeInt32(limit); + } + } } 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 8ca2b8905..bc5b09713 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.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; @@ -192,7 +194,7 @@ public class ActionBar extends FrameLayout { if (itemsColor != 0) { backButtonImageView.setColorFilter(new PorterDuffColorFilter(itemsColor, colorFilterMode)); } - backButtonImageView.setPadding(AndroidUtilities.dp(1), 0, 0, 0); + backButtonImageView.setPadding(dp(1), 0, 0, 0); addView(backButtonImageView, LayoutHelper.createFrame(54, 54, Gravity.LEFT | Gravity.TOP)); backButtonImageView.setOnClickListener(v -> { @@ -302,19 +304,18 @@ public class ActionBar extends FrameLayout { canvas.clipRect(0, -getTranslationY() + (occupyStatusBar ? AndroidUtilities.statusBarHeight : 0), getMeasuredWidth(), getMeasuredHeight()); } boolean result = super.drawChild(canvas, child, drawingTime); - if (supportsHolidayImage && !titleOverlayShown && !LocaleController.isRTL && (child == titleTextView[0] || child == titleTextView[1])) { + if (supportsHolidayImage && !titleOverlayShown && !LocaleController.isRTL && (child == titleTextView[0] || child == titleTextView[1] || child == titlesContainer && useContainerForTitles)) { Drawable drawable = Theme.getCurrentHolidayDrawable(); if (drawable != null) { - - SimpleTextView titleView = (SimpleTextView) child; - if (titleView.getVisibility() == View.VISIBLE && titleView.getText() instanceof String) { + SimpleTextView titleView = child == titlesContainer ? titleTextView[0] : (SimpleTextView) child; + if (titleView != null && titleView.getVisibility() == View.VISIBLE && titleView.getText() instanceof String) { TextPaint textPaint = titleView.getTextPaint(); textPaint.getFontMetricsInt(fontMetricsInt); textPaint.getTextBounds((String) titleView.getText(), 0, 1, rect); int x = titleView.getTextStartX() + Theme.getCurrentHolidayDrawableXOffset() + (rect.width() - (drawable.getIntrinsicWidth() + Theme.getCurrentHolidayDrawableXOffset())) / 2; - int y = titleView.getTextStartY() + Theme.getCurrentHolidayDrawableYOffset() + (int) Math.ceil((titleView.getTextHeight() - rect.height()) / 2.0f); + int y = titleView.getTextStartY() + Theme.getCurrentHolidayDrawableYOffset() + (int) Math.ceil((titleView.getTextHeight() - rect.height()) / 2.0f) + (int) (dp(8) * (1f - titlesContainer.getScaleY())); drawable.setBounds(x, y - drawable.getIntrinsicHeight(), x + drawable.getIntrinsicWidth(), y); - drawable.setAlpha((int) (255 * titleView.getAlpha())); + drawable.setAlpha((int) (255 * titlesContainer.getAlpha() * titleView.getAlpha())); drawable.draw(canvas); if (overlayTitleAnimationInProgress) { child.invalidate(); @@ -425,9 +426,9 @@ public class ActionBar extends FrameLayout { titleTextView[i].setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); } titleTextView[i].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleTextView[i].setDrawablePadding(AndroidUtilities.dp(4)); - titleTextView[i].setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); - titleTextView[i].setRightDrawableTopPadding(-AndroidUtilities.dp(1)); + titleTextView[i].setDrawablePadding(dp(4)); + titleTextView[i].setPadding(0, dp(8), 0, dp(8)); + titleTextView[i].setRightDrawableTopPadding(-dp(1)); if (useContainerForTitles) { titlesContainer.addView(titleTextView[i], 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); } else { @@ -1209,10 +1210,10 @@ public class ActionBar extends FrameLayout { int textLeft; if (backButtonImageView != null && backButtonImageView.getVisibility() != GONE) { - backButtonImageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(54), MeasureSpec.EXACTLY), actionBarHeightSpec); - textLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 80 : 72); + backButtonImageView.measure(MeasureSpec.makeMeasureSpec(dp(54), MeasureSpec.EXACTLY), actionBarHeightSpec); + textLeft = dp(AndroidUtilities.isTablet() ? 80 : 72); } else { - textLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 26 : 18); + textLeft = dp(AndroidUtilities.isTablet() ? 26 : 18); } if (menu != null && menu.getVisibility() != GONE) { @@ -1222,12 +1223,12 @@ public class ActionBar extends FrameLayout { menuWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST); menu.measure(menuWidth, actionBarHeightSpec); int itemsWidth = menu.getItemsMeasuredWidth(true); - menuWidth = MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(AndroidUtilities.isTablet() ? 74 : 66) + menu.getItemsMeasuredWidth(true), MeasureSpec.EXACTLY); + menuWidth = MeasureSpec.makeMeasureSpec(width - dp(AndroidUtilities.isTablet() ? 74 : 66) + menu.getItemsMeasuredWidth(true), MeasureSpec.EXACTLY); if (!isMenuOffsetSuppressed) { menu.translateXItems(-itemsWidth); } } else if (isSearchFieldVisible) { - menuWidth = MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(AndroidUtilities.isTablet() ? 74 : 66), MeasureSpec.EXACTLY); + menuWidth = MeasureSpec.makeMeasureSpec(width - dp(AndroidUtilities.isTablet() ? 74 : 66), MeasureSpec.EXACTLY); if (!isMenuOffsetSuppressed) { menu.translateXItems(0); } @@ -1243,7 +1244,7 @@ public class ActionBar extends FrameLayout { for (int i = 0; i < 2; i++) { if (titleTextView[0] != null && titleTextView[0].getVisibility() != GONE || subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { - int availableWidth = width - (menu != null ? menu.getMeasuredWidth() : 0) - AndroidUtilities.dp(16) - textLeft - titleRightMargin; + int availableWidth = width - (menu != null ? menu.getMeasuredWidth() : 0) - dp(16) - textLeft - titleRightMargin; if (((fromBottom && i == 0) || (!fromBottom && i == 1)) && overlayTitleAnimation && titleAnimationRunning) { titleTextView[i].setTextSize(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20); @@ -1270,29 +1271,29 @@ public class ActionBar extends FrameLayout { } if (titleTextView[i] != null && titleTextView[i].getVisibility() != GONE) { - titleTextView[i].measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24) + titleTextView[i].getPaddingTop() + titleTextView[i].getPaddingBottom(), MeasureSpec.AT_MOST)); + titleTextView[i].measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(24) + titleTextView[i].getPaddingTop() + titleTextView[i].getPaddingBottom(), MeasureSpec.AT_MOST)); if (centerScale) { CharSequence text = titleTextView[i].getText(); titleTextView[i].setPivotX(titleTextView[i].getTextPaint().measureText(text, 0, text.length()) / 2f); - titleTextView[i].setPivotY((AndroidUtilities.dp(24) >> 1)); + titleTextView[i].setPivotY((dp(24) >> 1)); } else { titleTextView[i].setPivotX(0); titleTextView[i].setPivotY(0); } } if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { - subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.AT_MOST)); } if (additionalSubtitleTextView != null && additionalSubtitleTextView.getVisibility() != GONE) { - additionalSubtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + additionalSubtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.AT_MOST)); } } } if (avatarSearchImageView != null) { avatarSearchImageView.measure( - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY) + MeasureSpec.makeMeasureSpec(dp(42), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(42), MeasureSpec.EXACTLY) ); } @@ -1317,13 +1318,13 @@ public class ActionBar extends FrameLayout { int textLeft; if (backButtonImageView != null && backButtonImageView.getVisibility() != GONE) { backButtonImageView.layout(0, additionalTop, backButtonImageView.getMeasuredWidth(), additionalTop + backButtonImageView.getMeasuredHeight()); - textLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 80 : 72); + textLeft = dp(AndroidUtilities.isTablet() ? 80 : 72); } else { - textLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 26 : 18); + textLeft = dp(AndroidUtilities.isTablet() ? 26 : 18); } if (menu != null && menu.getVisibility() != GONE) { - int menuLeft = menu.searchFieldVisible() ? AndroidUtilities.dp(AndroidUtilities.isTablet() ? 74 : 66) : (right - left) - menu.getMeasuredWidth(); + int menuLeft = menu.searchFieldVisible() ? dp(AndroidUtilities.isTablet() ? 74 : 66) : (right - left) - menu.getMeasuredWidth(); menu.layout(menuLeft, additionalTop, menuLeft + menu.getMeasuredWidth(), additionalTop + menu.getMeasuredHeight()); } @@ -1334,7 +1335,7 @@ public class ActionBar extends FrameLayout { textTop = (getCurrentActionBarHeight() - titleTextView[i].getTextHeight()) / 2; } else { if ((subtitleTextView != null && subtitleTextView.getVisibility() != GONE)) { - textTop = (getCurrentActionBarHeight() / 2 - titleTextView[i].getTextHeight()) / 2 + AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 3); + textTop = (getCurrentActionBarHeight() / 2 - titleTextView[i].getTextHeight()) / 2 + dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 3); } else { textTop = (getCurrentActionBarHeight() - titleTextView[i].getTextHeight()) / 2; } @@ -1343,20 +1344,20 @@ public class ActionBar extends FrameLayout { } } if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { - int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - subtitleTextView.getTextHeight()) / 2 - AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 1); + int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - subtitleTextView.getTextHeight()) / 2 - dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 1); subtitleTextView.layout(textLeft, additionalTop + textTop, textLeft + subtitleTextView.getMeasuredWidth(), additionalTop + textTop + subtitleTextView.getTextHeight()); } if (additionalSubtitleTextView != null && additionalSubtitleTextView.getVisibility() != GONE) { - int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - additionalSubtitleTextView.getTextHeight()) / 2 - AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 1); + int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - additionalSubtitleTextView.getTextHeight()) / 2 - dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 1); additionalSubtitleTextView.layout(textLeft, additionalTop + textTop, textLeft + additionalSubtitleTextView.getMeasuredWidth(), additionalTop + textTop + additionalSubtitleTextView.getTextHeight()); } if (avatarSearchImageView != null) { avatarSearchImageView.layout( - AndroidUtilities.dp(56 + 8), + dp(56 + 8), additionalTop + (getCurrentActionBarHeight() - avatarSearchImageView.getMeasuredHeight()) / 2, - AndroidUtilities.dp(56 + 8) + avatarSearchImageView.getMeasuredWidth(), + dp(56 + 8) + avatarSearchImageView.getMeasuredWidth(), additionalTop + (getCurrentActionBarHeight() + avatarSearchImageView.getMeasuredHeight()) / 2 ); } @@ -1476,7 +1477,7 @@ public class ActionBar extends FrameLayout { invalidate(); } titleTextView[0].setText(textToSet); - titleTextView[0].setDrawablePadding(AndroidUtilities.dp(4)); + titleTextView[0].setDrawablePadding(dp(4)); titleTextView[0].setRightDrawable(rightDrawableToSet); titleTextView[0].setRightDrawableOnClick(rightDrawableOnClickListener); if (rightDrawableToSet instanceof AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable) { @@ -1496,7 +1497,7 @@ public class ActionBar extends FrameLayout { createTitleTextView(1); } titleTextView[1].setText(textToSet); - titleTextView[1].setDrawablePadding(AndroidUtilities.dp(4)); + titleTextView[1].setDrawablePadding(dp(4)); titleTextView[1].setRightDrawable(rightDrawableToSet); titleTextView[1].setRightDrawableOnClick(rightDrawableOnClickListener); if (rightDrawableToSet instanceof AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable) { @@ -1510,7 +1511,7 @@ public class ActionBar extends FrameLayout { titleTextView[1] = titleTextView[0]; titleTextView[0] = tmp; titleTextView[0].setAlpha(0); - titleTextView[0].setTranslationY(-AndroidUtilities.dp(20)); + titleTextView[0].setTranslationY(-dp(20)); titleTextView[0].animate() .alpha(1f) .translationY(0) @@ -1518,7 +1519,7 @@ public class ActionBar extends FrameLayout { ViewPropertyAnimator animator = titleTextView[1].animate() .alpha(0); if (subtitleTextView == null) { - animator.translationY(AndroidUtilities.dp(20)); + animator.translationY(dp(20)); } else { animator.scaleY(0.7f).scaleX(0.7f); } @@ -1627,11 +1628,11 @@ public class ActionBar extends FrameLayout { public static int getCurrentActionBarHeight() { if (AndroidUtilities.isTablet()) { - return AndroidUtilities.dp(64); + return dp(64); } else if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - return AndroidUtilities.dp(48); + return dp(48); } else { - return AndroidUtilities.dp(56); + return dp(56); } } @@ -1665,7 +1666,7 @@ public class ActionBar extends FrameLayout { this.fromBottom = fromBottom; titleTextView[0].setAlpha(0); if (!crossfade) { - titleTextView[0].setTranslationY(fromBottom ? AndroidUtilities.dp(20) : -AndroidUtilities.dp(20)); + titleTextView[0].setTranslationY(fromBottom ? dp(20) : -dp(20)); } ViewPropertyAnimator a1 = titleTextView[0].animate().alpha(1f).translationY(0).setDuration(duration); if (interpolator != null) { @@ -1676,7 +1677,7 @@ public class ActionBar extends FrameLayout { titleAnimationRunning = true; ViewPropertyAnimator a = titleTextView[1].animate().alpha(0); if (!crossfade) { - a.translationY(fromBottom ? -AndroidUtilities.dp(20) : AndroidUtilities.dp(20)); + a.translationY(fromBottom ? -dp(20) : dp(20)); } if (interpolator != null) { a.setInterpolator(interpolator); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 304910e89..9e9019ad6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -396,6 +396,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F private float themeAnimationValue; private boolean animateThemeAfterAnimation; private Theme.ThemeInfo animateSetThemeAfterAnimation; + private boolean animateSetThemeAfterAnimationApply; private boolean animateSetThemeNightAfterAnimation; private int animateSetThemeAccentIdAfterAnimation; private boolean rebuildAfterAnimation; @@ -1256,10 +1257,10 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F } BaseFragment lastFragment = getLastFragment(); Dialog dialog = lastFragment != null ? lastFragment.getVisibleDialog() : null; - if (dialog == null && LaunchActivity.instance != null && LaunchActivity.instance.visibleDialog != null) { - dialog = LaunchActivity.instance.visibleDialog; + if (dialog == null && LaunchActivity.instance != null && LaunchActivity.instance.getVisibleDialog() != null) { + dialog = LaunchActivity.instance.getVisibleDialog(); } - if (shouldOpenFragmentOverlay(dialog)) { + if (lastFragment != null && shouldOpenFragmentOverlay(dialog)) { BaseFragment.BottomSheetParams bottomSheetParams = new BaseFragment.BottomSheetParams(); bottomSheetParams.transitionFromLeft = true; bottomSheetParams.allowNestedScroll = false; @@ -1564,7 +1565,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F } private boolean shouldOpenFragmentOverlay(Dialog visibleDialog) { - return visibleDialog instanceof ChatAttachAlert || visibleDialog instanceof BotWebViewSheet; + return (visibleDialog != null && visibleDialog.isShowing()) && (visibleDialog instanceof ChatAttachAlert || visibleDialog instanceof BotWebViewSheet); } @Override @@ -1726,6 +1727,10 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F fragment.setInPreviewMode(false); fragment.setInMenuMode(false); + + try { + AndroidUtilities.setLightStatusBar(parentActivity.getWindow(), Theme.getColor(Theme.key_actionBarDefault) == Color.WHITE || (fragment.hasForceLightStatusBar() && !Theme.getCurrentTheme().isDark()), fragment.hasForceLightStatusBar()); + } catch (Exception ignore) {} } @Override @@ -2124,6 +2129,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F animateSetThemeAfterAnimation = settings.theme; animateSetThemeNightAfterAnimation = settings.nightTheme; animateSetThemeAccentIdAfterAnimation = settings.accentId; + animateSetThemeAfterAnimationApply = settings.applyTrulyTheme; if (onDone != null) { onDone.run(); } @@ -2259,7 +2265,7 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F onDone.run(); } }; - if (fragmentCount >= 1 && settings.applyTheme) { + if (fragmentCount >= 1 && settings.applyTheme && settings.applyTrulyTheme) { if (settings.accentId != -1 && settings.theme != null) { settings.theme.setCurrentAccentId(settings.accentId); Theme.saveThemeAccents(settings.theme, true, false, true, false); @@ -2363,7 +2369,11 @@ public class ActionBarLayout extends FrameLayout implements INavigationLayout, F rebuildAllFragmentViews(rebuildLastAfterAnimation, showLastAfterAnimation); rebuildAfterAnimation = false; } else if (animateThemeAfterAnimation) { - animateThemedValues(animateSetThemeAfterAnimation, animateSetThemeAccentIdAfterAnimation, animateSetThemeNightAfterAnimation, false); + ThemeAnimationSettings settings = new ThemeAnimationSettings(animateSetThemeAfterAnimation, animateSetThemeAccentIdAfterAnimation, animateSetThemeNightAfterAnimation, false); + if (!animateSetThemeAfterAnimationApply) { + settings.applyTheme = settings.applyTrulyTheme = animateSetThemeAfterAnimationApply; + } + animateThemedValues(settings, null); animateSetThemeAfterAnimation = null; animateThemeAfterAnimation = false; } 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 8f3d3b141..5f727c5ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -83,6 +83,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati private View customView; private View bottomView; + private View aboveMessageView; private int customViewHeight = LayoutHelper.WRAP_CONTENT; private TextView titleTextView; private TextView secondTitleTextView; @@ -766,9 +767,12 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati progressView.setProgressColor(getThemedColor(Theme.key_dialog_inlineProgress)); progressViewContainer.addView(progressView, LayoutHelper.createFrame(86, 86, Gravity.CENTER)); } else { + if (aboveMessageView != null) { + scrollContainer.addView(aboveMessageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 22, 4, 22, 12)); + } scrollContainer.addView(messageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (topAnimationIsNew ? Gravity.CENTER_HORIZONTAL : LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 0, 24, customView != null || items != null ? customViewOffset : 0)); if (bottomView != null) { - scrollContainer.addView(bottomView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, -24, 24, 0)); + scrollContainer.addView(bottomView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 22, 12, 22, 0)); } } if (!TextUtils.isEmpty(message)) { @@ -1170,6 +1174,21 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati } } + public void setTextSize(int titleSizeDp, int messageSizeDp) { + if (titleTextView != null) { + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, titleSizeDp); + } + if (messageTextView != null) { + messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, messageSizeDp); + } + } + + public void setMessageLineSpacing(float spaceDp) { + if (messageTextView != null) { + messageTextView.setLineSpacing(AndroidUtilities.dp(spaceDp), 1.0f); + } + } + private void showCancelAlert() { if (!canCacnel || cancelDialog != null) { return; @@ -1523,6 +1542,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati return this; } + public Builder aboveMessageView(View view) { + alertDialog.aboveMessageView = view; + return this; + } + public Builder addBottomView(View view) { alertDialog.bottomView = view; return this; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 67f034d89..9e3105c1f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -109,6 +109,8 @@ public class BottomSheet extends Dialog { protected boolean fullWidth; protected boolean isFullscreen; private boolean fullHeight; + private int cellType; + private Integer selectedPos; protected ColorDrawable backDrawable = new ColorDrawable(0xff000000) { @Override public void setAlpha(int alpha) { @@ -897,7 +899,9 @@ public class BottomSheet extends Dialog { this.resourcesProvider = resourcesProvider; currentType = type; - setBackgroundDrawable(Theme.getSelectorDrawable(false, resourcesProvider)); + if (type != Builder.CELL_TYPE_CALL) { + setBackgroundDrawable(Theme.getSelectorDrawable(false, resourcesProvider)); + } //setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); imageView = new ImageView(context); @@ -910,7 +914,7 @@ public class BottomSheet extends Dialog { textView.setSingleLine(true); textView.setGravity(Gravity.CENTER_HORIZONTAL); textView.setEllipsize(TextUtils.TruncateAt.END); - if (type == 0) { + if (type == 0 || type == Builder.CELL_TYPE_CALL) { textView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL)); @@ -1234,7 +1238,7 @@ public class BottomSheet extends Dialog { if (items[a] == null) { continue; } - BottomSheetCell cell = new BottomSheetCell(getContext(), 0, resourcesProvider); + BottomSheetCell cell = new BottomSheetCell(getContext(), cellType, resourcesProvider); cell.setTextAndIcon(items[a], itemIcons != null ? itemIcons[a] : 0, null, bigTitle); containerView.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP, 0, topOffset, 0, 0)); topOffset += 48; @@ -1617,7 +1621,7 @@ public class BottomSheet extends Dialog { ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, getContainerViewHeight() + keyboardHeight + AndroidUtilities.dp(10) + (scrollNavBar ? getBottomInset() : 0)), ObjectAnimator.ofInt(backDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0) ); - currentSheetAnimation.setDuration(180); + currentSheetAnimation.setDuration(cellType == Builder.CELL_TYPE_CALL ? 330 : 180); currentSheetAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); currentSheetAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -1652,6 +1656,27 @@ public class BottomSheet extends Dialog { }); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); currentSheetAnimation.start(); + + if (cellType == Builder.CELL_TYPE_CALL && selectedPos != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int color1 = getItemViews().get(selectedPos).getTextView().getCurrentTextColor(); + int color2 = getItemViews().get(item).getTextView().getCurrentTextColor(); + ValueAnimator animator = ValueAnimator.ofArgb(color1, color2); + animator.addUpdateListener(a -> { + int color = (int) a.getAnimatedValue(); + setItemColor(selectedPos, color, color); + }); + animator.setDuration(130); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.start(); + ValueAnimator animator2 = ValueAnimator.ofArgb(color2, color1); + animator2.addUpdateListener(a -> { + int color = (int) a.getAnimatedValue(); + setItemColor(item, color, color); + }); + animator2.setDuration(130); + animator2.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator2.start(); + } } @Override @@ -1796,6 +1821,8 @@ public class BottomSheet extends Dialog { public static class Builder { + public static int CELL_TYPE_CALL = 4; + private BottomSheet bottomSheet; public Builder(Context context) { @@ -1863,6 +1890,16 @@ public class BottomSheet extends Dialog { return this; } + public Builder selectedPos(Integer pos) { + bottomSheet.selectedPos = pos; + return this; + } + + public Builder setCellType(int cellType) { + bottomSheet.cellType = cellType; + return this; + } + public Builder setTitleMultipleLines(boolean allowMultipleLines) { bottomSheet.multipleLinesTitle = allowMultipleLines; return this; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java index 33922de82..bc9282cb7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/EmojiThemes.java @@ -254,10 +254,12 @@ public class EmojiThemes { } else { baseTheme = Theme.getTheme("Blue"); } - themeInfo = new Theme.ThemeInfo(baseTheme); - accent = themeInfo.createNewAccent(tlTheme, currentAccount, true, settingsIndex); - if (accent != null) { - themeInfo.setCurrentAccentId(accent.id); + if (baseTheme != null) { + themeInfo = new Theme.ThemeInfo(baseTheme); + accent = themeInfo.createNewAccent(tlTheme, currentAccount, true, settingsIndex); + if (accent != null) { + themeInfo.setCurrentAccentId(accent.id); + } } } else { if (themeInfo.themeAccentsMap != null) { @@ -265,6 +267,10 @@ public class EmojiThemes { } } + if (themeInfo == null) { + return currentColors; + } + SparseIntArray currentColorsNoAccent; String[] wallpaperLink = new String[1]; if (themeInfo.pathToFile != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java index df3f19d93..2722ae095 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java @@ -1007,7 +1007,7 @@ public final class FloatingToolbar { }); } final int size = menuItems.size(); - final boolean premiumLocked = MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked; + final boolean premiumLocked = MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked(); for (int i = 0; i < size; i++) { final MenuItem menuItem = menuItems.get(i); final boolean show; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java index 497bcef10..8fe20bab7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java @@ -368,6 +368,7 @@ public interface INavigationLayout { public final boolean instant; public boolean onlyTopFragment; public boolean applyTheme = true; + public boolean applyTrulyTheme = true; public Runnable afterStartDescriptionsAddedRunnable; public Runnable beforeAnimationRunnable; public Runnable afterAnimationRunnable; 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 38a52e7fa..c796ea69e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -61,6 +61,7 @@ public class SimpleTextView extends View implements Drawable.Callback { private SpannableStringBuilder spannableStringBuilder; private Drawable leftDrawable; private Drawable rightDrawable; + private Drawable rightDrawable2; private Drawable replacedDrawable; private String replacedText; private int replacingDrawableTextIndex; @@ -273,6 +274,10 @@ public class SimpleTextView extends View implements Drawable.Callback { int dw = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); size += dw + drawablePadding; } + if (rightDrawable2 != null) { + int dw = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + size += dw + drawablePadding; + } return size; } @@ -342,6 +347,11 @@ public class SimpleTextView extends View implements Drawable.Callback { 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); if (replacingDrawableTextIndex >= 0) { @@ -450,7 +460,7 @@ public class SimpleTextView extends View implements Drawable.Callback { scrollingOffset = 0; currentScrollDelay = SCROLL_DELAY_MS; } - createLayout(width - getPaddingLeft() - getPaddingRight() - minusWidth - (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0)); + createLayout(width - getPaddingLeft() - getPaddingRight() - minusWidth - (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0) - (rightDrawableOutside && rightDrawable2 != null ? rightDrawable2.getIntrinsicWidth() + drawablePadding : 0)); int finalHeight; if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { @@ -460,7 +470,7 @@ public class SimpleTextView extends View implements Drawable.Callback { } if (widthWrapContent) { // textWidth = (int) Math.ceil(layout.getLineWidth(0)); - width = Math.min(width, getPaddingLeft() + textWidth + getPaddingRight() + minusWidth + (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0)); + width = Math.min(width, getPaddingLeft() + textWidth + getPaddingRight() + minusWidth + (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0) + (rightDrawableOutside && rightDrawable2 != null ? rightDrawable2.getIntrinsicWidth() + drawablePadding : 0)); } setMeasuredDimension(width, finalHeight); @@ -549,7 +559,7 @@ public class SimpleTextView extends View implements Drawable.Callback { @Override protected boolean verifyDrawable(@NonNull Drawable who) { - return who == rightDrawable || who == leftDrawable || super.verifyDrawable(who); + return who == rightDrawable || who == rightDrawable2 || who == leftDrawable || super.verifyDrawable(who); } public void replaceTextWithDrawable(Drawable drawable, String replacedText) { @@ -599,6 +609,26 @@ public class SimpleTextView extends View implements Drawable.Callback { } } + public void setRightDrawable2(Drawable drawable) { + if (rightDrawable2 == drawable) { + return; + } + if (rightDrawable2 != null) { + rightDrawable2.setCallback(null); + } + rightDrawable2 = drawable; + if (drawable != null) { + drawable.setCallback(this); + } + if (!recreateLayoutMaybe()) { + invalidate(); + } + } + + public Drawable getRightDrawable2() { + return rightDrawable2; + } + public void setRightDrawableScale(float scale) { rightDrawableScale = scale; } @@ -717,6 +747,11 @@ public class SimpleTextView extends View implements Drawable.Callback { 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) { width -= replacedDrawable.getIntrinsicWidth(); @@ -808,6 +843,27 @@ public class SimpleTextView extends View implements Drawable.Callback { rightDrawable.draw(canvas); totalWidth += drawablePadding + dw; } + if (rightDrawable2 != null && !rightDrawableHidden && rightDrawableScale > 0 && !rightDrawableOutside) { + 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; + } int nextScrollX = totalWidth + AndroidUtilities.dp(DIST_BETWEEN_SCROLLING_TEXT); if (scrollingOffset != 0) { @@ -835,6 +891,22 @@ public class SimpleTextView extends View implements Drawable.Callback { rightDrawable.setBounds(x, y, x + dw, y + dh); rightDrawable.draw(canvas); } + if (rightDrawable2 != null && !rightDrawableOutside) { + int dw = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + int dh = (int) (rightDrawable2.getIntrinsicHeight() * rightDrawableScale); + int x = textOffsetX + textWidth + drawablePadding + (int) -scrollingOffset + nextScrollX; + if (rightDrawable != null) { + x += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale) + drawablePadding; + } + 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); + } } if (layout != null) { @@ -939,6 +1011,25 @@ public class SimpleTextView extends View implements Drawable.Callback { rightDrawableY = y + (dh >> 1); rightDrawable.draw(canvas); } + if (rightDrawable2 != null && rightDrawableOutside) { + int x = Math.min( + textOffsetX + textWidth + drawablePadding + (scrollingOffset == 0 ? -nextScrollX : (int) -scrollingOffset) + nextScrollX, + getMaxTextWidth() - paddingRight + drawablePadding + ); + if (rightDrawable != null) { + x += (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale) + drawablePadding; + } + 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); + } } public int getRightDrawableX() { @@ -950,7 +1041,7 @@ public class SimpleTextView extends View implements Drawable.Callback { } private int getMaxTextWidth() { - return getMeasuredWidth() - (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0); + return getMeasuredWidth() - (rightDrawableOutside && rightDrawable != null ? rightDrawable.getIntrinsicWidth() + drawablePadding : 0) - (rightDrawableOutside && rightDrawable2 != null ? rightDrawable2.getIntrinsicWidth() + drawablePadding : 0); } private void drawLayout(Canvas canvas) { @@ -1035,6 +1126,8 @@ public class SimpleTextView extends View implements Drawable.Callback { invalidate(leftDrawable.getBounds()); } else if (who == rightDrawable) { invalidate(rightDrawable.getBounds()); + } else if (who == rightDrawable2) { + invalidate(rightDrawable2.getBounds()); } else if (who == replacedDrawable) { invalidate(replacedDrawable.getBounds()); } 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 a007d091d..7c88f7c8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -958,7 +958,7 @@ public class Theme { } if (currentType == TYPE_MEDIA) { if (customPaint || drawFullBottom) { - int radToUse = isBottomNear ? nearRad : rad; + int radToUse = isBottomNear || botButtonsBottom ? nearRad : rad; path.lineTo(bounds.left + padding, bounds.bottom - padding - radToUse); rect.set(bounds.left + padding, bounds.bottom - padding - radToUse * 2, bounds.left + padding + radToUse * 2, bounds.bottom - padding); @@ -1749,7 +1749,6 @@ public class Theme { Math.max(0, Color.blue(submenuBackground) - 10) )); - currentColors.put(key_chat_inCodeBackground, codeBackground(inBubble, isDarkTheme)); if (isDarkTheme && currentColors.get(key_chat_outBubbleGradient1) != 0) { int outBubbleAverage = averageColor(currentColors, key_chat_outBubbleGradient1, key_chat_outBubbleGradient2, key_chat_outBubbleGradient3); Color.colorToHSV(outBubbleAverage, tempHSV); @@ -4126,7 +4125,6 @@ public class Theme { public static final int key_stories_circle_closeFriends1 = colorsCount++; public static final int key_stories_circle_closeFriends2 = colorsCount++; - public static final int key_code_background = colorsCount++; public static final int key_chat_inCodeBackground = colorsCount++; public static final int key_chat_outCodeBackground = colorsCount++; public static final int key_code_keyword = colorsCount++; @@ -4411,6 +4409,7 @@ public class Theme { themeAccentExclusionKeys.add(key_statisticChartLine_lightgreen); themeAccentExclusionKeys.add(key_statisticChartLine_orange); themeAccentExclusionKeys.add(key_statisticChartLine_indigo); + themeAccentExclusionKeys.add(key_chat_inCodeBackground); themeAccentExclusionKeys.add(key_voipgroup_checkMenu); themeAccentExclusionKeys.add(key_voipgroup_muteButton); @@ -5757,7 +5756,7 @@ public class Theme { ripple = new ShapeDrawable(new RectShape()); ((ShapeDrawable) ripple).getPaint().setColor(rippleColor); } - Drawable pressed = new LayerDrawable(new Drawable[] { background, ripple }); + Drawable pressed = background == null ? ripple : new LayerDrawable(new Drawable[] { background, ripple }); stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressed); stateListDrawable.addState(new int[]{android.R.attr.state_selected}, pressed); stateListDrawable.addState(StateSet.WILD_CARD, background); @@ -5791,7 +5790,7 @@ public class Theme { } else { StateListDrawable stateListDrawable = new StateListDrawable(); Drawable ripple = new CircleDrawable(radius, rippleColor); - Drawable pressed = new LayerDrawable(new Drawable[] { background, ripple }); + Drawable pressed = background == null ? ripple : new LayerDrawable(new Drawable[] { background, ripple }); stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressed); stateListDrawable.addState(new int[]{android.R.attr.state_selected}, pressed); stateListDrawable.addState(StateSet.WILD_CARD, background); @@ -9868,9 +9867,13 @@ public class Theme { MotionBackgroundDrawable motionBackgroundDrawable = new MotionBackgroundDrawable(backgroundColor, gradientToColor1, gradientToColor2, gradientToColor3, false); Bitmap patternBitmap = null; - if (wallpaperFile != null && wallpaperDocument != null) { - File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(wallpaperDocument, true); - patternBitmap = SvgHelper.getBitmap(f, AndroidUtilities.dp(360), AndroidUtilities.dp(640), false); + if (wallpaperFile != null && !isCustomTheme()) { + if (wallpaperDocument != null) { + File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(wallpaperDocument, true); + patternBitmap = SvgHelper.getBitmap(f, AndroidUtilities.dp(360), AndroidUtilities.dp(640), false); + } else { + patternBitmap = SvgHelper.getBitmap(R.raw.default_pattern, AndroidUtilities.dp(360), AndroidUtilities.dp(640), Color.WHITE); + } if (patternBitmap != null) { FileOutputStream stream = null; try { 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 da994f514..d3a508cc5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -771,8 +771,7 @@ public class ThemeColors { defaultColors[key_stories_circle_closeFriends1] = 0xFFC9EB38; defaultColors[key_stories_circle_closeFriends2] = 0xFF09C167; - defaultColors[key_code_background] = 0x20000000; - defaultColors[key_chat_inCodeBackground] = 0x08484848; + defaultColors[key_chat_inCodeBackground] = 0xff6F889E; defaultColors[key_chat_outCodeBackground] = 0x123c7503; defaultColors[key_code_keyword] = 0xFFE05356; defaultColors[key_code_operator] = 0xFF4DBBFF; @@ -1513,7 +1512,6 @@ public class ThemeColors { colorKeysMap.put(key_stories_circle_dialog2, "stories_circle_dialog2"); colorKeysMap.put(key_stories_circle_closeFriends1, "stories_circle_closeFriends1"); colorKeysMap.put(key_stories_circle_closeFriends2, "stories_circle_closeFriends2"); - colorKeysMap.put(key_code_background, "code_background"); colorKeysMap.put(key_chat_inCodeBackground, "chat_inCodeBackground"); colorKeysMap.put(key_chat_outCodeBackground, "chat_outCodeBackground"); colorKeysMap.put(key_code_keyword, "code_keyword"); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java index 699f81395..24a61a9bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java @@ -152,7 +152,7 @@ public class AppIconsSelectorCell extends RecyclerListView implements Notificati private void updateIconsVisibility() { availableIcons.clear(); availableIcons.addAll(Arrays.asList(LauncherIconController.LauncherIcon.values())); - if (MessagesController.getInstance(currentAccount).premiumLocked) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { for (int i = 0; i < availableIcons.size(); i++) { if (availableIcons.get(i).premium) { availableIcons.remove(i); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java index deff68f91..b62f91235 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java @@ -9,12 +9,15 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewGroup; +import org.telegram.ui.ActionBar.Theme; + public abstract class BaseCell extends ViewGroup { private final class CheckForTap implements Runnable { @@ -110,4 +113,12 @@ public abstract class BaseCell extends ViewGroup { protected boolean onLongPress() { return true; } + + public int getBoundsLeft() { + return 0; + } + + public int getBoundsRight() { + return getWidth(); + } } 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 6c683cbd3..de8837a38 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -22,6 +22,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.os.Build; import android.text.Layout; import android.text.Spannable; @@ -42,11 +43,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.DownloadController; @@ -65,6 +68,7 @@ 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; @@ -94,6 +98,7 @@ import org.telegram.ui.PhotoViewer; import org.telegram.ui.Stories.StoriesUtilities; import org.telegram.ui.Stories.UploadingDotsSpannable; import org.telegram.ui.Stories.recorder.HintView2; +import org.telegram.ui.Stories.recorder.PreviewView; import java.util.ArrayList; import java.util.HashMap; @@ -167,7 +172,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD default void didClickButton(ChatActionCell cell) { } - default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, boolean animateConfetti) { + default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, String slug, boolean animateConfetti) { } default void didOpenPremiumGiftChannel(ChatActionCell cell, String slug, boolean animateConfetti) { @@ -219,6 +224,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD private URLSpan pressedLink; private int currentAccount = UserConfig.selectedAccount; private ImageReceiver imageReceiver; + private Drawable wallpaperPreviewDrawable; + private Path clipPath; private AvatarDrawable avatarDrawable; private StaticLayout textLayout; private int textWidth; @@ -267,6 +274,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD private ArrayList lineWidths = new ArrayList<>(); private ArrayList lineHeights = new ArrayList<>(); private Path backgroundPath = new Path(); + private int backgroundLeft, backgroundRight; private RectF rect = new RectF(); private boolean invalidatePath = true; private boolean invalidateColors = false; @@ -449,6 +457,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD previousWidth = 0; imageReceiver.setAutoRepeatCount(0); imageReceiver.clearDecorators(); + if (messageObject.type != MessageObject.TYPE_ACTION_WALLPAPER) { + wallpaperPreviewDrawable = null; + } if (messageObject.isStoryMention()) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.media.user_id); avatarDrawable.setInfo(currentAccount, user); @@ -470,11 +481,34 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } } - TLRPC.MessageAction action = messageObject.messageOwner.action; - if (action.wallpaper.uploadingImage != null) { - imageReceiver.setImage(ImageLocation.getForPath(action.wallpaper.uploadingImage), "150_150_wallpaper" + action.wallpaper.id + ChatBackgroundDrawable.hash(action.wallpaper.settings), null, null, ChatBackgroundDrawable.createThumb(action.wallpaper), 0, null, action.wallpaper, 1); + TLRPC.WallPaper wallPaper = null; + if (messageObject.currentEvent != null && messageObject.currentEvent.action instanceof TLRPC.TL_channelAdminLogEventActionChangeWallpaper) { + wallPaper = ((TLRPC.TL_channelAdminLogEventActionChangeWallpaper) messageObject.currentEvent.action).new_value; + } else if (messageObject.messageOwner != null && messageObject.messageOwner.action != null) { + TLRPC.MessageAction action = messageObject.messageOwner.action; + wallPaper = action.wallpaper; + } + if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(wallPaper))) { + final boolean isDark = themeDelegate != null ? themeDelegate.isDark() : Theme.isCurrentThemeDark(); + imageReceiver.clearImage(); + wallpaperPreviewDrawable = PreviewView.getBackgroundDrawableFromTheme(currentAccount, ChatThemeController.getWallpaperEmoticon(wallPaper), isDark, false); + if (wallpaperPreviewDrawable != null) { + wallpaperPreviewDrawable.setCallback(this); + } + } else if (wallPaper != null && wallPaper.uploadingImage != null) { + imageReceiver.setImage(ImageLocation.getForPath(wallPaper.uploadingImage), "150_150_wallpaper" + wallPaper.id + ChatBackgroundDrawable.hash(wallPaper.settings), null, null, ChatBackgroundDrawable.createThumb(wallPaper), 0, null, wallPaper, 1); + wallpaperPreviewDrawable = null; + } else if (wallPaper != null) { + TLRPC.Document document = null; + if (messageObject.photoThumbsObject instanceof TLRPC.Document) { + document = (TLRPC.Document) messageObject.photoThumbsObject; + } else if (wallPaper != null) { + document = wallPaper.document; + } + imageReceiver.setImage(ImageLocation.getForDocument(document), "150_150_wallpaper" + wallPaper.id + ChatBackgroundDrawable.hash(wallPaper.settings), null, null, ChatBackgroundDrawable.createThumb(wallPaper), 0, null, wallPaper, 1); + wallpaperPreviewDrawable = null; } else { - imageReceiver.setImage(ImageLocation.getForDocument((TLRPC.Document) messageObject.photoThumbsObject), "150_150_wallpaper" + action.wallpaper.id + ChatBackgroundDrawable.hash(action.wallpaper.settings), null, null, ChatBackgroundDrawable.createThumb(action.wallpaper), 0, null, action.wallpaper, 1); + wallpaperPreviewDrawable = null; } imageReceiver.setRoundRadius((int) (stickerSize / 2f)); @@ -548,12 +582,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD set = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(packName); } if (set != null) { - int months; - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { - months = ((TLRPC.TL_messageActionGiftCode) messageObject.messageOwner.action).months; - } else { - months = messageObject.messageOwner.action.months; - } + int months = messageObject.messageOwner.action.months; String monthsEmoticon; if (USE_PREMIUM_GIFT_MONTHS_AS_EMOJI_NUMBERS) { StringBuilder monthsEmoticonBuilder = new StringBuilder(); @@ -916,15 +945,33 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } + private boolean isSelfGiftCode() { + if (currentMessageObject != null && currentMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { + if (currentMessageObject.messageOwner.from_id instanceof TLRPC.TL_peerUser) { + return MessagesController.getInstance(currentAccount).getUser(currentMessageObject.messageOwner.from_id.user_id).self; + } + } + return false; + } + + private boolean isGiftCode() { + return currentMessageObject != null && currentMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionGiftCode; + } + private void openPremiumGiftPreview() { TLRPC.TL_premiumGiftOption giftOption = new TLRPC.TL_premiumGiftOption(); TLRPC.MessageAction action = currentMessageObject.messageOwner.action; giftOption.amount = action.amount; giftOption.months = action.months; giftOption.currency = action.currency; - + String slug; + if (isGiftCode()) { + slug = isSelfGiftCode() ? null : ((TLRPC.TL_messageActionGiftCode) currentMessageObject.messageOwner.action).slug; + } else { + slug = null; + } if (delegate != null) { - AndroidUtilities.runOnUIThread(() -> delegate.didOpenPremiumGift(ChatActionCell.this, giftOption, false)); + AndroidUtilities.runOnUIThread(() -> delegate.didOpenPremiumGift(ChatActionCell.this, giftOption, slug, false)); } } @@ -1159,7 +1206,13 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD if (messageObject.messageOwner.media.photo != null) { text = LocaleController.getString(R.string.AttachPhotoExpired); } else if (messageObject.messageOwner.media.document instanceof TLRPC.TL_documentEmpty || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && messageObject.messageOwner.media.document == null) { - text = LocaleController.getString(R.string.AttachVideoExpired); + if (messageObject.messageOwner.media.voice) { + text = LocaleController.getString(R.string.AttachVoiceExpired); + } else if (messageObject.messageOwner.media.round) { + text = LocaleController.getString(R.string.AttachRoundExpired); + } else { + text = LocaleController.getString(R.string.AttachVideoExpired); + } } else { text = AnimatedEmojiSpan.cloneSpans(messageObject.messageText); } @@ -1177,7 +1230,9 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL) { createGiftPremiumChannelLayouts(); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM) { - createGiftPremiumLayouts(LocaleController.getString(R.string.ActionGiftPremiumTitle), LocaleController.formatString(R.string.ActionGiftPremiumSubtitle, LocaleController.formatPluralString("Months", messageObject.messageOwner.action.months)), LocaleController.getString(R.string.ActionGiftPremiumView), giftRectSize, true); + String actionName = isGiftCode() && !isSelfGiftCode() ? LocaleController.getString("GiftPremiumUseGiftBtn", R.string.GiftPremiumUseGiftBtn) : + LocaleController.getString("ActionGiftPremiumView", R.string.ActionGiftPremiumView); + createGiftPremiumLayouts(LocaleController.getString(R.string.ActionGiftPremiumTitle), LocaleController.formatString(R.string.ActionGiftPremiumSubtitle, LocaleController.formatPluralString("Months", messageObject.messageOwner.action.months)), actionName, giftRectSize, true); } else if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { TLRPC.TL_messageActionSuggestProfilePhoto actionSuggestProfilePhoto = (TLRPC.TL_messageActionSuggestProfilePhoto) messageObject.messageOwner.action; String description; @@ -1212,11 +1267,13 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD CharSequence description; String action = null; boolean actionClickableAsImage = true; - if (!messageObject.isOutOwner() && messageObject.isWallpaperForBoth() && messageObject.isCurrentWallpaper()) { + if (messageObject.getDialogId() < 0) { + description = messageObject.messageText; + } else if (!messageObject.isOutOwner() && messageObject.isWallpaperForBoth() && messageObject.isCurrentWallpaper()) { description = messageObject.messageText; action = LocaleController.getString(R.string.RemoveWallpaperAction); actionClickableAsImage = false; - } else if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { + } else if (user != null && user.id == UserConfig.getInstance(currentAccount).clientUserId) { description = messageObject.messageText; } else { description = messageObject.messageText; @@ -1310,7 +1367,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD giftSubtitlePaint.setTextSize(dp(15)); } int subtitleWidth = giftPremiumSubtitleWidth = width; - if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { + if (currentMessageObject != null && (currentMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER && currentMessageObject.getDialogId() >= 0)) { final int recommendedWidthForTwoLines = HintView2.cutInFancyHalf(subtitle, giftSubtitlePaint); if (recommendedWidthForTwoLines < subtitleWidth && recommendedWidthForTwoLines > subtitleWidth / 5f) { subtitleWidth = recommendedWidthForTwoLines; @@ -1384,6 +1441,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } if (giftSubtitlePaint != null && giftSubtitlePaint.getColor() != textPaint.getColor()) { giftSubtitlePaint.setColor(textPaint.getColor()); + giftSubtitlePaint.linkColor = textPaint.getColor(); } } } @@ -1391,7 +1449,20 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD drawBackground(canvas, false); if (isButtonLayout(messageObject) || (messageObject != null && messageObject.type == MessageObject.TYPE_ACTION_PHOTO)) { - if (messageObject.isStoryMention()) { + if (wallpaperPreviewDrawable != null) { + canvas.save(); + canvas.translate(imageReceiver.getImageX(), imageReceiver.getImageY()); + if (clipPath == null) { + clipPath = new Path(); + } else { + clipPath.rewind(); + } + clipPath.addCircle(imageReceiver.getImageWidth() / 2f, imageReceiver.getImageHeight() / 2f, imageReceiver.getImageWidth() / 2f, Path.Direction.CW); + canvas.clipPath(clipPath); + wallpaperPreviewDrawable.setBounds(0, 0, (int) imageReceiver.getImageWidth(), (int) imageReceiver.getImageHeight()); + wallpaperPreviewDrawable.draw(canvas); + canvas.restore(); + } else if (messageObject.isStoryMention()) { long dialogId = messageObject.messageOwner.media.user_id; avatarStoryParams.storyId = messageObject.messageOwner.media.id; StoriesUtilities.drawAvatarWithStory(dialogId, canvas, imageReceiver, avatarStoryParams); @@ -1519,6 +1590,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD int oldColor = giftSubtitlePaint.getColor(); settingWallpaperPaint.setAlpha((int) (Color.alpha(oldColor) * (1f - p))); giftSubtitlePaint.setAlpha((int) (Color.alpha(oldColor) * p)); + giftSubtitlePaint.linkColor = giftSubtitlePaint.getColor(); float s = 0.8f + 0.2f * p; canvas.save(); @@ -1528,6 +1600,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD canvas.restore(); giftSubtitlePaint.setAlpha((int) (Color.alpha(oldColor) * (1f - p))); + giftSubtitlePaint.linkColor = giftSubtitlePaint.getColor(); s = 0.8f + 0.2f * (1f - p); canvas.save(); canvas.scale(s, s, settingWallpaperLayout.getWidth() / 2f, settingWallpaperLayout.getHeight() / 2f); @@ -1542,6 +1615,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD giftSubtitlePaint.setColor(oldColor); + giftSubtitlePaint.linkColor = oldColor; } else { settingWallpaperLayout.draw(canvas); canvas.save(); @@ -1679,6 +1753,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD return super.drawChild(canvas, child, drawingTime); } + private void checkLeftRightBounds() { + backgroundLeft = (int) Math.min(backgroundLeft, rect.left); + backgroundRight = (int) Math.max(backgroundRight, rect.right); + } + public void drawBackground(Canvas canvas, boolean fromParent) { if (canDrawInParent) { if (hasGradientService() && !fromParent) { @@ -1706,6 +1785,8 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } if (invalidatePath) { invalidatePath = false; + backgroundLeft = getWidth(); + backgroundRight = 0; lineWidths.clear(); final int count = textLayout == null ? 0 : textLayout.getLineCount(); final int corner = dp(11); @@ -1771,9 +1852,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD if (a == 0 || lineWidth > prevLineWidth) { rect.set(startX - cornerOffset - corner, y, startX + cornerRest, y + corner * 2); + checkLeftRightBounds(); backgroundPath.arcTo(rect, -90, 90); } else if (lineWidth < prevLineWidth) { rect.set(startX + cornerRest, y, startX + cornerRest + innerCornerRad * 2, y + innerCornerRad * 2); + checkLeftRightBounds(); backgroundPath.arcTo(rect, -90, -90); } y += height; @@ -1790,9 +1873,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD if (a == count - 1 || lineWidth > nextLineWidth) { rect.set(startX - cornerOffset - corner, y - corner * 2, startX + cornerRest, y); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 0, 90); } else if (lineWidth < nextLineWidth) { rect.set(startX + cornerRest, y - innerCornerRad * 2, startX + cornerRest + innerCornerRad * 2, y); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 180, -90); } @@ -1814,9 +1899,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD if (a == count - 1 || lineWidth > nextLineWidth) { rect.set(startX - cornerRest, y - corner * 2, startX + cornerOffset + corner, y); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 90, 90); } else if (lineWidth < nextLineWidth) { rect.set(startX - cornerRest - innerCornerRad * 2, y - innerCornerRad * 2, startX - cornerRest, y); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 90, -90); } @@ -1824,9 +1911,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD if (a == 0 || lineWidth > prevLineWidth) { rect.set(startX - cornerRest, y, startX + cornerOffset + corner, y + corner * 2); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 180, 90); } else if (lineWidth < prevLineWidth) { rect.set(startX - cornerRest - innerCornerRad * 2, y, startX - cornerRest, y + innerCornerRad * 2); + checkLeftRightBounds(); backgroundPath.arcTo(rect, 0, -90); } } @@ -1896,6 +1985,30 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } + @Override + public int getBoundsLeft() { + if (isButtonLayout(currentMessageObject)) { + return (getWidth() - giftRectSize) / 2; + } + int left = backgroundLeft; + if (imageReceiver != null && imageReceiver.getVisible()) { + left = Math.min((int) imageReceiver.getImageX(), left); + } + return left; + } + + @Override + public int getBoundsRight() { + if (isButtonLayout(currentMessageObject)) { + return (getWidth() + giftRectSize) / 2; + } + int right = backgroundRight; + if (imageReceiver != null && imageReceiver.getVisible()) { + right = Math.max((int) imageReceiver.getImageX2(), right); + } + return right; + } + public boolean hasGradientService() { return overrideBackgroundPaint == null && (themeDelegate != null ? themeDelegate.hasGradientService() : Theme.hasGradientService()); } @@ -1987,7 +2100,7 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD return Theme.getColor(key, themeDelegate); } - private Paint getThemedPaint(String paintKey) { + protected Paint getThemedPaint(String paintKey) { Paint paint = themeDelegate != null ? themeDelegate.getPaint(paintKey) : null; return paint != null ? paint : Theme.getThemePaint(paintKey); } @@ -2031,6 +2144,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD } } + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == wallpaperPreviewDrawable || super.verifyDrawable(who); + } + public boolean isFloating() { return false; } 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 0396fb8d4..594f0761e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -9,6 +9,7 @@ package org.telegram.ui.Cells; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -34,6 +35,7 @@ import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; @@ -81,10 +83,13 @@ import android.view.animation.OvershootInterpolator; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; 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; @@ -134,6 +139,7 @@ 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; @@ -151,6 +157,7 @@ import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.MsgClockDrawable; import org.telegram.ui.Components.Point; import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayMessageCell; +import org.telegram.ui.Components.Premium.boosts.cells.msg.GiveawayResultsMessageCell; import org.telegram.ui.Components.QuoteHighlight; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgress2; @@ -180,6 +187,7 @@ import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.SecretMediaViewer; import org.telegram.ui.Stories.StoriesUtilities; import org.telegram.ui.Stories.StoryViewer; +import org.telegram.ui.Stories.recorder.CaptionContainerView; import org.telegram.ui.Stories.recorder.DominantColors; import java.io.File; @@ -201,8 +209,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean flipImage; private boolean visibleOnScreen = true; public boolean shouldCheckVisibleOnScreen; - float parentBoundsTop; - int parentBoundsBottom; + public float parentBoundsTop; + public int parentBoundsBottom; public ExpiredStoryView expiredStoryView; private boolean skipFrameUpdate; @@ -254,7 +262,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate invalidate(); } else if (id == NotificationCenter.didUpdatePremiumGiftStickers) { MessageObject messageObject = currentMessageObject; - if (messageObject != null && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { + if (messageObject != null && (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults)) { setMessageObject(messageObject, currentMessagesGroup, pinnedBottom, pinnedTop); } } @@ -570,7 +578,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return null; } - default boolean needPlayMessage(MessageObject messageObject, boolean muted) { + default boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { return false; } @@ -755,6 +763,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean groupPhotoInvisible; public final ReactionsLayoutInBubble reactionsLayoutInBubble = new ReactionsLayoutInBubble(this); public final GiveawayMessageCell giveawayMessageCell = new GiveawayMessageCell(this); + public final GiveawayResultsMessageCell giveawayResultsMessageCell = new GiveawayResultsMessageCell(this); private boolean invalidateSpoilersParent; @@ -802,6 +811,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private Drawable locationLoadingThumb; private Drawable gradientDrawable; private Paint gradientLoadingPaint; + private CaptionContainerView.PeriodDrawable oncePeriod; + private Paint onceClearPaint; + private RLottieDrawable onceFire; + private Paint onceRadialPaint; + private Paint onceRadialStrokePaint; + private int onceRadialPaintColor; private boolean disallowLongPress; private float lastTouchX; @@ -815,7 +830,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean checkBoxAnimationInProgress; private float checkBoxAnimationProgress; private long lastCheckBoxAnimationTime; - private int checkBoxTranslation; + public int checkBoxTranslation; public boolean linkPreviewAbove; private boolean isSmallImage; @@ -1311,6 +1326,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private Drawable linkPreviewSelector; public int linkPreviewSelectorColor; + @Nullable private ChatMessageCellDelegate delegate; private MessageBackgroundDrawable backgroundDrawable; @@ -1524,6 +1540,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + public Theme.ResourcesProvider getResourcesProvider() { + return resourcesProvider; + } + private void createPollUI() { if (pollAvatarImages != null) { return; @@ -2313,13 +2333,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND) { if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { - delegate.needPlayMessage(currentMessageObject, false); + delegate.needPlayMessage(this, currentMessageObject, false); } else { MediaController.getInstance().pauseMessage(currentMessageObject); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && drawImageButton) { if (buttonState == -1) { - if (SharedConfig.isAutoplayGifs()) { + if (SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview) { delegate.didPressImage(this, lastTouchX, lastTouchY); } else { buttonState = 2; @@ -2855,7 +2875,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isSendError()) { imagePressed = false; result = false; - } else if (currentMessageObject.type == MessageObject.TYPE_GIF && buttonState == -1 && SharedConfig.isAutoplayGifs() && photoImage.getAnimation() == null) { + } else if (currentMessageObject.type == MessageObject.TYPE_GIF && buttonState == -1 && SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview && photoImage.getAnimation() == null) { imagePressed = false; result = false; } @@ -2933,7 +2953,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int offset = AndroidUtilities.dp(27); area2 = x >= buttonX + offset && x <= buttonX + offset + side && y >= buttonY + offset && y <= buttonY + offset + side; } - if (!area2 && (currentMessageObject == null || !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed)) { + if (!area2 && (currentMessageObject == null || !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isVoice() || currentMessageObject.isMediaSpoilersRevealed)) { if (buttonState == 0 || buttonState == 1 || buttonState == 2) { area = x >= buttonX - AndroidUtilities.dp(12) && x <= buttonX - AndroidUtilities.dp(12) + backgroundWidth && y >= (drawInstantView ? buttonY : namesOffset + mediaOffsetY) && y <= (drawInstantView ? buttonY + side : namesOffset + mediaOffsetY + AndroidUtilities.dp(82)); } else { @@ -3222,7 +3242,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate @Override public boolean onTouchEvent(MotionEvent event) { - if (currentMessageObject == null || !delegate.canPerformActions() || animationRunning) { + if (currentMessageObject == null || delegate != null && !delegate.canPerformActions() || animationRunning) { if (currentMessageObject != null && currentMessageObject.preview) { return checkTextSelection(event); } else { @@ -3325,6 +3345,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!result) { result = giveawayMessageCell.checkMotionEvent(event); } + if (!result) { + result = giveawayResultsMessageCell.checkMotionEvent(event); + } if (event.getAction() == MotionEvent.ACTION_CANCEL) { spoilerPressed = null; @@ -3855,7 +3878,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } - if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { + if (overridenDuration >= 0) { + duration = overridenDuration; + } else if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { duration = Math.max(0, duration - currentMessageObject.audioProgressSec); } if (lastTime != duration) { @@ -3886,7 +3911,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate double duration = 0; if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { - if (!MediaController.getInstance().isPlayingMessage(currentMessageObject)) { + if (overridenDuration >= 0) { + duration = overridenDuration; + } else if (!MediaController.getInstance().isPlayingMessage(currentMessageObject)) { for (int a = 0; a < documentAttach.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { @@ -3921,6 +3948,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private long overridenDuration = -1; + public void overrideDuration(long duration) { + overridenDuration = duration; + } + public void setFullyDraw(boolean draw) { fullyDraw = draw; } @@ -4071,7 +4103,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate didPressButton(true, false); } else { if (!MediaController.getInstance().isPlayingMessage(currentMessageObject) || MediaController.getInstance().isMessagePaused()) { - delegate.needPlayMessage(currentMessageObject, false); + delegate.needPlayMessage(this, currentMessageObject, false); } else { MediaController.getInstance().pauseMessage(currentMessageObject); } @@ -4344,6 +4376,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private AudioVisualizerDrawable overridenAudioVisualizer; + public void overrideAudioVisualizer(AudioVisualizerDrawable audioVisualizerDrawable) { + this.overridenAudioVisualizer = audioVisualizerDrawable; + } + public TLRPC.User getCurrentUser() { return currentUser; } @@ -4527,6 +4564,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } giveawayMessageCell.onAttachedToWindow(); + giveawayResultsMessageCell.onAttachedToWindow(); replyImageReceiver.onAttachedToWindow(); locationImageReceiver.onAttachedToWindow(); blurredPhotoImage.onAttachedToWindow(); @@ -4558,6 +4596,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.onDetachedFromWindow(); blurredPhotoImage.onDetachedFromWindow(); giveawayMessageCell.onDetachedFromWindow(); + giveawayResultsMessageCell.onDetachedFromWindow(); AnimatedEmojiSpan.release(this, animatedEmojiDescriptionStack); AnimatedEmojiSpan.release(this, animatedEmojiReplyStack); @@ -4777,8 +4816,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate hasNewLineForTime = false; flipImage = false; isThreadPost = isThreadChat && messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.channel_post != 0 && messageObject.messageOwner.reply_to == null; - isAvatarVisible = !isThreadPost && isChat && !messageObject.isOutOwner() && messageObject.needDrawAvatar() && (currentPosition == null || currentPosition.edge); - boolean drawAvatar = isChat && !isThreadPost && !messageObject.isOutOwner() && messageObject.needDrawAvatar(); + isAvatarVisible = needDrawAvatar() && (currentPosition == null || currentPosition.edge); + boolean drawAvatar = needDrawAvatar(); if (messageObject.customAvatarDrawable != null || messageObject.forceAvatar) { isAvatarVisible = true; drawAvatar = true; @@ -4947,7 +4986,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageIdChanged || messageObject.reactionsChanged || wasPlayingRound != isPlayingRound) { messageObject.reactionsChanged = false; - if (!messageObject.isExpiredStory() && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0))) { + if (messageObject.shouldDrawReactions() && !messageObject.isExpiredStory() && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0))) { boolean isSmall = !messageObject.shouldDrawReactionsInLayout(); if (currentPosition != null) { reactionsLayoutInBubble.setMessage(groupedMessages.findPrimaryMessageObject(), !messageObject.shouldDrawReactionsInLayout(), resourcesProvider); @@ -5112,7 +5151,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; drawName = false; - } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveaway() || messageObject.isSponsored()) { + } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveawayOrGiveawayResults() || messageObject.isSponsored()) { drawForwardedName = !isRepliesChat; int maxWidth; @@ -5160,7 +5199,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate TLRPC.Document androidThemeDocument = null; TL_stories.StoryItem storyItem = null; TLRPC.ThemeSettings androidThemeSettings = null; - if (messageObject.isGiveaway()) { + if (messageObject.isGiveawayOrGiveawayResults()) { hasLinkPreview = true; } @@ -5185,7 +5224,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } - } else if (messageObject.isGiveaway()) { + } else if (messageObject.isGiveawayOrGiveawayResults()) { drawInstantView = true; drawInstantViewType = 19; } else if ("telegram_channel_boost".equals(webpageType)) { @@ -5357,6 +5396,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photosCountLayout = new StaticLayout(str, Theme.chat_durationPaint, photosCountWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } + if (messageObject.isRepostPreview) { + drawInstantView = false; + } backgroundWidth = maxWidth; if (hasLinkPreview && !linkPreviewAbove || hasGamePreview || hasInvoicePreview || maxWidth - messageObject.lastLineWidth < timeMore) { backgroundWidth = Math.max(backgroundWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(31); @@ -5376,6 +5418,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate setMessageObjectInternal(messageObject); giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); + giveawayResultsMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? AndroidUtilities.dp(10) : 0); if (messageObject.isSponsored()) { @@ -5385,7 +5428,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (!reactionsLayoutInBubble.isSmall) { - reactionsLayoutInBubble.measure(messageObject.isGiveaway() ? giveawayMessageCell.getMeasuredWidth() : maxWidth, Gravity.LEFT); + int availableWidth = maxWidth; + if (messageObject.isGiveaway()) { + availableWidth = giveawayMessageCell.getMeasuredWidth(); + } else if (messageObject.isGiveawayResults()) { + availableWidth = giveawayResultsMessageCell.getMeasuredWidth(); + } + reactionsLayoutInBubble.measure(availableWidth, Gravity.LEFT); if (!reactionsLayoutInBubble.isEmpty) { reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + AndroidUtilities.dp(8); if (reactionsLayoutInBubble.width > backgroundWidth) { @@ -5416,7 +5465,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (hasLinkPreview || hasGamePreview || hasInvoicePreview) { int linkPreviewMaxWidth; - if (AndroidUtilities.isTablet()) { + if (currentMessageObject.isRepostPreview) { + linkPreviewMaxWidth = currentMessageObject.getMaxMessageTextWidth(); + } else if (AndroidUtilities.isTablet()) { linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80 + (drawAvatar ? 52 : 0)); } else { linkPreviewMaxWidth = getParentWidth() - AndroidUtilities.dp(80 + (drawAvatar ? 52 : 0)); @@ -5608,7 +5659,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate totalHeight += giveawayMessageCell.getMeasuredHeight(); linkPreviewHeight += giveawayMessageCell.getMeasuredHeight(); + totalHeight += giveawayResultsMessageCell.getMeasuredHeight(); + linkPreviewHeight += giveawayResultsMessageCell.getMeasuredHeight(); maxChildWidth = Math.max(maxChildWidth, giveawayMessageCell.getMeasuredWidth()); + maxChildWidth = Math.max(maxChildWidth, giveawayResultsMessageCell.getMeasuredWidth()); if (site_name != null) { try { @@ -5674,11 +5728,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate titleCs = Emoji.replaceEmoji(title, Theme.chat_replyNamePaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); } catch (Exception ignore) { } + int maxLines = 4; + if (currentMessageObject.isRepostPreview) { + maxLines = 1; + } if (!isSmallImage) { - titleLayout = StaticLayoutEx.createStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 4); + titleLayout = StaticLayoutEx.createStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, maxLines); } else { restLines = restLinesCount; - titleLayout = generateStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - smallImageSide - smallSideMargin, restLinesCount, 4); + titleLayout = generateStaticLayout(titleCs, Theme.chat_replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - smallImageSide - smallSideMargin, restLinesCount, maxLines); restLinesCount -= titleLayout.getLineCount(); } @@ -5755,11 +5813,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate boolean allowAllLines = site_name != null && site_name.toString().toLowerCase().equals("twitter"); CharSequence text = overrideDescrption != null ? overrideDescrption : messageObject.linkDescription; boolean isRTL = AndroidUtilities.isRTL(text); + int maxLines = allowAllLines ? 100 : (currentMessageObject.isRepostPreview ? 3 : 6); if (restLinesCount == 3 && !isSmallImage) { - descriptionLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, allowAllLines ? 100 : 6); + descriptionLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, maxLines); } else { restLines = restLinesCount; - descriptionLayout = generateStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide : 0), linkPreviewMaxWidth - smallImageSide - (isRTL ? 0 : smallSideMargin), restLinesCount, allowAllLines ? 100 : 6); + descriptionLayout = generateStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide + 2 * smallSideMargin : 0), linkPreviewMaxWidth - smallImageSide - 2 * smallSideMargin, restLinesCount, maxLines); } animatedEmojiDescriptionStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiDescriptionStack, descriptionLayout); @@ -5838,7 +5897,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate isSmallImage = smallImage = false; documentAttachType = DOCUMENT_ATTACH_TYPE_ROUND; } else if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId())) { - if (!messageObject.isGame() && !SharedConfig.isAutoplayGifs()) { + if (!messageObject.isGame() && !(SharedConfig.isAutoplayGifs() && !messageObject.isRepostPreview)) { messageObject.gifState = 1; } photoImage.setAllowStartAnimation(messageObject.gifState != 1); @@ -6226,7 +6285,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { photoImage.setNeedsQualityThumb(true); photoImage.setShouldGenerateQualityThumb(true); - if (!isSmallImage && SharedConfig.isAutoplayVideo() && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && ( + if (!isSmallImage && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && ( (currentMessageObject.mediaExists || currentMessageObject.attachPathExists) || messageObject.canStreamVideo() && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) )) { @@ -6253,7 +6312,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } String filter = currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter; - if (messageObject.mediaExists || autoDownload) { + if ((messageObject.mediaExists || autoDownload) && !currentMessageObject.isRepostPreview) { autoPlayingMedia = true; TLRPC.VideoSize videoSize = MessageObject.getDocumentVideoThumb(document); if (!messageObject.mediaExists && videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { @@ -6358,11 +6417,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } - if (!hasInvoicePreview && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { linkPreviewHeight += AndroidUtilities.dp(6); totalHeight += AndroidUtilities.dp(6); } - if (!hasInvoicePreview && !currentMessageObject.isGiveaway() && ( + if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults() && ( currentPhotoObject != null || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO ) && (authorLayout != null || descriptionLayout != null || titleLayout != null || siteNameLayout != null)) { linkPreviewHeight += AndroidUtilities.dp(2.66f); @@ -6928,7 +6987,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.isImportedForward() && messageObject.messageOwner.fwd_from.from_id == null) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); + 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); } mediaBackground = isMedia = messageObject.type != MessageObject.TYPE_FILE; drawImageButton = true; @@ -6938,7 +6997,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int photoHeight = 0; int additionHeight = 0; - if (messageObject.gifState != 2 && !SharedConfig.isAutoplayGifs() && (messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO)) { + if (messageObject.gifState != 2 && !(SharedConfig.isAutoplayGifs() && !messageObject.isRepostPreview) && (messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_ROUND_VIDEO)) { messageObject.gifState = 1; } @@ -7708,7 +7767,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { w -= AndroidUtilities.dp(9); } - if ((isChat && !isThreadPost && !m.isOutOwner() || m.forceAvatar) && m.needDrawAvatar() && (rowPosition == null || rowPosition.edge)) { + if (((isChat || m.isRepostPreview) && !isThreadPost && !m.isOutOwner() || m.forceAvatar) && m.needDrawAvatar() && (rowPosition == null || rowPosition.edge)) { w -= AndroidUtilities.dp(48); } w += getAdditionalWidthForPosition(rowPosition); @@ -7907,7 +7966,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentPhotoObjectThumb.size = -1; } - if (SharedConfig.isAutoplayVideo() && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && messageObject.type == MessageObject.TYPE_VIDEO && !messageObject.needDrawBluredPreview() && + if (SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && (!currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || currentMessageObject.revealingMediaSpoilers) && messageObject.type == MessageObject.TYPE_VIDEO && !messageObject.needDrawBluredPreview() && ((currentMessageObject.mediaExists || currentMessageObject.attachPathExists) || messageObject.canStreamVideo() && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject)) ) { if (currentPosition != null) { @@ -7917,6 +7976,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + final int cacheType = currentMessageObject.shouldEncryptPhotoOrVideo() ? ImageLoader.CACHE_TYPE_ENCRYPTED : ImageLoader.CACHE_TYPE_NONE; if (autoPlayingMedia) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); @@ -7943,7 +8003,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.clearImage(); } } else if (messageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { - photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, cacheType); } else if (messageObject.type == MessageObject.TYPE_PHOTO) { if (messageObject.useCustomPhoto) { photoImage.setImageBitmap(getResources().getDrawable(R.drawable.theme_preview_image)); @@ -7957,11 +8017,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoExist = false; } if (photoExist || !currentMessageObject.loadingCancelled && DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, cacheType); } else { photoNotSet = true; if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { - photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(null, null, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, currentMessageObject, cacheType); } else { photoImage.setImageBitmap((Drawable) null); } @@ -7993,19 +8053,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setCrossfadeDuration(250); } if (localFile == 0 && videoSize != null && (currentPhotoObject == null || currentPhotoObjectThumb == null)) { - 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, 0); + 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); } else { - photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForDocument(document), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, document.size, null, messageObject, cacheType); } } } else if (localFile == 1) { - photoImage.setImage(ImageLocation.getForPath(messageObject.isSendError() ? null : messageObject.messageOwner.attachPath), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForPath(messageObject.isSendError() ? null : messageObject.messageOwner.attachPath), null, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } else { 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, 0); + 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); } @@ -8019,19 +8079,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setCrossfadeWithOldImage(true); photoImage.setCrossfadeDuration(250); } - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } } } else { if (messageObject.videoEditedInfo != null && messageObject.type == MessageObject.TYPE_ROUND_VIDEO && !currentMessageObject.needDrawBluredPreview()) { - photoImage.setImage(ImageLocation.getForPath(messageObject.videoEditedInfo.originalPath), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(ImageLocation.getForPath(messageObject.videoEditedInfo.originalPath), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); photoImage.setMediaStartEndTime(currentMessageObject.videoEditedInfo.startTime / 1000, currentMessageObject.videoEditedInfo.endTime / 1000); } else { if (!messageIdChanged && !currentMessageObject.needDrawBluredPreview()) { photoImage.setCrossfadeWithOldImage(true); photoImage.setCrossfadeDuration(250); } - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, cacheType); } } } @@ -8281,7 +8341,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate botButtonsByPosition.clear(); botButtonsLayout = null; } - if (!messageObject.isRestrictedMessage && currentPosition == null && (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) && !messageObject.hasExtendedMedia()) { + if (!messageObject.isRestrictedMessage && !messageObject.isRepostPreview && currentPosition == null && (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) && !messageObject.hasExtendedMedia()) { int rows; if (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) { @@ -8761,6 +8821,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate timePressed = false; gamePreviewPressed = false; giveawayMessageCell.setButtonPressed(false); + giveawayResultsMessageCell.setButtonPressed(false); if (pressedVoteButton != -1 || pollHintPressed || psaHintPressed || instantPressed || otherPressed || commentButtonPressed) { instantPressed = commentButtonPressed = false; @@ -8883,6 +8944,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject == null) { return; } + if (invalidateCallback != null) { + invalidateCallback.run(); + return; + } super.invalidate(); if ((invalidatesParent || currentMessagesGroup != null && invalidateParentForce()) && getParent() != null) { View parent = (View) getParent(); @@ -8897,12 +8962,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private Runnable invalidateCallback; + public void setInvalidateCallback(Runnable callback) { + invalidateCallback = callback; + } + @Override public void invalidate(int l, int t, int r, int b) { if (currentMessageObject == null) { return; } + if (invalidateCallback != null) { + invalidateCallback.run(); + return; + } super.invalidate(l, t, r, b); if (invalidatesParent) { if (getParent() != null) { @@ -8996,6 +9070,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate requestDisallowInterceptTouchEvent(false); } + @Override + public boolean isSeekBarDragAllowed() { + return currentMessageObject == null || !currentMessageObject.isVoiceOnce(); + } + + @Override + public boolean reverseWaveform() { + return currentMessageObject != null && currentMessageObject.isVoiceOnce(); + } + @Override public void onSeekBarDrag(float progress) { if (currentMessageObject == null) { @@ -9045,7 +9129,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ) || MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber <= 0 && - !MessagesController.getInstance(currentAccount).premiumLocked && + !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && !currentMessageObject.isOutOwner() && ( currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60 @@ -9053,7 +9137,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ) && ( currentMessageObject.isVoice() && useSeekBarWaveform || currentMessageObject.isRoundVideo() - ) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) + ) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) && + (currentMessageObject.messageOwner.media == null || currentMessageObject.messageOwner.media.ttl_seconds == 0) ); updateSeekBarWaveformWidth(null); } @@ -9278,7 +9363,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if ( currentMessageObject.hasCodeAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) || currentMessageObject.hasQuoteAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) - || currentMessageObject.isGiveaway() + || currentMessageObject.isGiveawayOrGiveawayResults() ) { newLineForTime = true; newLineForTimeDp = 18; @@ -9611,7 +9696,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public void setMessageObject(MessageObject messageObject, MessageObject.GroupedMessages groupedMessages, boolean bottomNear, boolean topNear) { - if (attachedToWindow) { + if (attachedToWindow && !frozen) { setMessageContent(messageObject, groupedMessages, bottomNear, topNear); } else { messageObjectToSet = messageObject; @@ -9621,6 +9706,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + private boolean frozen; + public void freezeCell(boolean freeze) { + this.frozen = freeze; + if (!frozen && messageObjectToSet != null && attachedToWindow) { + messageObjectToSet.animateComments = false; + setMessageContent(messageObjectToSet, groupedMessagesToSet, bottomNearToSet, topNearToSet); + messageObjectToSet = null; + groupedMessagesToSet = null; + } + } + private int getAdditionalWidthForPosition(MessageObject.GroupedMessagePosition position) { int w = 0; if (position != null) { @@ -9831,7 +9927,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate inLayout = false; } updateSelectionTextPosition(); - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight + keyboardHeight); + setMeasuredDimension( + isWidthAdaptive() ? getBoundsRight() - getBoundsLeft() : MeasureSpec.getSize(widthMeasureSpec), + totalHeight + keyboardHeight + ); } public void forceResetMessageObject() { @@ -9907,7 +10006,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isAnyKindOfSticker()) { timeX = Math.max(AndroidUtilities.dp(26), timeX); } - if (isAvatarVisible) { + if (isAvatarVisible && !isWidthAdaptive()) { timeX += AndroidUtilities.dp(48); } if (currentPosition != null && currentPosition.leftSpanOffset != 0) { @@ -9928,7 +10027,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isAnyKindOfSticker()) { timeX = Math.max(0, timeX); } - if (isAvatarVisible) { + if (isAvatarVisible && !isWidthAdaptive()) { timeX += AndroidUtilities.dp(48); } if (shouldDrawTimeOnMedia()) { @@ -9951,7 +10050,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (isAvatarVisible) { - avatarImage.setImageCoords(AndroidUtilities.dp(6), avatarImage.getImageY(), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + avatarImage.setImageCoords(dp(currentMessageObject.isRepostPreview ? 15 : 6), avatarImage.getImageY(), dp(currentMessageObject.isRepostPreview ? 36 : 42), dp(currentMessageObject.isRepostPreview ? 36 : 42)); } if (currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && currentUnlockString != null) { @@ -9980,7 +10079,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += AndroidUtilities.dp(44); } } else { @@ -9995,16 +10094,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(57); buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); + } else if (needDrawAvatar()) { + seekBarX = AndroidUtilities.dp(114); + buttonX = AndroidUtilities.dp(71); + timeAudioX = AndroidUtilities.dp(124); } else { - if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { - seekBarX = AndroidUtilities.dp(114); - buttonX = AndroidUtilities.dp(71); - timeAudioX = AndroidUtilities.dp(124); - } else { - seekBarX = AndroidUtilities.dp(66); - buttonX = AndroidUtilities.dp(23); - timeAudioX = AndroidUtilities.dp(76); - } + seekBarX = AndroidUtilities.dp(66); + buttonX = AndroidUtilities.dp(23); + timeAudioX = AndroidUtilities.dp(76); } if (hasLinkPreview) { seekBarX += AndroidUtilities.dp(10); @@ -10077,7 +10174,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); } else { - if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { seekBarX = AndroidUtilities.dp(113); buttonX = AndroidUtilities.dp(71); timeAudioX = AndroidUtilities.dp(124); @@ -10102,7 +10199,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isOutOwner()) { buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); } else { - if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { buttonX = AndroidUtilities.dp(71); } else { buttonX = AndroidUtilities.dp(23); @@ -10118,7 +10215,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int x; if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); - } else if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + } else if (needDrawAvatar()) { x = AndroidUtilities.dp(72); } else { x = AndroidUtilities.dp(23); @@ -10148,7 +10245,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); } } else { - if (isChat && isAvatarVisible && !isPlayingRound) { + if ((isChat || currentMessageObject.isRepostPreview) && isAvatarVisible && !isPlayingRound) { x = AndroidUtilities.dp(63); } else { x = AndroidUtilities.dp(15); @@ -10189,7 +10286,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public boolean needDelayRoundProgressDraw() { - return (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && MediaController.getInstance().isPlayingMessage(currentMessageObject); + return (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) && currentMessageObject != null && currentMessageObject.type != MessageObject.TYPE_ROUND_VIDEO && MediaController.getInstance().isPlayingMessage(currentMessageObject); } public void drawRoundProgress(Canvas canvas) { @@ -10419,7 +10516,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate imageDrawn = false; radialProgress.setCircleCrossfadeColor(-1, 0.0f, 1.0f); - if (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isGiveaway()) { + if (currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isGiveawayOrGiveawayResults()) { layoutTextXY(false); if (!enterTransitionInProgress && currentMessageObject != null && !currentMessageObject.preview) { if (!drawForBlur && animatedEmojiStack != null && ((currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty()) || (transitionParams.animateOutTextBlocks != null && !transitionParams.animateOutTextBlocks.isEmpty()))) { @@ -10512,7 +10609,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.save(); canvas.scale(-1f, 1, photoImage.getCenterX(), photoImage.getCenterY()); if (allowDrawPhotoImage()) { - imageDrawn = photoImage.draw(canvas); + imageDrawn = drawPhotoImage(canvas); } else { imageDrawn = true; } @@ -10522,7 +10619,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.restore(); } else { if (allowDrawPhotoImage()) { - imageDrawn = photoImage.draw(canvas); + imageDrawn = drawPhotoImage(canvas); } else { imageDrawn = true; } @@ -10587,7 +10684,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { - if (drawPhotoImage && photoImage.getVisible() && !hasGamePreview && !currentMessageObject.needDrawBluredPreview() && !currentMessageObject.preview && !isSmallImage) { + if (drawPhotoImage && !currentMessageObject.isRepostPreview && photoImage.getVisible() && !hasGamePreview && !currentMessageObject.needDrawBluredPreview() && !currentMessageObject.preview && !isSmallImage) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha)); setDrawableBounds(Theme.chat_msgMediaMenuDrawable, otherX = (int) (photoImage.getImageX() + photoImage.getImageWidth() - AndroidUtilities.dp(14)), otherY = (int) (photoImage.getImageY() + AndroidUtilities.dp(8.1f))); @@ -10615,6 +10712,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); + radialProgress.iconScale = 1f; radialProgress.draw(canvas); canvas.save(); @@ -10698,7 +10796,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate radialProgress.setProgressColor(getThemedColor(isDrawSelectionBackground() || buttonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } AudioVisualizerDrawable audioVisualizerDrawable; - if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { + if (overridenAudioVisualizer != null) { + audioVisualizerDrawable = overridenAudioVisualizer; + } else if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { audioVisualizerDrawable = Theme.getCurrentAudiVisualizerDrawable(); } else { audioVisualizerDrawable = Theme.getAnimatedOutAudioVisualizerDrawable(currentMessageObject); @@ -10715,7 +10815,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!enterTransitionInProgress && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); - radialProgress.draw(canvas); + radialProgress.iconScale = 1f; + drawVoiceOnce(canvas, seekBarWaveform == null ? 1f : 1f - seekBarWaveform.explosionRate, () -> radialProgress.draw(canvas)); } int seekBarX = this.seekBarX; @@ -11128,6 +11229,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animator.start(); } + public boolean drawingToBitmap; + private void drawBlurredPhoto(Canvas canvas) { if (currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress == 1f) { return; @@ -11162,7 +11265,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaSpoilerEffect2 != null) { canvas.translate(photoImage.getImageX(), photoImage.getImageY()); - mediaSpoilerEffect2.draw(canvas, this, (int) photoImage.getImageWidth(), (int) photoImage.getImageHeight(), photoImage.getAlpha()); + mediaSpoilerEffect2.draw(canvas, this, (int) photoImage.getImageWidth(), (int) photoImage.getImageHeight(), photoImage.getAlpha(), drawingToBitmap); canvas.restore(); } else { int sColor = Color.WHITE; @@ -11187,6 +11290,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private void updateReactionLayoutPosition() { + if (!currentMessageObject.shouldDrawReactions()) { + return; + } if (!reactionsLayoutInBubble.isEmpty && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { if (currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.isAnimatedEmoji() || currentMessageObject.isAnyKindOfSticker()) { if (currentMessageObject.isOutOwner()) { @@ -11239,6 +11345,99 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + public void drawVoiceOnce(Canvas canvas, float progress, Runnable drawRadialProgress) { + if (currentMessageObject != null && currentMessageObject.isVoiceOnce()) { + final float scale = progress; + final float rcx = radialProgress.progressRect.centerX() + (float) Math.cos(AndroidUtilities.lerp(190, 45, scale) / 180f * Math.PI) * dp(22.6274f); + final float rcy = radialProgress.progressRect.centerY() + (float) Math.sin(AndroidUtilities.lerp(190, 45, scale) / 180f * Math.PI) * dp(22.6274f); + + AndroidUtilities.rectTmp.set(radialProgress.progressRect); + AndroidUtilities.rectTmp.inset(-dp(1), -dp(1)); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); + radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); + radialProgress.iconScale = scale; + drawRadialProgress.run(); + if (onceClearPaint == null) { + onceClearPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + onceClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + if (scale < 1f) { + canvas.saveLayerAlpha(radialProgress.progressRect, 0xFF, Canvas.ALL_SAVE_FLAG); + 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) { + onceFire = new RLottieDrawable(R.raw.fire_once, "fire_once", dp(32), dp(32), true, null); + onceFire.setMasterParent(this); + onceFire.setAllowDecodeSingleFrame(true); + onceFire.setAutoRepeat(1); + onceFire.start(); + } + onceFire.setBounds( + (int) radialProgress.progressRect.left, + (int) radialProgress.progressRect.top, + (int) radialProgress.progressRect.right, + (int) radialProgress.progressRect.bottom + ); + if (onceRadialPaint == null) { + onceRadialPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + 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)); + } + radialProgress.mediaActionDrawable.applyShaderMatrix(false); + onceRadialPaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); + onceRadialStrokePaint.setShader(radialProgress.mediaActionDrawable.paint2.getShader()); + onceFire.draw(canvas, onceRadialPaint); + canvas.restore(); + + onceRadialStrokePaint.setAlpha((int) (0xFF * (1f - scale))); + onceRadialStrokePaint.setStrokeWidth(dp(1.66f)); + rect.set(radialProgress.progressRect); + rect.inset(dp(3), dp(3)); + canvas.drawArc(rect, -90, -360 * (1f - seekBarWaveform.explodeProgress), false, onceRadialStrokePaint); + if (timerParticles == null) { + timerParticles = new TimerParticles(); + } + timerParticles.draw(canvas, onceRadialStrokePaint, rect, -360 * (1f - seekBarWaveform.explodeProgress), 1f - scale); + } else if (onceFire != null) { + onceFire.recycle(true); + onceFire = null; + if (timerParticles != null) { + timerParticles = null; + } + } + canvas.drawCircle(rcx, rcy, dp(10 + scale * 1.5f) * scale, onceClearPaint); + canvas.restore(); + + 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 * scale; + oncePeriod.setTextSize(10 * scale); + canvas.saveLayerAlpha(rcx - dp(10), rcy - dp(10), rcx + dp(10), rcy + dp(10), 0xFF, Canvas.ALL_SAVE_FLAG); + canvas.drawCircle(rcx, rcy, dp(10) * scale, radialProgress.circlePaint); + oncePeriod.setClear(AndroidUtilities.computePerceivedBrightness(radialProgress.circlePaint.getColor()) > .8f); + oncePeriod.setCenterXY(rcx, rcy); + oncePeriod.draw(canvas, scale); + canvas.restore(); + } else { + drawRadialProgress.run(); + } + } + public void drawLinkPreview(Canvas canvas, float alpha) { if (!currentMessageObject.isSponsored() && !hasLinkPreview && !hasGamePreview && !hasInvoicePreview) { return; @@ -11298,10 +11497,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } Theme.chat_replyNamePaint.setColor(linkLine.check(currentMessageObject, currentUser, currentChat, resourcesProvider, ReplyMessageLine.TYPE_LINK)); + final boolean drawPhotoImageBefore = drawInstantView && (drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 && drawInstantViewType != 18) || drawInstantViewType == 6 && imageBackgroundColor != 0; + final boolean drawPhotoImageAfter = !drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 18 || isSmallImage; + boolean restore = false; boolean drawInstantButtonInside = false; boolean loading = delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_INSTANT); - if (!hasInvoicePreview && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { drawInstantButtonInside = true; if (linkPreviewBounce == null) { @@ -11315,7 +11517,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate AndroidUtilities.rectTmp.set(linkX, linkPreviewY - AndroidUtilities.dp(6), linkX + width, linkPreviewY + linkPreviewHeight + (drawInstantButtonInside && drawInstantView ? AndroidUtilities.dp(42) : 0)); linkLine.setLoading(loading); float rad = (float) Math.floor(SharedConfig.bubbleRadius / (currentMessageObject.isSponsored() ? 2f : 3f)); - linkLine.drawBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); + linkLine + .offsetEmoji(0, drawPhotoImageBefore ? (1f - isSmallImage()) * (dp(18) + photoImage.getImageHeight() + (siteNameLayout != null ? siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1) : 0)) : 0) + .drawBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); int rippleColor = linkLine.getBackgroundColor(); if (linkPreviewSelector == null) { @@ -11351,7 +11555,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate linkPreviewY += currentMessageObject.textHeight + AndroidUtilities.dp(4); } - if (drawPhotoImage && drawInstantView && (drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 && drawInstantViewType != 18) || drawInstantViewType == 6 && imageBackgroundColor != 0) { + if (drawPhotoImage && drawPhotoImageBefore) { if (isSmallImage) { if (transitionParams != null && transitionParams.animateSmallImage) { float diff = (linkPreviewY != startY ? AndroidUtilities.dp(2) : 0) + transitionParams.photoImageFromHeight + AndroidUtilities.dp(6); @@ -11579,7 +11783,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); } - if (drawPhotoImage && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1 || drawInstantViewType == 18 || isSmallImage)) { + if (drawPhotoImage && drawPhotoImageAfter) { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } @@ -11697,6 +11901,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.restore(); } giveawayMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); + giveawayResultsMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); if (drawInstantView) { Drawable instantDrawable; @@ -11836,12 +12041,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private boolean shouldDrawMenuDrawable() { - return (currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) && !hasLinkPreview; + return (currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) && !hasLinkPreview && (currentMessageObject == null || !currentMessageObject.isRepostPreview); } private void drawBotButtons(Canvas canvas, ArrayList botButtons, int alpha) { int addX; - if (currentMessageObject.isOutOwner()) { + if (currentMessageObject != null && currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - AndroidUtilities.dp(10); } else { addX = backgroundDrawableLeft + AndroidUtilities.dp(mediaBackground || drawPinnedBottom ? 1 : 7); @@ -12008,7 +12213,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += AndroidUtilities.dp(44); } } else { @@ -12307,7 +12512,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isOutOwner() && (Theme.isCurrentThemeDark() || Theme.isCustomTheme())) { quoteLine.setBackgroundColor(getThemedColor(Theme.key_chat_outCodeBackground)); } - AndroidUtilities.rectTmp.set(0, -dp(2 + 4) - block.languageHeight, maxWidth + dp(4), block.height + dp(2 + 4)); + AndroidUtilities.rectTmp.set(0, -dp(2 + 4) - block.languageHeight, namesOffset <= 0 ? maxWidth + dp(4) : maxWidth, block.height + dp(2 + 4)); AndroidUtilities.rectTmp.offset((block.isRtl() ? rtlOffset : 0), 0); if (block.hasCodeCopyButton) { AndroidUtilities.rectTmp.bottom += dp(38); @@ -12328,7 +12533,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.translate(dp(10), 0); if (block.languageLayout != null) { - block.languageLayout.ellipsize((int) (maxWidth - dp(8 + 4))).draw(canvas, 0, -dp(6) - block.languageHeight / 2f, quoteLine.getColor(), alpha); + block.languageLayout.ellipsize((int) (maxWidth - dp(8 + 4))).draw(canvas, 0, -dp(6) - block.languageHeight / 2f, quoteLine.color3, alpha); } } } @@ -12342,7 +12547,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } paint.setAlpha(wasAlpha); } - if (delegate.getTextSelectionHelper() != null && transitionParams.animateChangeProgress == 1f && !drawOnlyText) { + if (delegate != null && delegate.getTextSelectionHelper() != null && transitionParams.animateChangeProgress == 1f && !drawOnlyText) { if (caption) { delegate.getTextSelectionHelper().drawCaption(currentMessageObject, block, canvas); } else { @@ -12534,13 +12739,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { int maxWidth; if (AndroidUtilities.isTablet()) { - if ((isChat && !isThreadPost && !currentMessageObject.isOutOwner() || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(42); } else { maxWidth = AndroidUtilities.getMinTabletSide(); } } else { - if ((isChat && !isThreadPost && !currentMessageObject.isOutOwner() || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { maxWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y) - AndroidUtilities.dp(42); } else { maxWidth = Math.min(getParentWidth(), AndroidUtilities.displaySize.y); @@ -13055,7 +13260,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; } - if (delegate.needPlayMessage(currentMessageObject, false)) { + if (delegate.needPlayMessage(this, currentMessageObject, false)) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); @@ -13081,9 +13286,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate thumb = currentPhotoObjectThumb; thumbFilter = currentPhotoFilterThumb; } + final int cacheType = currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0; if (currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW) { photoImage.setForceLoading(true); - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, currentPhotoObject.size, null, currentMessageObject, cacheType); } else if (currentMessageObject.type == MessageObject.TYPE_GIF) { FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); if (currentMessageObject.loadedFileSize > 0) { @@ -13106,14 +13312,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate createLoadingProgressLayout(documentAttach); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { - FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, currentMessageObject.shouldEncryptPhotoOrVideo() ? 2 : 0); + FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL, cacheType); if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(currentMessageObject.getDocument()); } } else if (currentMessageObject.type == MessageObject.TYPE_TEXT && documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { photoImage.setForceLoading(true); - photoImage.setImage(ImageLocation.getForDocument(documentAttach), null, ImageLocation.getForDocument(currentPhotoObject, documentAttach), currentPhotoFilterThumb, documentAttach.size, null, currentMessageObject, 0); + photoImage.setImage(ImageLocation.getForDocument(documentAttach), null, ImageLocation.getForDocument(currentPhotoObject, documentAttach), currentPhotoFilterThumb, documentAttach.size, null, currentMessageObject, cacheType); currentMessageObject.gifState = 2; if (currentMessageObject.loadedFileSize > 0) { createLoadingProgressLayout(currentMessageObject.getDocument()); @@ -13188,7 +13394,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; } - if (delegate.needPlayMessage(currentMessageObject, false)) { + if (delegate.needPlayMessage(this, currentMessageObject, false)) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); @@ -13203,7 +13409,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) { + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { //asdf1 radialProgress.setProgress(0, false); FileLoader.getInstance(currentAccount).loadFile(documentAttach, currentMessageObject, FileLoader.PRIORITY_NORMAL_UP, 0); currentMessageObject.loadingCancelled = false; @@ -13231,9 +13437,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate radialProgress.setProgress(0, false); radialProgress.setMiniIcon(getMiniIconForCurrentState(), false, animated); } - delegate.didPressImage(this, 0, 0); + if (delegate != null) { + 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()) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen()) { // asdf2 if (currentMessageObject.isOut() && (currentMessageObject.isSending() || currentMessageObject.isEditing()) || currentMessageObject.isSendError()) { if (delegate != null && radialProgress.getIcon() != MediaActionDrawable.ICON_CHECK) { delegate.didPressCancelSendButton(this); @@ -13274,7 +13482,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); autoPlayingMedia = true; - } else if (!isSmallImage && SharedConfig.isAutoplayVideo() && documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { + } else if (!isSmallImage && SharedConfig.isAutoplayVideo() && !currentMessageObject.isRepostPreview && documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { animatingNoSound = 2; photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); if (!PhotoViewer.isPlayingMessage(currentMessageObject)) { @@ -13286,7 +13494,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate autoPlayingMedia = true; } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { photoImage.setImage(ImageLocation.getForDocument(documentAttach), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || currentPhotoObject != null && "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, documentAttach.size, null, currentMessageObject, 0); - if (SharedConfig.isAutoplayGifs()) { + if (SharedConfig.isAutoplayGifs() && !currentMessageObject.isRepostPreview) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); } else { @@ -13548,9 +13756,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public void onProvideStructure(ViewStructure structure) { super.onProvideStructure(structure); if (allowAssistant && Build.VERSION.SDK_INT >= 23) { - if (currentMessageObject.messageText != null && currentMessageObject.messageText.length() > 0) { + if (currentMessageObject != null && currentMessageObject.messageText != null && currentMessageObject.messageText.length() > 0) { structure.setText(currentMessageObject.messageText); - } else if (currentMessageObject.caption != null && currentMessageObject.caption.length() > 0) { + } else if (currentMessageObject != null && currentMessageObject.caption != null && currentMessageObject.caption.length() > 0) { structure.setText(currentMessageObject.caption); } } @@ -13624,6 +13832,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate timeString = ""; } else if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE) { timeString = ""; + } else if (currentMessageObject.isRepostPreview) { + timeString = LocaleController.formatSmallDateChat(messageObject.messageOwner.date) + ", " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); } else if (edited) { timeString = LocaleController.getString("EditedMessage", R.string.EditedMessage) + " " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); } else { @@ -13671,7 +13881,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate timeWidth += AndroidUtilities.dp(18); } } - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(Integer.MAX_VALUE, Gravity.LEFT); timeWidth += reactionsLayoutInBubble.width; } @@ -13734,8 +13944,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.saved_from_peer != null && (delegate == null || delegate.isReplyOrSelf()); } - private boolean checkNeedDrawShareButton(MessageObject messageObject) { - if (currentMessageObject.deleted || currentMessageObject.isSponsored()) { + protected boolean checkNeedDrawShareButton(MessageObject messageObject) { + if (currentMessageObject.deleted && !currentMessageObject.deletedByThanos || currentMessageObject.isSponsored()) { return false; } if (currentPosition != null) { @@ -14106,7 +14316,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate topicButton = null; } - if ((!isThreadChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice() || (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.story_id != 0 || !TextUtils.isEmpty(messageObject.messageOwner.reply_to.quote_text) || messageObject.messageOwner.reply_to.reply_from != null))) { + if (!messageObject.isGiveawayResults() && (!isThreadChat || messageObject.getReplyTopMsgId(isForum) != 0 || isForumGeneral) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice() || (messageObject.messageOwner.reply_to != null && (messageObject.messageOwner.reply_to.story_id != 0 || !TextUtils.isEmpty(messageObject.messageOwner.reply_to.quote_text) || messageObject.messageOwner.reply_to.reply_from != null))) { if (currentPosition == null || currentPosition.minY == 0) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO || messageObject.type == MessageObject.TYPE_EMOJIS) { namesOffset += AndroidUtilities.dp(20) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); @@ -14202,7 +14412,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentReplyPhoto = photoSize; replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), hasReplySpoiler ? "5_5_b" : "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), hasReplySpoiler ? "50_50_b4" : "50_50_b", size, null, messageObject, cacheType); needReplyImage = true; - maxWidth -= AndroidUtilities.dp(35); + maxWidth -= AndroidUtilities.dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); } } else if (photoSize == null || messageObject.replyMessageObject == null || messageObject.replyMessageObject.isAnyKindOfSticker() || messageObject.isAnyKindOfSticker() && !AndroidUtilities.isTablet() || messageObject.replyMessageObject.isSecretMedia() || messageObject.replyMessageObject.isWebpageDocument()) { replyImageReceiver.setImageBitmap((Drawable) null); @@ -14216,7 +14426,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentReplyPhoto = photoSize; replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), hasReplySpoiler ? "5_5_b" : "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), hasReplySpoiler ? "50_50_b4" : "50_50_b", size, null, messageObject.replyMessageObject, cacheType); needReplyImage = true; - maxWidth -= AndroidUtilities.dp(35); + maxWidth -= AndroidUtilities.dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); } if (DialogObject.isEncryptedDialog(messageObject.getDialogId())) { @@ -14385,7 +14595,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (stringFinalName != null) { replyNameLayout = new StaticLayout(stringFinalName, Theme.chat_replyNamePaint, maxWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyNameLayout.getLineCount() > 0) { - replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + AndroidUtilities.dp(8); + replyNameWidth += (int) Math.ceil(replyNameLayout.getLineWidth(0)) + AndroidUtilities.dp(4); replyNameOffset = (int) replyNameLayout.getLineLeft(0); } } @@ -14410,15 +14620,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } replyTextRTL = AndroidUtilities.isRTL(sb); if (isReplyQuote) { -// maxWidth += AndroidUtilities.dp(12); + maxWidth += AndroidUtilities.dp(24 + 12); // replyTextWidth += AndroidUtilities.dp(24); } if (isReplyQuote && needReplyImage && !replyTextRTL) { final float sz = AndroidUtilities.dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize(); sb.setSpan(new LeadingMarginSpan.Standard((int) sz + AndroidUtilities.dp(4), 0), 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); replyTextWidth -= sz; + maxWidth += sz; } - if (!isReplyQuote || currentMessageObject.shouldDrawWithoutBackground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (!isReplyQuote && (currentMessageObject.shouldDrawWithoutBackground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) { stringFinalText = TextUtils.ellipsize(sb, textPaint, maxWidth, TextUtils.TruncateAt.END); } else { stringFinalText = sb; @@ -14471,7 +14682,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate FileLog.e(e); } } - } else if (!isThreadChat && messageObject.getReplyMsgId() != 0) { + } 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.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += AndroidUtilities.dp(14 + 4) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); @@ -14515,19 +14726,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return name; } - private boolean isNeedAuthorName() { + protected boolean isNeedAuthorName() { if (currentMessageObject.forceAvatar) { return true; } if (currentMessageObject.isSponsored()) { return false; } - if (currentMessageObject.isGiveaway()) { + if (currentMessageObject.isGiveawayOrGiveawayResults()) { return false; } return ( isPinnedChat && currentMessageObject.type == MessageObject.TYPE_TEXT || - !pinnedTop && drawName && isChat && (!currentMessageObject.isOutOwner() || currentMessageObject.isSupergroup() && currentMessageObject.isFromGroup()) || + !pinnedTop && drawName && isChat && (!currentMessageObject.isOutOwner() || currentMessageObject.isSupergroup() && currentMessageObject.isFromGroup() || currentMessageObject.isRepostPreview) || currentMessageObject.isImportedForward() && currentMessageObject.messageOwner.fwd_from.from_id == null ); } @@ -14709,6 +14920,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + protected boolean isWidthAdaptive() { + return false; + } + + @Override + public int getBoundsLeft() { + return Math.max(0, getBackgroundDrawableLeft() - (needDrawAvatar() ? dp(currentPosition != null ? 73 : (currentMessageObject.isRepostPreview ? 42 : 63)) : 0)); + } + + @Override + public int getBoundsRight() { + return getBackgroundDrawableRight() + (checkNeedDrawShareButton(currentMessageObject) ? dp(48) : 0); + } + @SuppressLint("WrongCall") @Override protected void onDraw(Canvas canvas) { @@ -14780,6 +15005,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } + if (isWidthAdaptive()) { + canvas.save(); + canvas.translate(-getBoundsLeft(), 0); + } drawBackgroundInternal(canvas, false); if (isHighlightedAnimated) { @@ -14962,6 +15191,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (restore != Integer.MIN_VALUE) { canvas.restoreToCount(restore); } + if (isWidthAdaptive()) { + canvas.restore(); + } updateSelectionTextPosition(); } @@ -15077,7 +15309,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); } - backgroundDrawableLeft = AndroidUtilities.dp(((isChat || currentMessageObject != null && currentMessageObject.forceAvatar) && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); + backgroundDrawableLeft = AndroidUtilities.dp(((isChat || currentMessageObject != null && (currentMessageObject.isRepostPreview || currentMessageObject.forceAvatar)) && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); backgroundDrawableRight = backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)); if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (!currentPosition.edge) { @@ -15507,6 +15739,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate channelRecommendationsCell.draw(canvas); return; } + if (currentMessageObject == null) { + return; + } if (!enterTransitionInProgress) { drawAnimatedEmojis(canvas, 1f); } @@ -15562,7 +15797,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - color = peerColor.getColor1(isDark()); + color = peerColor.getColor(0, resourcesProvider); } else { color = getThemedColor(Theme.key_chat_inForwardedNameText); } @@ -15765,7 +16000,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate sideStartY -= getTranslationY(); } } - if (!reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && !reactionsLayoutInBubble.isSmall) { if (isRoundVideo) { sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { @@ -15843,7 +16078,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public int getBackgroundDrawableLeft() { - if (currentMessageObject.isOutOwner()) { + MessageObject messageObject = getMessageObject(); + if (messageObject != null && messageObject.isOutOwner()) { if (isRoundVideo) { return layoutWidth - backgroundWidth - (int) ((1f - getVideoTranscriptionProgress()) * AndroidUtilities.dp(9)); } @@ -15851,10 +16087,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { int r; if (isRoundVideo) { - r = AndroidUtilities.dp(((isChat || currentMessageObject != null && currentMessageObject.forceAvatar) && isAvatarVisible ? 48 : 0) + 3); + r = AndroidUtilities.dp(((isChat || messageObject != null && (messageObject.isRepostPreview || messageObject.forceAvatar)) && isAvatarVisible ? 48 : 0) + 3); r += (int) (AndroidUtilities.dp(6) * (1f - getVideoTranscriptionProgress())); } else { - r = AndroidUtilities.dp(((isChat || currentMessageObject != null && currentMessageObject.forceAvatar) && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); + r = AndroidUtilities.dp(((isChat || messageObject != null && (messageObject.isRepostPreview || messageObject.forceAvatar)) && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); } if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (currentPosition.leftSpanOffset != 0) { @@ -15940,7 +16176,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public void drawBackground(Canvas canvas, int left, int top, int right, int bottom, boolean pinnedTop, boolean pinnedBottom, boolean selected, int keyboardHeight) { - if (currentMessageObject.isOutOwner()) { + if (currentMessageObject != null && currentMessageObject.isOutOwner()) { if (!mediaBackground && !pinnedBottom) { currentBackgroundDrawable = (Theme.MessageDrawable) getThemedDrawable(selected ? Theme.key_drawable_msgOutSelected : Theme.key_drawable_msgOut); } else { @@ -16015,7 +16251,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } lastNamesAnimationTime = newAnimationTime; - if (currentMessageObject.deleted && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1) { + if (currentMessageObject.deleted && !drawingToBitmap && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1) { return; } @@ -16054,9 +16290,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate float alphaProgress = currentMessageObject.isOut() && (checkBoxVisible || checkBoxAnimationInProgress) ? (1.0f - checkBoxAnimationProgress) : 1.0f; rect.set((int) nameX - AndroidUtilities.dp(12), (int) nameY - AndroidUtilities.dp(5), (int) nameX + AndroidUtilities.dp(12) + nameWidth, (int) nameY + AndroidUtilities.dp(22)); + applyServiceShaderMatrix(); oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alphaProgress * oldAlpha * replyForwardAlpha)); - applyServiceShaderMatrix(); canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); if (hasGradientService()) { int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); @@ -16116,7 +16352,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_namePaint.setColor(peerColor.getColor1(isDark())); + Theme.chat_namePaint.setColor(peerColor.getColor(0, resourcesProvider)); } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_inForwardedNameText)); } @@ -16256,7 +16492,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - float forwardNameXLocal; + float forwardNameXLocal = 0; int forwardNameRight = -1; boolean needDrawReplyBackground = true; if (drawForwardedNameLocal && forwardedNameLayoutLocal[0] != null && forwardedNameLayoutLocal[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { @@ -16298,7 +16534,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int backWidth = forwardedNameWidthLocal + AndroidUtilities.dp(14); if (hasReply) { needDrawReplyBackground = false; - int replyBackWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); + int replyBackWidth = Math.max(replyNameWidth, replyTextWidth) - AndroidUtilities.dp(4); rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), forwardNameRight = ((int) forwardNameXLocal - AndroidUtilities.dp(7) + Math.max(backWidth, replyBackWidth)), forwardNameY + forwardHeight + AndroidUtilities.dp(6) + AndroidUtilities.dp(41)); } else { rect.set((int) forwardNameXLocal - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameXLocal - AndroidUtilities.dp(7) + backWidth, forwardNameY + forwardHeight + AndroidUtilities.dp(6)); @@ -16354,7 +16590,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_forwardNamePaint.setColor(peerColor.getColor1(isDark())); + Theme.chat_forwardNamePaint.setColor(peerColor.getColor(0, resourcesProvider)); } } } @@ -16494,6 +16730,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } replyStartY = AndroidUtilities.lerp(transitionParams.animateFromReplyY, this.replyStartY, transitionParams.animateChangeProgress); } + if (!needDrawReplyBackground) { + replyStartX = forwardNameXLocal; + } final boolean loading = currentMessageObject != null && delegate != null && delegate.isProgressLoading(this, ChatActivity.PROGRESS_REPLY); if (replyPressedFloat == null) { replyPressedFloat = new AnimatedFloat(this); @@ -16829,6 +17068,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public void setCheckBoxVisible(boolean visible, boolean animated) { + if (animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { + return; + } if (visible) { quoteHighlight = null; if (checkBox == null) { @@ -16873,6 +17115,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public void setChecked(boolean checked, boolean allChecked, boolean animated) { + if (!checked && animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { + return; + } if (checkBox != null) { checkBox.setChecked(allChecked, animated); } @@ -16914,7 +17159,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private boolean shouldDrawCaptionLayout() { - return !currentMessageObject.preview && (currentPosition == null || (currentMessagesGroup != null && currentMessagesGroup.isDocuments && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0)) && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && currentMessageObject.isVoice()); + return currentMessageObject != null && !currentMessageObject.preview && (currentPosition == null || (currentMessagesGroup != null && currentMessagesGroup.isDocuments && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0)) && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && currentMessageObject.isVoice()); } public void drawCaptionLayout(Canvas canvas, boolean selectionOnly, float alpha) { @@ -16940,7 +17185,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate reactionsLayoutInBubble.drawServiceShaderBackground = 1f - getVideoTranscriptionProgress(); } - if (!selectionOnly && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { + if (!selectionOnly && currentMessageObject.shouldDrawReactions() && (currentPosition == null || ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) && !reactionsLayoutInBubble.isSmall) { if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { applyServiceShaderMatrix(); } @@ -17218,7 +17463,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (captionLayout == null || selectionOnly && links.isEmpty() || (currentMessageObject.deleted && currentPosition != null) || alpha == 0) { + if (captionLayout == null || selectionOnly && links.isEmpty() || (currentMessageObject.deleted && !drawingToBitmap && currentPosition != null) || alpha == 0) { return; } setupTextColors(); @@ -17557,7 +17802,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate timeX += animationOffsetX; timeTitleTimeX += animationOffsetX; } - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { if (transitionParams.animateBackgroundBoundsInner && transitionParams.deltaRight != 0) { timeTitleTimeX += reactionsLayoutInBubble.getCurrentWidth(1f); } else { @@ -17639,7 +17884,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate alpha = oldAlpha3; float additionalX = -timeLayout.getLineLeft(0); - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, null); } @@ -17710,7 +17955,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate timeYOffset = -(drawCommentButton ? AndroidUtilities.dp(43) : 0); } float additionalX = -timeLayout.getLineLeft(0); - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, null); } @@ -18437,8 +18682,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (hasGamePreview) { } else if (currentMessageObject.type == MessageObject.TYPE_VIDEO || currentMessageObject.type == MessageObject.TYPE_PHOTO || currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { - if (photoImage.getVisible()) { - if (!currentMessageObject.needDrawBluredPreview() && !currentMessageObject.preview && !isSmallImage) { + if (photoImage.getVisible() && !currentMessageObject.isRepostPreview) { + if (!currentMessageObject.needDrawBluredPreview() && !currentMessageObject.isRepostPreview && !currentMessageObject.preview && !isSmallImage) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); if (drawMediaCheckBox) { @@ -18465,7 +18710,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate fullWidth = (currentPosition.flags & mask) == mask; } - if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && (buttonState == 1 || buttonState == 2 || buttonState == 0 || buttonState == 3 || buttonState == -1) || currentMessageObject.needDrawBluredPreview()) { + if (((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && (buttonState == 1 || buttonState == 2 || buttonState == 0 || buttonState == 3 || buttonState == -1) || currentMessageObject.needDrawBluredPreview()) && !currentMessageObject.isRepostVideoPreview) { if (autoPlayingMedia) { updatePlayingMessageProgress(); } @@ -18777,7 +19022,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + AndroidUtilities.dp(16); } else { - if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { x = AndroidUtilities.dp(74); } else { x = AndroidUtilities.dp(25); @@ -18854,7 +19099,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + AndroidUtilities.dp(11); } else { - if ((isChat && !isThreadPost || currentMessageObject.forceAvatar) && currentMessageObject.needDrawAvatar()) { + if (needDrawAvatar()) { x = AndroidUtilities.dp(68); } else { x = AndroidUtilities.dp(20); @@ -19145,14 +19390,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.restore(); } - 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; + 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); } - 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)); @@ -19196,7 +19443,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (drawImageButton && photoImage.getVisible() && !isSmallImage) { + if (drawImageButton && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isRepostVideoPreview) { if (controlsAlpha != 1.0f) { radialProgress.setOverrideAlpha(controlsAlpha); } @@ -19226,7 +19473,7 @@ 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() && 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) { @@ -19251,6 +19498,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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) { canvas.restore(); @@ -19282,7 +19530,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate invalidate(); updateSecretTimeText(currentMessageObject); } - if ((drawVideoImageButton || animatingDrawVideoImageButton != 0) && photoImage.getVisible() && !isSmallImage) { + if ((drawVideoImageButton || animatingDrawVideoImageButton != 0) && !currentMessageObject.isRepostPreview && photoImage.getVisible() && !isSmallImage) { if (controlsAlpha != 1.0f) { videoRadialProgress.setOverrideAlpha(controlsAlpha); } @@ -19339,17 +19587,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate rect.set(x1, y1, x1 + timeWidthAudio + AndroidUtilities.dp(8 + 12 + 2), y1 + AndroidUtilities.dp(17)); - int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha * timeAlpha * (1f - getVideoTranscriptionProgress()))); applyServiceShaderMatrix(); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), getThemedPaint(Theme.key_paint_chatActionBackground)); + Paint bgPaint = getThemedPaint(Theme.key_paint_chatActionBackground); + int oldAlpha = bgPaint.getAlpha(); + bgPaint.setAlpha((int) (oldAlpha * timeAlpha * 0.5f * (1f - getVideoTranscriptionProgress()))); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), bgPaint); if (hasGradientService()) { - int oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * (1f - getVideoTranscriptionProgress()))); - canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Theme.chat_actionBackgroundGradientDarkenPaint); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + Paint darkenPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); + int oldAlpha2 = darkenPaint.getAlpha(); + darkenPaint.setAlpha((int) (oldAlpha2 * timeAlpha * (1f - getVideoTranscriptionProgress()))); + canvas.drawRoundRect(rect, AndroidUtilities.dp(6), AndroidUtilities.dp(6), darkenPaint); + darkenPaint.setAlpha(oldAlpha2); } - getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + bgPaint.setAlpha(oldAlpha); boolean showPlayingDrawable = playing || !currentMessageObject.isContentUnread(); @@ -20521,7 +20771,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (action == AccessibilityNodeInfo.ACTION_LONG_CLICK) { ClickableSpan link = getLinkById(virtualViewId, virtualViewId >= LINK_CAPTION_IDS_START); - if (link != null) { + if (link != null && delegate != null) { delegate.didPressUrl(ChatMessageCell.this, link, true); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); } @@ -21450,4 +21700,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } return Theme.isCurrentThemeDark(); } + + public boolean needDrawAvatar() { + return isChat && !isThreadPost && currentMessageObject != null && !currentMessageObject.isOutOwner() && currentMessageObject.needDrawAvatar() || currentMessageObject != null && currentMessageObject.forceAvatar; + } + + protected boolean drawPhotoImage(Canvas canvas) { + return photoImage.draw(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 d878df5f9..d6d2bc29d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -1169,6 +1169,11 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } else if (chat.fake) { drawScam = 2; Theme.dialogs_fakeDrawable.checkText(); + } else if (DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + drawPremium = true; + nameLayoutEllipsizeByGradient = true; + emojiStatus.center = LocaleController.isRTL; + emojiStatus.set(DialogObject.getEmojiStatusDocumentId(chat.emoji_status), false); } else { drawVerified = !forbidVerified && chat.verified; } @@ -1472,7 +1477,13 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && message.messageOwner.media.photo instanceof TLRPC.TL_photoEmpty && message.messageOwner.media.ttl_seconds != 0) { messageString = LocaleController.getString("AttachPhotoExpired", R.string.AttachPhotoExpired); } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && (message.messageOwner.media.document instanceof TLRPC.TL_documentEmpty || message.messageOwner.media.document == null) && message.messageOwner.media.ttl_seconds != 0) { - messageString = LocaleController.getString("AttachVideoExpired", R.string.AttachVideoExpired); + if (message.messageOwner.media.voice) { + messageString = LocaleController.getString(R.string.AttachVoiceExpired); + } else if (message.messageOwner.media.round) { + messageString = LocaleController.getString(R.string.AttachRoundExpired); + } else { + messageString = LocaleController.getString(R.string.AttachVideoExpired); + } } else if (getCaptionMessage() != null) { MessageObject message = getCaptionMessage(); String emoji; @@ -1522,8 +1533,9 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; } else { if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { - TLRPC.TL_messageMediaGiveaway mediaPoll = (TLRPC.TL_messageMediaGiveaway) message.messageOwner.media; messageString = LocaleController.getString("BoostingGiveawayChannelStarted", R.string.BoostingGiveawayChannelStarted); + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + messageString = LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) message.messageOwner.media; messageString = "\uD83D\uDCCA " + mediaPoll.poll.question; @@ -2722,17 +2734,29 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava invalidate = true; } } - if (user != null && (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0) { - user = MessagesController.getInstance(currentAccount).getUser(user.id); - Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); - if (emojiStatusId != null) { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(emojiStatusId, animated); - } else { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); + if ((mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0) { + if (user != null) { + user = MessagesController.getInstance(currentAccount).getUser(user.id); + if (user != null && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) { + nameLayoutEllipsizeByGradient = true; + emojiStatus.set(DialogObject.getEmojiStatusDocumentId(user.emoji_status), animated); + } else { + nameLayoutEllipsizeByGradient = true; + emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); + } + invalidate = true; + } + if (chat != null) { + chat = MessagesController.getInstance(currentAccount).getChat(chat.id); + if (chat != null && DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + nameLayoutEllipsizeByGradient = true; + emojiStatus.set(DialogObject.getEmojiStatusDocumentId(chat.emoji_status), animated); + } else { + nameLayoutEllipsizeByGradient = true; + emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); + } + invalidate = true; } - invalidate = true; } if (isDialogCell || isTopic) { if ((mask & MessagesController.UPDATE_MASK_USER_PRINT) != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java index a9c23b56d..03d271f78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java @@ -17,16 +17,18 @@ import android.widget.TextView; import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; public class DialogsHintCell extends FrameLayout { - private LinearLayout contentView; - private TextView titleView; - private TextView messageView; - private ImageView chevronView; + private final LinearLayout contentView; + private final TextView titleView; + private final TextView messageView; + private final ImageView chevronView; + private final ImageView closeView; public DialogsHintCell(@NonNull Context context) { super(context); @@ -43,7 +45,7 @@ public class DialogsHintCell extends FrameLayout { titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); titleView.setSingleLine(); - contentView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + contentView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP)); messageView = new TextView(context); messageView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -55,6 +57,12 @@ public class DialogsHintCell extends FrameLayout { chevronView.setImageResource(R.drawable.arrow_newchat); addView(chevronView, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL)); + closeView = new ImageView(context); + closeView.setImageResource(R.drawable.msg_close); + closeView.setPadding(dp(6), dp(6), dp(6), dp(6)); + addView(closeView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? -15 : 0, 0, LocaleController.isRTL ? 0 : -15, 0)); + closeView.setVisibility(GONE); + setClipToPadding(false); updateColors(); } @@ -62,12 +70,28 @@ public class DialogsHintCell extends FrameLayout { titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); messageView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); chevronView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.SRC_IN); + closeView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.SRC_IN); + closeView.setBackground(Theme.AdaptiveRipple.filledCircle()); setBackground(Theme.AdaptiveRipple.filledRect()); } public void setText(CharSequence title, CharSequence subtitle) { titleView.setText(title); + titleView.setCompoundDrawables(null, null, null, null); messageView.setText(subtitle); + chevronView.setVisibility(VISIBLE); + closeView.setVisibility(GONE); + } + + public void setChristmasStyle(OnClickListener closeListener) { + chevronView.setVisibility(INVISIBLE); + closeView.setVisibility(VISIBLE); + closeView.setOnClickListener(closeListener); + Emoji.EmojiDrawable drawable = Emoji.getEmojiDrawable("\uD83C\uDF84"); + if (drawable != null) { + drawable.setBounds(dp(2), -dp(2), Emoji.drawImgSize + dp(2), Emoji.drawImgSize - dp(2)); + titleView.setCompoundDrawables(null, null, drawable, null); + } } @Override @@ -85,8 +109,8 @@ public class DialogsHintCell extends FrameLayout { width = AndroidUtilities.displaySize.x; } contentView.measure( - MeasureSpec.makeMeasureSpec(width - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST) + MeasureSpec.makeMeasureSpec(width - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST) ); this.height = contentView.getMeasuredHeight() + getPaddingTop() + getPaddingBottom() + 1; super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java index 48a236803..6082a03ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java @@ -29,6 +29,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; @@ -474,10 +475,8 @@ public class GroupCallUserCell extends FrameLayout { nameTextView.setText(UserObject.getUserName(currentUser)); if (currentUser != null && currentUser.verified) { rightDrawable.set(verifiedDrawable = (verifiedDrawable == null ? new VerifiedDrawable(getContext()) : verifiedDrawable), animated); - } else if (currentUser != null && currentUser.emoji_status instanceof TLRPC.TL_emojiStatus) { - rightDrawable.set(((TLRPC.TL_emojiStatus) currentUser.emoji_status).document_id, animated); - } else if (currentUser != null && currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - rightDrawable.set(((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).document_id, animated); + } else if (currentUser != null && DialogObject.getEmojiStatusDocumentId(currentUser.emoji_status) != 0) { + rightDrawable.set(DialogObject.getEmojiStatusDocumentId(currentUser.emoji_status), animated); } else if (currentUser != null && currentUser.premium) { if (premiumDrawable == null) { premiumDrawable = getContext().getResources().getDrawable(R.drawable.msg_premium_liststar).mutate(); @@ -515,6 +514,8 @@ public class GroupCallUserCell extends FrameLayout { nameTextView.setText(currentChat.title); if (currentChat.verified) { rightDrawable.set(verifiedDrawable = (verifiedDrawable == null ? new VerifiedDrawable(getContext()) : verifiedDrawable), animated); + } else if (currentChat != null && DialogObject.getEmojiStatusDocumentId(currentChat.emoji_status) != 0) { + rightDrawable.set(DialogObject.getEmojiStatusDocumentId(currentChat.emoji_status), animated); } else { rightDrawable.set((Drawable) null, animated); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java index c1478c2bd..f1932853e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java @@ -21,6 +21,7 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; 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; @@ -106,6 +107,7 @@ public class ManageChatUserCell extends FrameLayout { nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); 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 + 18 : (68 + namePadding), 11.5f, LocaleController.isRTL ? (68 + namePadding) : 28 + 18, 0)); + NotificationCenter.listenEmojiLoading(nameTextView); statusTextView = new SimpleTextView(context); statusTextView.setTextSize(14); 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 dbd87813e..fe844a1e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -308,7 +308,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No nameLeft = AndroidUtilities.dp(11); } nameLockTop = AndroidUtilities.dp(22.0f); - updateStatus(false, null, false); + updateStatus(false, null, null, false); } else if (chat != null) { dialog_id = -chat.id; drawCheck = chat.verified; @@ -317,7 +317,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No } else { nameLeft = AndroidUtilities.dp(11); } - updateStatus(drawCheck, null, false); + updateStatus(drawCheck, null, chat, false); } else if (user != null) { dialog_id = user.id; if (!LocaleController.isRTL) { @@ -328,7 +328,7 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No nameLockTop = AndroidUtilities.dp(21); drawCheck = user.verified; drawPremium = !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user); - updateStatus(drawCheck, user, false); + updateStatus(drawCheck, user, null, false); } else if (contact != null) { dialog_id = 0; if (!LocaleController.isRTL) { @@ -587,16 +587,16 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No nameLockLeft += getPaddingLeft(); } - public void updateStatus(boolean verified, TLRPC.User user, boolean animated) { + public void updateStatus(boolean verified, TLRPC.User user, TLRPC.Chat chat, boolean animated) { statusDrawable.center = LocaleController.isRTL; if (verified) { statusDrawable.set(new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable, 0, 0), animated); statusDrawable.setColor(null); - } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); + } else if (user != null && !savedMessages && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) { + statusDrawable.set(DialogObject.getEmojiStatusDocumentId(user.emoji_status), animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); - } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatus) { - statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + } else if (chat != null && !savedMessages && DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + statusDrawable.set(DialogObject.getEmojiStatusDocumentId(chat.emoji_status), animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); } else if (user != null && !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { statusDrawable.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); @@ -662,8 +662,8 @@ public class ProfileSearchCell extends BaseCell implements NotificationCenter.No continueUpdate = true; } } - if (!continueUpdate && (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0 && user != null) { - updateStatus(user.verified, user, true); + if (!continueUpdate && (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0 && (user != null || chat != null)) { + updateStatus(user != null ? user.verified : chat.verified, user, chat, true); } if (!continueUpdate && ((mask & MessagesController.UPDATE_MASK_NAME) != 0 && user != null) || (mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 && chat != null) { String newName; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java index 616957c36..f8cfed7e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java @@ -8,7 +8,10 @@ import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import android.text.style.RelativeSizeSpan; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -23,6 +26,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; @@ -33,12 +37,14 @@ import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.DotDividerSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MessageSeenCheckDrawable; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; @@ -57,6 +63,8 @@ public class ReactedUserHolderView extends FrameLayout { SimpleTextView titleView; SimpleTextView subtitleView; BackupImageView reactView; + public BackupImageView storyPreviewView; + public int storyId; AvatarDrawable avatarDrawable = new AvatarDrawable(); View overlaySelectorView; StatusBadgeComponent statusBadgeComponent; @@ -73,6 +81,8 @@ public class ReactedUserHolderView extends FrameLayout { public static final MessageSeenCheckDrawable seenDrawable = new MessageSeenCheckDrawable(R.drawable.msg_mini_checks, Theme.key_windowBackgroundWhiteGrayText); public static final MessageSeenCheckDrawable reactDrawable = new MessageSeenCheckDrawable(R.drawable.msg_reactions, Theme.key_windowBackgroundWhiteGrayText, 16, 16, 5.66f); + public static final MessageSeenCheckDrawable repostDrawable = new MessageSeenCheckDrawable(R.drawable.mini_repost_story, Theme.key_stories_circle1); + public static final MessageSeenCheckDrawable forwardDrawable = new MessageSeenCheckDrawable(R.drawable.mini_forward_story, Theme.key_stories_circle1); public ReactedUserHolderView(int style, int currentAccount, @NonNull Context context, Theme.ResourcesProvider resourcesProvider) { this(style, currentAccount, context, resourcesProvider, true); @@ -148,6 +158,9 @@ public class ReactedUserHolderView extends FrameLayout { reactView = new BackupImageView(context); addView(reactView, LayoutHelper.createFrameRelatively(24, 24, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 12, 0)); + storyPreviewView = new BackupImageView(context); + addView(storyPreviewView, LayoutHelper.createFrameRelatively(22, 35, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 12, 0)); + if (useOverlaySelector) { overlaySelectorView = new View(context); overlaySelectorView.setBackground(Theme.getSelectorDrawable(false)); @@ -155,7 +168,7 @@ public class ReactedUserHolderView extends FrameLayout { } } - public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction reaction, boolean like, long date, boolean dateIsSeen, boolean animated) { + public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction reaction, boolean like, long date, TL_stories.StoryItem storyItem, boolean isForward, boolean dateIsSeen, boolean animated) { TLObject u = user; if (u == null) { u = chat; @@ -223,6 +236,24 @@ public class ReactedUserHolderView extends FrameLayout { contentDescription = LocaleController.formatString("AccDescrPersonHasSeen", R.string.AccDescrPersonHasSeen, titleView.getText()); } + if (storyItem != null) { + storyId = storyItem.id; + if (storyItem.media != null && storyItem.media.photo != null) { + final TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.photo.sizes, 35, false, null, true); + storyPreviewView.setImage(ImageLocation.getForPhoto(photoSize, storyItem.media.photo), "22_35", null, null, -1, storyItem); + } else if (storyItem.media != null && storyItem.media.document != null) { + final TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.document.thumbs, 35, false, null, true); + storyPreviewView.setImage(ImageLocation.getForDocument(photoSize, storyItem.media.document), "22_35", null, null, -1, storyItem); + } + storyPreviewView.setRoundRadius(AndroidUtilities.dp(3.33f)); + if (date <= 0) { + date = storyItem.date; + } + } else { + storyId = -1; + storyPreviewView.setImageDrawable(null); + } + if (date != 0) { contentDescription += " " + LocaleController.formatSeenDate(date); } @@ -230,8 +261,41 @@ public class ReactedUserHolderView extends FrameLayout { if (date != 0) { subtitleView.setVisibility(View.VISIBLE); - CharSequence icon = dateIsSeen ? seenDrawable.getSpanned(getContext(), resourcesProvider) : reactDrawable.getSpanned(getContext(), resourcesProvider); - subtitleView.setText(TextUtils.concat(icon, LocaleController.formatSeenDate(date))); + MessageSeenCheckDrawable drawable; + if (storyItem != null) { + drawable = isForward ? forwardDrawable : repostDrawable; + } else if (dateIsSeen) { + drawable = seenDrawable; + } else { + drawable = reactDrawable; + } + SpannableStringBuilder ssb = new SpannableStringBuilder(); + ssb.append(drawable.getSpanned(getContext(), resourcesProvider)); + ssb.append(LocaleController.formatSeenDate(date)); + if (!isForward && storyItem != null && !TextUtils.isEmpty(storyItem.caption)) { + ssb.append(" "); + ssb.append("."); + DotDividerSpan dotSpan = new DotDividerSpan(); + dotSpan.setSize(2.33333f); + dotSpan.setTopPadding(AndroidUtilities.dp(5)); + ssb.setSpan(dotSpan, ssb.length() - 1, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" "); + int index = ssb.length(); + ssb.append(LocaleController.getString(R.string.StoryRepostCommented)); + ssb.setSpan(new RelativeSizeSpan(.95f), index, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (!isForward && storyItem != null && storyItem.fwd_from != null && storyItem.fwd_from.modified) { + ssb.append(" "); + ssb.append("."); + DotDividerSpan dotSpan = new DotDividerSpan(); + dotSpan.setSize(2.33333f); + dotSpan.setTopPadding(AndroidUtilities.dp(5)); + ssb.setSpan(dotSpan, ssb.length() - 1, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" "); + int index = ssb.length(); + ssb.append("edited"); + ssb.setSpan(new RelativeSizeSpan(.95f), index, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + subtitleView.setText(ssb); subtitleView.setTranslationY(!dateIsSeen ? AndroidUtilities.dp(-1) : 0); titleView.setTranslationY(0); if (animated) { @@ -263,7 +327,7 @@ public class ReactedUserHolderView extends FrameLayout { } else { chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); } - setUserReaction(user, chat, reaction.reaction, false, reaction.date, reaction.dateIsSeen, false); + setUserReaction(user, chat, reaction.reaction, false, reaction.date, null, false, reaction.dateIsSeen, false); } @Override 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 694593da1..f7dd2b022 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -12,10 +12,13 @@ import static org.telegram.messenger.AndroidUtilities.dp; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.SystemClock; @@ -79,12 +82,16 @@ public class ShareDialogCell extends FrameLayout { private boolean topicWasVisible; private final int currentAccount = UserConfig.selectedAccount; - private final Theme.ResourcesProvider resourcesProvider; + public final Theme.ResourcesProvider resourcesProvider; public static final int TYPE_SHARE = 0; public static final int TYPE_CALL = 1; public static final int TYPE_CREATE = 2; + public BackupImageView getImageView() { + return imageView; + } + public ShareDialogCell(Context context, int type, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -144,11 +151,15 @@ public class ShareDialogCell extends FrameLayout { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); } + protected String repostToCustomName() { + return LocaleController.getString(R.string.FwdMyStory); + } + public void setDialog(long uid, boolean checked, CharSequence name) { if (uid == Long.MAX_VALUE) { - nameTextView.setText(LocaleController.getString(R.string.FwdMyStory)); + nameTextView.setText(repostToCustomName()); if (repostStoryDrawable == null) { - repostStoryDrawable = new RepostStoryDrawable(imageView, resourcesProvider); + repostStoryDrawable = new RepostStoryDrawable(getContext(), imageView, true, resourcesProvider); } imageView.setImage(null, null, repostStoryDrawable, null); } else if (DialogObject.isUserDialog(uid)) { @@ -321,41 +332,62 @@ public class ShareDialogCell extends FrameLayout { } } - private static class RepostStoryDrawable extends Drawable { + public static class RepostStoryDrawable extends Drawable { private final LinearGradient gradient; private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final RLottieDrawable lottieDrawable; + private final Drawable drawable; - public RepostStoryDrawable(View view, Theme.ResourcesProvider resourcesProvider) { + public RepostStoryDrawable(Context context, View parentView, boolean animate, Theme.ResourcesProvider resourcesProvider) { gradient = new LinearGradient(0, 0, dp(56), dp(56), new int[] { Theme.getColor(Theme.key_stories_circle1, resourcesProvider), Theme.getColor(Theme.key_stories_circle2, resourcesProvider) }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); paint.setShader(gradient); - lottieDrawable = new RLottieDrawable(R.raw.story_repost, "story_repost", dp(42), dp(42), true, null); - lottieDrawable.setMasterParent(view); - AndroidUtilities.runOnUIThread(lottieDrawable::start, 450); + if (animate) { + lottieDrawable = new RLottieDrawable(R.raw.story_repost, "story_repost", dp(42), dp(42), true, null); + lottieDrawable.setMasterParent(parentView); + AndroidUtilities.runOnUIThread(lottieDrawable::start, 450); + drawable = null; + } else { + lottieDrawable = null; + drawable = context.getResources().getDrawable(R.drawable.large_repost_story).mutate(); + drawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } } + int alpha = 0xFF; @Override public void draw(@NonNull Canvas canvas) { canvas.save(); canvas.translate(getBounds().left, getBounds().top); - canvas.drawCircle(getBounds().width() / 2f, getBounds().height() / 2f, getBounds().width() / 2f, paint); + AndroidUtilities.rectTmp.set(0, 0, getBounds().width(), getBounds().height()); + paint.setAlpha(alpha); + float r2 = Math.min(getBounds().width(), getBounds().height()) / 2f * ((float) alpha / 0xFF); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r2, r2, paint); canvas.restore(); - AndroidUtilities.rectTmp2.set(getBounds()); - AndroidUtilities.rectTmp2.inset(dp(8), dp(8)); - lottieDrawable.setBounds(AndroidUtilities.rectTmp2); - lottieDrawable.draw(canvas); + final int r = dp(lottieDrawable != null ? 20 : 15); + AndroidUtilities.rectTmp2.set( + getBounds().centerX() - r, + getBounds().centerY() - r, + getBounds().centerX() + r, + getBounds().centerY() + r + ); + Drawable drawable = lottieDrawable == null ? this.drawable : lottieDrawable; + if (drawable != null) { + drawable.setBounds(AndroidUtilities.rectTmp2); + drawable.setAlpha(alpha); + drawable.draw(canvas); + } } @Override public void setAlpha(int alpha) { - + this.alpha = alpha; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index 61b7f2958..6dbc2f11b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -33,6 +35,7 @@ import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.Switch; import org.telegram.ui.FilterCreateActivity; +import org.telegram.ui.PeerColorActivity; public class TextCell extends FrameLayout { @@ -94,11 +97,11 @@ public class TextCell extends FrameLayout { valueTextView = new AnimatedTextView(context, false, false, true); valueTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); - valueTextView.setPadding(0, AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18)); - valueTextView.setTextSize(AndroidUtilities.dp(16)); + valueTextView.setPadding(0, dp(18), 0, dp(18)); + valueTextView.setTextSize(dp(16)); valueTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); valueTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - valueTextView.setTranslationY(AndroidUtilities.dp(-2)); + valueTextView.setTranslationY(dp(-2)); addView(valueTextView); valueSpoilersTextView = new SimpleTextView(context); @@ -166,7 +169,7 @@ public class TextCell extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); - int height = AndroidUtilities.dp(heightDp); + int height = dp(heightDp); if (lastWidth != 0 && lastWidth != width && valueText != null) { valueTextView.setText(TextUtils.ellipsize(valueText, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), false); @@ -175,16 +178,16 @@ public class TextCell extends FrameLayout { int valueWidth; if (prioritizeTitleOverValue) { - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(width - dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + subtitleView.measure(MeasureSpec.makeMeasureSpec(width - dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + valueTextView.measure(MeasureSpec.makeMeasureSpec(width - dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); } else { - valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueTextView.measure(MeasureSpec.makeMeasureSpec(width - dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); valueWidth = Math.max(valueTextView.width(), valueSpoilersTextView.getTextWidth()); - textView.measure(MeasureSpec.makeMeasureSpec(Math.max(0, width - AndroidUtilities.dp(71 + leftPadding) - valueWidth), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(Math.max(0, width - dp(71 + leftPadding) - valueWidth), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); + subtitleView.measure(MeasureSpec.makeMeasureSpec(width - dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); } if (imageView.getVisibility() == VISIBLE) { imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); @@ -193,7 +196,7 @@ public class TextCell extends FrameLayout { valueImageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); } if (checkBox != null) { - checkBox.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(37), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + checkBox.measure(MeasureSpec.makeMeasureSpec(dp(37), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(20), MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height + (needDivider ? 1 : 0)); } @@ -212,43 +215,43 @@ public class TextCell extends FrameLayout { int width = right - left; int viewTop = (height - Math.max(valueSpoilersTextView.getTextHeight(), valueTextView.getTextHeight())) / 2; - int viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + int viewLeft = LocaleController.isRTL ? dp(leftPadding) : width - valueTextView.getMeasuredWidth() - dp(leftPadding); if (prioritizeTitleOverValue && !LocaleController.isRTL) { - viewLeft = width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + viewLeft = width - valueTextView.getMeasuredWidth() - dp(leftPadding); } valueTextView.layout(viewLeft, viewTop, viewLeft + valueTextView.getMeasuredWidth(), viewTop + valueTextView.getMeasuredHeight()); - viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : width - valueSpoilersTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + viewLeft = LocaleController.isRTL ? dp(leftPadding) : width - valueSpoilersTextView.getMeasuredWidth() - dp(leftPadding); valueSpoilersTextView.layout(viewLeft, viewTop, viewLeft + valueSpoilersTextView.getMeasuredWidth(), viewTop + valueSpoilersTextView.getMeasuredHeight()); if (LocaleController.isRTL) { - viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); + viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); } else { - viewLeft = AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); + viewLeft = dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); } if (subtitleView.getVisibility() == View.VISIBLE) { int margin = heightDp > 50 ? 4 : 2; - viewTop = (height - textView.getTextHeight() - subtitleView.getTextHeight() - AndroidUtilities.dp(margin)) / 2; + viewTop = (height - textView.getTextHeight() - subtitleView.getTextHeight() - dp(margin)) / 2; textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); - viewTop = viewTop + textView.getTextHeight() + AndroidUtilities.dp(margin); + viewTop = viewTop + textView.getTextHeight() + dp(margin); subtitleView.layout(viewLeft, viewTop, viewLeft + subtitleView.getMeasuredWidth(), viewTop + subtitleView.getMeasuredHeight()); } else { viewTop = (height - textView.getTextHeight()) / 2; textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); } if (imageView.getVisibility() == VISIBLE) { - viewTop = AndroidUtilities.dp(heightDp > 50 ? 0 : 2) + (height - imageView.getMeasuredHeight()) / 2 - imageView.getPaddingTop(); - viewLeft = !LocaleController.isRTL ? AndroidUtilities.dp(imageLeft) : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(imageLeft); + viewTop = dp(heightDp > 50 ? 0 : 2) + (height - imageView.getMeasuredHeight()) / 2 - imageView.getPaddingTop(); + viewLeft = !LocaleController.isRTL ? dp(imageLeft) : width - imageView.getMeasuredWidth() - dp(imageLeft); imageView.layout(viewLeft, viewTop, viewLeft + imageView.getMeasuredWidth(), viewTop + imageView.getMeasuredHeight()); } if (valueImageView.getVisibility() == VISIBLE) { viewTop = (height - valueImageView.getMeasuredHeight()) / 2; - viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(23) : width - valueImageView.getMeasuredWidth() - AndroidUtilities.dp(23); + viewLeft = LocaleController.isRTL ? dp(23) : width - valueImageView.getMeasuredWidth() - dp(23); valueImageView.layout(viewLeft, viewTop, viewLeft + valueImageView.getMeasuredWidth(), viewTop + valueImageView.getMeasuredHeight()); } if (checkBox != null && checkBox.getVisibility() == VISIBLE) { viewTop = (height - checkBox.getMeasuredHeight()) / 2; - viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(22) : width - checkBox.getMeasuredWidth() - AndroidUtilities.dp(22); + viewLeft = LocaleController.isRTL ? dp(22) : width - checkBox.getMeasuredWidth() - dp(22); checkBox.layout(viewLeft, viewTop, viewLeft + checkBox.getMeasuredWidth(), viewTop + checkBox.getMeasuredHeight()); } } @@ -286,6 +289,7 @@ public class TextCell extends FrameLayout { public void setText(String text, boolean divider) { imageLeft = 21; textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); imageView.setVisibility(GONE); valueTextView.setVisibility(GONE); @@ -295,25 +299,32 @@ public class TextCell extends FrameLayout { setWillNotDraw(!needDivider); } - public void setTextAndIcon(String text, int resId, boolean divider) { + public void setLockLevel(boolean plus, int level) { + textView.setRightDrawable(new PeerColorActivity.LevelLock(getContext(), plus, level, resourcesProvider)); + textView.setDrawablePadding(dp(6)); + } + + public void setTextAndIcon(CharSequence text, int resId, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); imageView.setImageResource(resId); imageView.setVisibility(VISIBLE); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); needDivider = divider; setWillNotDraw(!needDivider); } - public void setTextAndColorfulIcon(String text, int resId, int color, boolean divider) { + public void setTextAndColorfulIcon(CharSequence text, int resId, int color, boolean divider) { imageLeft = 21; offsetFromImage = 71; textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); setColorfulIcon(color, resId); valueTextView.setVisibility(GONE); @@ -326,6 +337,7 @@ public class TextCell extends FrameLayout { offsetFromImage = 68; imageLeft = 18; textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); imageView.setColorFilter(null); if (drawable instanceof RLottieDrawable) { @@ -336,7 +348,7 @@ public class TextCell extends FrameLayout { imageView.setVisibility(VISIBLE); valueTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); - imageView.setPadding(0, AndroidUtilities.dp(6), 0, 0); + imageView.setPadding(0, dp(6), 0, 0); needDivider = divider; setWillNotDraw(!needDivider); } @@ -357,6 +369,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); valueTextView.setVisibility(VISIBLE); valueSpoilersTextView.setVisibility(GONE); @@ -373,6 +386,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); valueTextView.setVisibility(VISIBLE); valueSpoilersTextView.setVisibility(GONE); @@ -389,6 +403,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueSpoilersTextView.setVisibility(VISIBLE); valueSpoilersTextView.setText(value); valueTextView.setVisibility(GONE); @@ -396,7 +411,7 @@ public class TextCell extends FrameLayout { imageView.setVisibility(VISIBLE); imageView.setTranslationX(0); imageView.setTranslationY(0); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); imageView.setImageResource(resId); needDivider = divider; setWillNotDraw(!needDivider); @@ -409,6 +424,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueSpoilersTextView.setVisibility(VISIBLE); valueSpoilersTextView.setText(value); valueTextView.setVisibility(GONE); @@ -429,6 +445,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(TextUtils.ellipsize(valueText = value, valueTextView.getPaint(), AndroidUtilities.displaySize.x / 2.5f, TextUtils.TruncateAt.END), animated); valueTextView.setVisibility(VISIBLE); valueSpoilersTextView.setVisibility(GONE); @@ -436,7 +453,7 @@ public class TextCell extends FrameLayout { imageView.setVisibility(VISIBLE); imageView.setTranslationX(0); imageView.setTranslationY(0); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); imageView.setImageResource(resId); needDivider = divider; setWillNotDraw(!needDivider); @@ -445,7 +462,7 @@ public class TextCell extends FrameLayout { } } - public static CharSequence applyNewSpan(String str) { + public static CharSequence applyNewSpan(CharSequence str) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); spannableStringBuilder.append(" d"); FilterCreateActivity.NewSpan span = new FilterCreateActivity.NewSpan(10); @@ -457,17 +474,18 @@ public class TextCell extends FrameLayout { public void setColorfulIcon(int color, int resId) { offsetFromImage = getOffsetFromImage(true); imageView.setVisibility(VISIBLE); - imageView.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); - imageView.setTranslationX(AndroidUtilities.dp(LocaleController.isRTL ? 0 : -3)); + imageView.setPadding(dp(2), dp(2), dp(2), dp(2)); + imageView.setTranslationX(dp(LocaleController.isRTL ? 0 : -3)); imageView.setImageResource(resId); imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); - imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), color)); + imageView.setBackground(Theme.createRoundRectDrawable(dp(9), color)); } public void setTextAndCheck(CharSequence text, boolean checked, boolean divider) { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); imageView.setVisibility(GONE); valueImageView.setVisibility(GONE); needDivider = divider; @@ -482,6 +500,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); @@ -490,7 +509,7 @@ public class TextCell extends FrameLayout { checkBox.setChecked(checked, false); } imageView.setVisibility(VISIBLE); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); imageView.setImageResource(resId); needDivider = divider; setWillNotDraw(!needDivider); @@ -500,6 +519,7 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); @@ -508,7 +528,7 @@ public class TextCell extends FrameLayout { checkBox.setChecked(checked, false); } imageView.setVisibility(VISIBLE); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); imageView.setImageDrawable(resDrawable); needDivider = divider; setWillNotDraw(!needDivider); @@ -518,13 +538,14 @@ public class TextCell extends FrameLayout { imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); valueImageView.setVisibility(VISIBLE); valueImageView.setImageDrawable(drawable); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); imageView.setVisibility(GONE); - imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); + imageView.setPadding(0, dp(7), 0, 0); needDivider = divider; setWillNotDraw(!needDivider); if (checkBox != null) { @@ -543,7 +564,7 @@ public class TextCell extends FrameLayout { if (paint == null) { paint = Theme.dividerPaint; } - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? (inDialogs ? 72 : 68) : 20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? (inDialogs ? 72 : 68) : 20) : 0), getMeasuredHeight() - 1, paint); + canvas.drawLine(LocaleController.isRTL ? 0 : dp(imageView.getVisibility() == VISIBLE ? (inDialogs ? 72 : 68) : 20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? dp(imageView.getVisibility() == VISIBLE ? (inDialogs ? 72 : 68) : 20) : 0), getMeasuredHeight() - 1, paint); } } @@ -693,16 +714,16 @@ public class TextCell extends FrameLayout { paint.setAlpha((int) (255 * alpha)); int cy = getMeasuredHeight() >> 1; AndroidUtilities.rectTmp.set( - getMeasuredWidth() - AndroidUtilities.dp(21) - AndroidUtilities.dp(loadingSize), - cy - AndroidUtilities.dp(3), - getMeasuredWidth() - AndroidUtilities.dp(21), - cy + AndroidUtilities.dp(3) + getMeasuredWidth() - dp(21) - dp(loadingSize), + cy - dp(3), + getMeasuredWidth() - dp(21), + cy + dp(3) ); if (LocaleController.isRTL) { AndroidUtilities.rectTmp.left = getMeasuredWidth() - AndroidUtilities.rectTmp.left; AndroidUtilities.rectTmp.right = getMeasuredWidth() - AndroidUtilities.rectTmp.right; } - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(3), AndroidUtilities.dp(3), paint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(3), dp(3), paint); invalidate(); } valueTextView.setAlpha(1f - drawLoadingProgress); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java index c605dab72..a24822240 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -385,10 +385,13 @@ public class TextCheckCell extends FrameLayout { canvas.drawCircle(cx, cy, animatedRad, animationPaint); } if (needDivider) { - if (imageView != null) { - canvas.drawLine(LocaleController.isRTL ? 0 : padding, getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? padding : 0), getMeasuredHeight() - 1, Theme.dividerPaint); - } else { - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + Paint dividerPaint = resourcesProvider != null ? resourcesProvider.getPaint(Theme.key_paint_divider) : Theme.dividerPaint; + if (dividerPaint != null) { + if (imageView != null) { + canvas.drawLine(LocaleController.isRTL ? 0 : padding, getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? padding : 0), getMeasuredHeight() - 1, dividerPaint); + } else { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, dividerPaint); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java index 8294b7c2e..9e3298972 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java @@ -16,6 +16,7 @@ import android.view.MotionEvent; import android.view.ViewTreeObserver; import android.widget.LinearLayout; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import org.telegram.messenger.AndroidUtilities; @@ -30,7 +31,9 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatBackgroundDrawable; import org.telegram.ui.Components.AnimatedColor; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -38,6 +41,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MotionBackgroundDrawable; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Stories.recorder.StoryEntry; public class ThemePreviewMessagesCell extends LinearLayout { @@ -340,10 +344,7 @@ public class ThemePreviewMessagesCell extends LinearLayout { if (getMessageObject() != null && getMessageObject().overrideLinkColor >= 0) { final int colorId = getMessageObject().overrideLinkColor; final int color1, color2; - if (getMessageObject().overrideProfilePeerColor != null) { - color1 = getMessageObject().overrideProfilePeerColor.getAvatarColor1(); - color2 = getMessageObject().overrideProfilePeerColor.getAvatarColor2(); - } else if (colorId >= 14) { + if (colorId >= 14) { MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); MessagesController.PeerColors peerColors = messagesController != null ? messagesController.peerColors : null; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; @@ -443,9 +444,32 @@ public class ThemePreviewMessagesCell extends LinearLayout { private Drawable overrideDrawable; public void setOverrideBackground(Drawable drawable) { overrideDrawable = drawable; + if (overrideDrawable != null) { + overrideDrawable.setCallback(this); + } + if (overrideDrawable instanceof ChatBackgroundDrawable) { + if (isAttachedToWindow()) { + ((ChatBackgroundDrawable) overrideDrawable).onAttachedToWindow(this); + } + } invalidate(); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (overrideDrawable instanceof ChatBackgroundDrawable) { + ((ChatBackgroundDrawable) overrideDrawable).onAttachedToWindow(this); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == overrideDrawable || who == oldBackgroundDrawable || super.verifyDrawable(who); + } + + public boolean customAnimation; + private final AnimatedFloat overrideDrawableUpdate = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @Override protected void onDraw(Canvas canvas) { @@ -454,7 +478,7 @@ public class ThemePreviewMessagesCell extends LinearLayout { invalidate(); } if (newDrawable != backgroundDrawable && newDrawable != null) { - if (Theme.isAnimatingColor()) { + if (Theme.isAnimatingColor() || customAnimation) { oldBackgroundDrawable = backgroundDrawable; oldBackgroundGradientDisposable = backgroundGradientDisposable; } else if (backgroundGradientDisposable != null) { @@ -462,15 +486,16 @@ public class ThemePreviewMessagesCell extends LinearLayout { backgroundGradientDisposable = null; } backgroundDrawable = newDrawable; + overrideDrawableUpdate.set(0, true); } - float themeAnimationValue = parentLayout.getThemeAnimationValue(); + float themeAnimationValue = customAnimation ? overrideDrawableUpdate.set(1) : parentLayout.getThemeAnimationValue(); for (int a = 0; a < 2; a++) { Drawable drawable = a == 0 ? oldBackgroundDrawable : backgroundDrawable; if (drawable == null) { continue; } int alpha; - if (a == 1 && oldBackgroundDrawable != null && parentLayout != null) { + if (a == 1 && oldBackgroundDrawable != null && (parentLayout != null || customAnimation)) { alpha = (int) (255 * themeAnimationValue); } else { alpha = 255; @@ -510,6 +535,8 @@ public class ThemePreviewMessagesCell extends LinearLayout { } drawable.draw(canvas); canvas.restore(); + } else { + StoryEntry.drawBackgroundDrawable(canvas, drawable, getWidth(), getHeight()); } if (a == 0 && oldBackgroundDrawable != null && themeAnimationValue >= 1.0f) { if (oldBackgroundGradientDisposable != null) { @@ -539,6 +566,9 @@ public class ThemePreviewMessagesCell extends LinearLayout { oldBackgroundGradientDisposable.dispose(); oldBackgroundGradientDisposable = null; } + if (overrideDrawable instanceof ChatBackgroundDrawable) { + ((ChatBackgroundDrawable) overrideDrawable).onDetachedFromWindow(this); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java index 6b39900c3..a4f9d6ce3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java @@ -354,7 +354,7 @@ public class WallpaperCell extends FrameLayout { int width = MeasureSpec.getSize(widthMeasureSpec); int availableWidth = width - AndroidUtilities.dp(14 * 2 + 6 * (spanCount - 1)); int itemWidth = availableWidth / spanCount; - int height = currentType == WallpapersListActivity.TYPE_ALL ? AndroidUtilities.dp(180) : itemWidth; + int height = currentType == WallpapersListActivity.TYPE_ALL || currentType == WallpapersListActivity.TYPE_CHANNEL_PATTERNS || currentType == WallpapersListActivity.TYPE_CHANNEL_CUSTOM ? AndroidUtilities.dp(180) : itemWidth; setMeasuredDimension(width, height + (isTop ? AndroidUtilities.dp(14) : 0) + (AndroidUtilities.dp(isBottom ? 14 : 6))); for (int a = 0; a < spanCount; a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index a03937c11..9f935c9e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2377,7 +2377,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio } @Override - public boolean needPlayMessage(MessageObject messageObject, boolean muted) { + public boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { if (messageObject.isVoice() || messageObject.isRoundVideo()) { boolean result = MediaController.getInstance().playMessage(messageObject, muted); MediaController.getInstance().setVoiceMessagesPlaylist(null, false); @@ -2674,6 +2674,10 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio @Override public void didClickImage(ChatActionCell cell) { MessageObject message = cell.getMessageObject(); + if (message.type == MessageObject.TYPE_ACTION_WALLPAPER) { + presentFragment(new ChannelColorActivity(getDialogId()).setOnApplied(ChannelAdminLogActivity.this)); + return; + } PhotoViewer.getInstance().setParentActivity(ChannelAdminLogActivity.this); TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 640); if (photoSize != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java new file mode 100644 index 000000000..c255fb169 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelColorActivity.java @@ -0,0 +1,2185 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.util.SparseIntArray; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ChatThemeController; +import org.telegram.messenger.DialogObject; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.ResultCallback; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.EmojiThemes; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeColors; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.ThemePreviewMessagesCell; +import org.telegram.ui.Cells.ThemesHorizontalListCell; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.ChatThemeBottomSheet; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; +import org.telegram.ui.Components.FlickerLoadingView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.Text; +import org.telegram.ui.Components.ThemeSmallPreviewView; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.Stories.recorder.PreviewView; + +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ChannelColorActivity extends BaseFragment { + + public final long dialogId; + public int currentLevel; + public TL_stories.TL_premium_boostsStatus boostsStatus; + + public int currentReplyColor, selectedReplyColor; + public long currentReplyEmoji, selectedReplyEmoji; + public int currentProfileColor, selectedProfileColor; + public long currentProfileEmoji, selectedProfileEmoji; + public TLRPC.EmojiStatus currentStatusEmoji, selectedStatusEmoji; + public TLRPC.WallPaper currentWallpaper, selectedWallpaper; + public TLRPC.WallPaper galleryWallpaper; + + public Drawable backgroundDrawable; + + public int minLevelRequired() { + int lvl = 0; + if (currentReplyColor != selectedReplyColor) { + MessagesController.PeerColors peerColors = getMessagesController().peerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedReplyColor); + if (peerColor != null) { + lvl = Math.max(lvl, peerColor.lvl); + } + } + if (currentReplyEmoji != selectedReplyEmoji) { + lvl = Math.max(lvl, getMessagesController().channelBgIconLevelMin); + } + if (currentProfileColor != selectedProfileColor) { + MessagesController.PeerColors peerColors = getMessagesController().profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedProfileColor); + if (peerColor != null) { + lvl = Math.max(lvl, peerColor.lvl); + } + } + if (currentProfileEmoji != selectedProfileEmoji) { + lvl = Math.max(lvl, getMessagesController().channelProfileIconLevelMin); + } + if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji)) { + lvl = Math.max(lvl, getMessagesController().channelEmojiStatusLevelMin); + } + if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { + if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(selectedWallpaper))) { + lvl = Math.max(lvl, getMessagesController().channelWallpaperLevelMin); + } else { + lvl = Math.max(lvl, getMessagesController().channelCustomWallpaperLevelMin); + } + } + return lvl; + } + + private SpannableStringBuilder lock; + public void updateButton(boolean animated) { + if (boostsStatus == null) { + return; + } + int minLevel = minLevelRequired(); + if (currentLevel >= minLevel) { + button.setSubText(null, animated); + } else { + if (lock == null) { + lock = new SpannableStringBuilder("l"); + ColoredImageSpan coloredImageSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); + coloredImageSpan.setTopOffset(1); + lock.setSpan(coloredImageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + SpannableStringBuilder buttonLockedText = new SpannableStringBuilder(); + buttonLockedText.append(lock).append(LocaleController.formatPluralString("BoostLevelRequired", minLevel)); + button.setSubText(buttonLockedText, animated); + } + } + + public class ThemeDelegate implements Theme.ResourcesProvider { + @Override + public int getColor(int key) { + int index = currentColors.indexOfKey(key); + if (index >= 0) { + return currentColors.valueAt(index); + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getColor(key); + } + return Theme.getColor(key); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (drawableKey.equals(Theme.key_drawable_msgIn)) { + return msgInDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgInSelected)) { + return msgInDrawableSelected; + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getDrawable(drawableKey); + } + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public Paint getPaint(String paintKey) { + if (paintKey.equals(Theme.key_paint_divider)) { + return dividerPaint; + } + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public boolean isDark() { + return isDark; + } + + public void toggle() { + isDark = !isDark; + updateThemeColors(); + updateColors(); + } + } + + @Override + public boolean onFragmentCreate() { + getMediaDataController().loadRestrictedStatusEmojis(); + return super.onFragmentCreate(); + } + + public ChannelColorActivity(long dialogId) { + super(); + this.dialogId = dialogId; + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat != null) { + currentLevel = chat.level; + } + MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + this.boostsStatus = boostsStatus; + if (boostsStatus != null) { + this.currentLevel = boostsStatus.level; + if (chat != null) { + chat.flags |= 1024; + chat.level = currentLevel; + } + } + updateButton(true); + if (button != null) { + button.setLoading(false); + } + }); + + resourceProvider = new ThemeDelegate(); + msgInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, false, resourceProvider); + msgInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, true, resourceProvider); + } + + @Override + public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + parentResourcesProvider = resourceProvider; + } + + private boolean isDark = Theme.isCurrentThemeDark(); + private RLottieDrawable sunDrawable; + private ActionBarMenuItem dayNightItem; + + private RecyclerListView listView; + private Adapter adapter; + private FrameLayout buttonContainer; + private ButtonWithCounterView button; + + @Override + public View createView(Context context) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat != null) { + currentReplyColor = selectedReplyColor = ChatObject.getColorId(chat); + currentReplyEmoji = selectedReplyEmoji = ChatObject.getEmojiId(chat); + currentProfileColor = selectedProfileColor = ChatObject.getProfileColorId(chat); + currentProfileEmoji = selectedProfileEmoji = ChatObject.getProfileEmojiId(chat); + currentStatusEmoji = selectedStatusEmoji = chat.emoji_status; + } + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + currentWallpaper = selectedWallpaper = chatFull.wallpaper; + if (ChatThemeController.isNotEmoticonWallpaper(currentWallpaper)) { + galleryWallpaper = currentWallpaper; + } + } + + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setTitle(LocaleController.getString(R.string.ChannelColorTitle2)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (currentLevel >= minLevelRequired() && hasUnsavedChanged()) { + showUnsavedAlert(); + return; + } + finishFragment(); + } else if (id == 1) { + toggleTheme(); + } + } + }); + + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (!isDark) { + sunDrawable.setCustomEndFrame(0); + sunDrawable.setCurrentFrame(0); + } else { + sunDrawable.setCurrentFrame(35); + sunDrawable.setCustomEndFrame(36); + } + sunDrawable.beginApplyLayerColors(); + int color = Theme.getColor(Theme.key_chats_menuName, resourceProvider); + sunDrawable.setLayerColor("Sunny.**", color); + sunDrawable.setLayerColor("Path 6.**", color); + sunDrawable.setLayerColor("Path.**", color); + sunDrawable.setLayerColor("Path 5.**", color); + dayNightItem = actionBar.createMenu().addItem(1, sunDrawable); + + FrameLayout contentView = new FrameLayout(context); + + updateRows(); + listView = new RecyclerListView(context, resourceProvider); + listView.setAdapter(adapter = new Adapter()); + listView.setLayoutManager(new LinearLayoutManager(context)); + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 68)); + listView.setOnItemClickListener((view, position) -> { + if (view instanceof EmojiCell) { + long selectedEmojiId = 0; + if (position == replyEmojiRow) { + selectedEmojiId = selectedReplyEmoji; + } else if (position == profileEmojiRow) { + selectedEmojiId = selectedProfileEmoji; + } else if (position == statusEmojiRow) { + selectedEmojiId = DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji); + } + showSelectStatusDialog((EmojiCell) view, selectedEmojiId, position == statusEmojiRow, (documentId, until) -> { + if (position == replyEmojiRow) { + selectedReplyEmoji = documentId; + updateMessagesPreview(true); + } else if (position == profileEmojiRow) { + selectedProfileEmoji = documentId; + updateProfilePreview(true); + } else if (position == statusEmojiRow) { + if (documentId == 0) { + selectedStatusEmoji = null; + } else { + if (until != null) { + selectedStatusEmoji = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) selectedStatusEmoji).until = until; + ((TLRPC.TL_emojiStatusUntil) selectedStatusEmoji).document_id = documentId; + } else { + selectedStatusEmoji = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) selectedStatusEmoji).document_id = documentId; + } + } + updateProfilePreview(true); + } + updateButton(true); + ((EmojiCell) view).setEmoji(documentId, true); + }); + } else if (position == removeProfileColorRow) { + selectedProfileColor = -1; + selectedProfileEmoji = 0; + updateProfilePreview(true); + updateButton(true); + updateRows(); + } else if (position == wallpaperRow) { + ChannelWallpaperActivity activity = new ChannelWallpaperActivity(dialogId, boostsStatus); + activity.setResourceProvider(resourceProvider); + activity.setSelectedWallpaper(selectedWallpaper, galleryWallpaper); + activity.setOnSelectedWallpaperChange((currentWallpaper, selectedWallpaper, galleryWallpaper) -> { + this.currentWallpaper = currentWallpaper; + this.selectedWallpaper = selectedWallpaper; + this.galleryWallpaper = galleryWallpaper; + + updateButton(false); + updateMessagesPreview(false); + }); + presentFragment(activity); + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); + + button = new ButtonWithCounterView(context, resourceProvider); + button.setText(LocaleController.getString(R.string.ApplyChanges), false); + button.setOnClickListener(v -> buttonClick()); + updateButton(false); + + buttonContainer = new FrameLayout(context); + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 10, 10, 10, 10)); + contentView.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 68, Gravity.BOTTOM)); + + return fragmentView = contentView; + } + + @Override + public boolean onBackPressed() { + if (currentLevel >= minLevelRequired() && hasUnsavedChanged()) { + showUnsavedAlert(); + return false; + } + return super.onBackPressed(); + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + return !hasUnsavedChanged() || currentLevel < minLevelRequired(); + } + + private void buttonClick() { + if (boostsStatus == null || button.isLoading()) { + return; + } + if (currentLevel < minLevelRequired()) { + button.setLoading(true); + showLimit(); + return; + } + + int[] reqCount = new int[] { 0 }; + int[] reqReceivedCount = new int[] { 0 }; + boolean[] receivedError = new boolean[] { false }; + Utilities.Callback whenRequestDone = error -> AndroidUtilities.runOnUIThread(() -> { + if (receivedError[0] || reqReceivedCount[0] >= reqCount[0]) return; + if (error != null) { + receivedError[0] = true; + if ("BOOSTS_REQUIRED".equals(error.text)) { + showLimit(); + } else { + button.setLoading(false); + BulletinFactory.of(this).createSimpleBulletin(R.raw.error, LocaleController.formatString(R.string.UnknownErrorCode, error.text)).show(); + } + return; + } + reqReceivedCount[0]++; + if (reqReceivedCount[0] == reqCount[0]) { + finishFragment(); + showBulletin(); + button.setLoading(false); + } + }); + + TLRPC.Chat channel = getMessagesController().getChat(-dialogId); + if (channel == null) { + FileLog.e("channel is null in ChannelColorAcitivity"); + BulletinFactory.of(this).createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.UnknownError)).show(); + return; + } + + button.setLoading(true); + + if (currentReplyColor != selectedReplyColor || currentReplyEmoji != selectedReplyEmoji) { + TLRPC.TL_channels_updateColor req = new TLRPC.TL_channels_updateColor(); + req.channel = getMessagesController().getInputChannel(-dialogId); + req.for_profile = false; + + if (channel.color == null) { + channel.color = new TLRPC.TL_peerColor(); + channel.flags2 |= 128; + } + req.flags |= 4; + req.color = selectedReplyColor; + channel.color.flags |= 1; + channel.color.color = selectedReplyColor; + + if (selectedReplyEmoji != 0) { + req.flags |= 1; + req.background_emoji_id = selectedReplyEmoji; + channel.color.flags |= 2; + channel.color.background_emoji_id = selectedReplyEmoji; + } else { + channel.color.flags &=~ 2; + channel.color.background_emoji_id = 0; + } + + reqCount[0]++; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.Updates) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + if (whenRequestDone != null) { + whenRequestDone.run(err); + } + }); + } + + if (currentProfileColor != selectedProfileColor || currentProfileEmoji != selectedProfileEmoji) { + TLRPC.TL_channels_updateColor req = new TLRPC.TL_channels_updateColor(); + req.channel = getMessagesController().getInputChannel(-dialogId); + req.for_profile = true; + + if (channel.profile_color == null) { + channel.profile_color = new TLRPC.TL_peerColor(); + channel.flags2 |= 256; + } + if (selectedProfileColor >= 0) { + req.flags |= 4; + req.color = selectedProfileColor; + channel.profile_color.flags |= 1; + channel.profile_color.color = selectedProfileColor; + } else { + channel.profile_color.flags &=~ 1; + } + + if (selectedProfileEmoji != 0) { + req.flags |= 1; + req.background_emoji_id = selectedProfileEmoji; + channel.profile_color.flags |= 2; + channel.profile_color.background_emoji_id = selectedProfileEmoji; + } else { + channel.profile_color.flags &=~ 2; + channel.profile_color.background_emoji_id = 0; + } + + reqCount[0]++; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.Updates) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + if (whenRequestDone != null) { + whenRequestDone.run(err); + } + }); + } + + if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { + TLRPC.TL_messages_setChatWallPaper req = new TLRPC.TL_messages_setChatWallPaper(); + req.peer = getMessagesController().getInputPeer(dialogId); + if (selectedWallpaper != null) { + if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(selectedWallpaper))) { + req.flags |= 1; + req.wallpaper = new TLRPC.TL_inputWallPaperNoFile(); + ((TLRPC.TL_inputWallPaperNoFile) req.wallpaper).id = 0; + + req.flags |= 4; + req.settings = new TLRPC.TL_wallPaperSettings(); + req.settings.flags |= 128; + req.settings.emoticon = ChatThemeController.getWallpaperEmoticon(selectedWallpaper); + } else { + req.flags |= 1; + if (selectedWallpaper instanceof TLRPC.TL_wallPaper) { + TLRPC.TL_inputWallPaper wallPaper = new TLRPC.TL_inputWallPaper(); + wallPaper.id = selectedWallpaper.id; + wallPaper.access_hash = selectedWallpaper.access_hash; + req.wallpaper = wallPaper; + } else if (selectedWallpaper instanceof TLRPC.TL_wallPaperNoFile) { + TLRPC.TL_inputWallPaperNoFile wallPaperNoFile = new TLRPC.TL_inputWallPaperNoFile(); + wallPaperNoFile.id = selectedWallpaper.id; + req.wallpaper = wallPaperNoFile; + } + } + } + + reqCount[0]++; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.Updates) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + if (whenRequestDone != null) { + whenRequestDone.run(err); + } + }); + TLRPC.ChatFull chatFull1 = getMessagesController().getChatFull(-dialogId); + ChatThemeController.getInstance(currentAccount).saveChatWallpaper(dialogId, selectedWallpaper); + if (chatFull1 != null) { + if (selectedWallpaper == null) { + chatFull1.flags2 &=~ 128; + chatFull1.wallpaper = null; + } else { + chatFull1.flags2 |= 128; + chatFull1.wallpaper = selectedWallpaper; + } + getMessagesController().putChatFull(chatFull1); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, chatFull1, 0, false, false); + } + } + + if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji)) { + TLRPC.TL_channels_updateEmojiStatus req = new TLRPC.TL_channels_updateEmojiStatus(); + req.channel = getMessagesController().getInputChannel(-dialogId); + if (selectedStatusEmoji == null || selectedStatusEmoji instanceof TLRPC.TL_emojiStatusEmpty) { + req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + channel.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + channel.flags2 &=~ 512; + } else { + req.emoji_status = selectedStatusEmoji; + channel.emoji_status = selectedStatusEmoji; + channel.flags |= 512; + } + + getMessagesController().updateEmojiStatusUntilUpdate(dialogId, selectedStatusEmoji); + + reqCount[0]++; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.Updates) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + if (whenRequestDone != null) { + whenRequestDone.run(err); + } + }); + } + + if (reqCount[0] == 0) { + finishFragment(); + button.setLoading(false); + } else { + getMessagesController().putChat(channel, false); + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_EMOJI_STATUS); + } + } + + private void showLimit() { + getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + int type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR; + int lvl = 0; + if (currentReplyColor != selectedReplyColor) { + MessagesController.PeerColors peerColors = getMessagesController().peerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedReplyColor); + if (peerColor != null && peerColor.lvl > currentLevel) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR; + lvl = peerColor.lvl; + } + } + if (currentProfileColor != selectedProfileColor) { + MessagesController.PeerColors peerColors = getMessagesController().profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(selectedProfileColor); + if (peerColor != null && peerColor.lvl > currentLevel) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_PROFILE_COLOR; + lvl = peerColor.lvl; + } + } + if (currentReplyEmoji != selectedReplyEmoji && getMessagesController().channelBgIconLevelMin > currentLevel) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_REPLY_ICON; + } + if (currentProfileEmoji != selectedProfileEmoji && getMessagesController().channelProfileIconLevelMin > currentLevel) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_PROFILE_ICON; + } + if (!DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji) && getMessagesController().channelEmojiStatusLevelMin > currentLevel) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_EMOJI_STATUS; + } + if (!ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper)) { + if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(selectedWallpaper))) { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_WALLPAPER; + } else { + type = LimitReachedBottomSheet.TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER; + } + } + final int level = lvl; + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), type, currentAccount, getResourceProvider()) { + @Override + protected int channelColorLevelMin() { + return level; + } + }; + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + TLRPC.Chat channel = getMessagesController().getChat(-dialogId); + if (channel != null) { + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", channel.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + } + StatisticActivity fragment = new StatisticActivity(args); + presentFragment(fragment); + }); + } + showDialog(limitReachedBottomSheet); + button.setLoading(false); + }); + } + + private void showUnsavedAlert() { + if (getVisibleDialog() != null) { + return; + } + AlertDialog alertDialog = new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.ChannelColorUnsaved)) + .setMessage(LocaleController.getString(R.string.ChannelColorUnsavedMessage)) + .setNegativeButton(LocaleController.getString(R.string.Dismiss), (di, w) -> { + finishFragment(); + }) + .setPositiveButton(LocaleController.getString(R.string.ApplyTheme), (di, w) -> { + buttonClick(); + }) + .create(); + showDialog(alertDialog); + ((TextView) alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE)).setTextColor(getThemedColor(Theme.key_text_RedBold)); + } + + private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; + public void showSelectStatusDialog(EmojiCell cell, long documentId, boolean emojiStatus, Utilities.Callback2 onSet) { + if (selectAnimatedEmojiDialog != null || cell == null) { + return; + } + final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; + int xoff = 0, yoff = 0; + + final boolean down = cell.getTop() + cell.getHeight() > listView.getMeasuredHeight() / 2f; + AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; + View scrimDrawableParent = null; + final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); + final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); + if (cell != null) { + scrimDrawable = cell.imageDrawable; + scrimDrawableParent = cell; + if (cell.imageDrawable != null) { + cell.imageDrawable.play(); + cell.updateImageBounds(); + AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); + if (down) { + yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; + } else { + yoff = -(cell.getHeight() - AndroidUtilities.rectTmp2.centerY()) - AndroidUtilities.dp(16); + } + xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); + } + } + int type; + if (emojiStatus) { + type = down ? SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS_CHANNEL_TOP : SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS_CHANNEL; + } else { + type = down ? SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON : SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM; + } + SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(ChannelColorActivity.this, getContext(), true, xoff, type, true, getResourceProvider(), down ? 24 : 16, cell.getColor()) { + @Override + protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { + if (onSet != null) { + onSet.run(documentId == null ? 0 : documentId, until); + } + if (popup[0] != null) { + selectAnimatedEmojiDialog = null; + popup[0].dismiss(); + } + } + + @Override + protected float getScrimDrawableTranslationY() { + return 0; + } + }; + popupLayout.useAccentForPlus = true; + popupLayout.setSelected(documentId == 0 ? null : documentId); + popupLayout.setSaveState(3); + popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); + popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + selectAnimatedEmojiDialog = null; + } + }; + popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); + popup[0].dimBehind(); + } + + private static final int VIEW_TYPE_MESSAGE_PREVIEW = 0; + private static final int VIEW_TYPE_PROFILE_PREVIEW = 1; + private static final int VIEW_TYPE_WALLPAPER_THEMES = 2; + private static final int VIEW_TYPE_COLOR_REPLY_GRID = 3; + private static final int VIEW_TYPE_COLOR_PROFILE_GRID = 4; + private static final int VIEW_TYPE_BUTTON = 5; + private static final int VIEW_TYPE_BUTTON_EMOJI = 6; + private static final int VIEW_TYPE_SHADOW = 7; + + private int rowsCount = 0; + + private int messagesPreviewRow; + private int replyColorListRow; + private int replyEmojiRow; + private int replyHintRow; + + private int wallpaperThemesRow; + private int wallpaperRow; + private int wallpaperHintRow; + + private int profilePreviewRow; + private int profileColorGridRow; + private int profileEmojiRow; + private int profileHintRow; + + private int removeProfileColorRow; + private int removeProfileColorShadowRow; + + private int statusEmojiRow; + private int statusHintRow; + + private void updateRows() { + rowsCount = 0; + messagesPreviewRow = rowsCount++; + replyColorListRow = rowsCount++; + replyEmojiRow = rowsCount++; + replyHintRow = rowsCount++; + wallpaperThemesRow = rowsCount++; + wallpaperRow = rowsCount++; + wallpaperHintRow = rowsCount++; + profilePreviewRow = rowsCount++; + profileColorGridRow = rowsCount++; + profileEmojiRow = rowsCount++; + if (selectedProfileEmoji != 0 || selectedProfileColor >= 0) { + boolean wasButton = removeProfileColorRow >= 0; + removeProfileColorRow = rowsCount++; + if (!wasButton && adapter != null) { + adapter.notifyItemInserted(removeProfileColorRow); + adapter.notifyItemChanged(profileEmojiRow); + } + } else { + int wasIndex = removeProfileColorRow; + removeProfileColorRow = -1; + if (wasIndex >= 0 && adapter != null) { + adapter.notifyItemRemoved(wasIndex); + adapter.notifyItemChanged(profileEmojiRow); + } + } + profileHintRow = rowsCount++; + statusEmojiRow = rowsCount++; + statusHintRow = rowsCount++; + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_MESSAGE_PREVIEW) { + ThemePreviewMessagesCell messagesCell = new ThemePreviewMessagesCell(getContext(), parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId, resourceProvider); + messagesCell.customAnimation = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + messagesCell.fragment = ChannelColorActivity.this; + messagesCell.setOverrideBackground(backgroundDrawable = PreviewView.getBackgroundDrawable(backgroundDrawable, currentAccount, selectedWallpaper, isDark)); + view = messagesCell; + } else if (viewType == VIEW_TYPE_WALLPAPER_THEMES) { + ThemeChooser themesWallpaper = new ThemeChooser(getContext(), false, currentAccount, resourceProvider); + themesWallpaper.setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(selectedWallpaper), false); + themesWallpaper.setGalleryWallpaper(galleryWallpaper); + themesWallpaper.setOnEmoticonSelected(emoticon -> { + if (emoticon == null) { + selectedWallpaper = galleryWallpaper; + } else { + selectedWallpaper = new TLRPC.TL_wallPaperNoFile(); + selectedWallpaper.id = 0; + selectedWallpaper.flags |= 4; + selectedWallpaper.settings = new TLRPC.TL_wallPaperSettings(); + selectedWallpaper.settings.emoticon = emoticon; + } + updateButton(true); + updateMessagesPreview(true); + }); + themesWallpaper.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = themesWallpaper; + } else if (viewType == VIEW_TYPE_BUTTON) { + TextCell textCell = new TextCell(getContext(), getResourceProvider()); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + } else if (viewType == VIEW_TYPE_BUTTON_EMOJI) { + EmojiCell emojiCell = new EmojiCell(getContext(), resourceProvider); + emojiCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = emojiCell; + } else if (viewType == VIEW_TYPE_COLOR_REPLY_GRID) { + PeerColorPicker listCell = new PeerColorPicker(getContext(), currentAccount, resourceProvider); + listCell.listView.setOnItemClickListener((view2, position) -> { + selectedReplyColor = listCell.toColorId(position); + updateButton(true); + updateMessagesPreview(true); + updateProfilePreview(true); + + if (view2.getLeft() < listCell.listView.getPaddingLeft() + dp(24)) { + listCell.listView.smoothScrollBy((int) -(listCell.listView.getPaddingLeft() + dp(48) - view2.getLeft()), 0); + } else if (view2.getLeft() + view2.getWidth() > listCell.listView.getMeasuredWidth() - listCell.listView.getPaddingRight() - dp(24)) { + listCell.listView.smoothScrollBy((int) (view2.getLeft() + view2.getWidth() - (listCell.listView.getMeasuredWidth() - listCell.listView.getPaddingRight() - dp(48))), 0); + } + }); + listCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = listCell; +// PeerColorActivity.PeerColorGrid gridCell = new PeerColorActivity.PeerColorGrid(getContext(), PeerColorActivity.PAGE_NAME, currentAccount, resourceProvider); +// gridCell.setOnColorClick(color -> { +// selectedReplyColor = color; +// updateButton(true); +// updateMessagesPreview(true); +// updateProfilePreview(true); +// }); +// gridCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); +// view = gridCell; + } else if (viewType == VIEW_TYPE_COLOR_PROFILE_GRID) { + PeerColorActivity.PeerColorGrid gridCell = new PeerColorActivity.PeerColorGrid(getContext(), PeerColorActivity.PAGE_PROFILE, currentAccount, resourceProvider); + gridCell.setDivider(false); + gridCell.setOnColorClick(color -> { + selectedProfileColor = color; + updateButton(true); + updateProfilePreview(true); + }); + gridCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = gridCell; + } else if (viewType == VIEW_TYPE_PROFILE_PREVIEW) { + view = new ProfilePreview(getContext()); + } else { + view = new TextInfoPrivacyCell(getContext()); + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case VIEW_TYPE_BUTTON: + TextCell textCell = (TextCell) holder.itemView; + if (position == removeProfileColorRow) { + textCell.setText(LocaleController.getString(R.string.ChannelProfileColorReset), false); + } else { + textCell.setText(LocaleController.getString(R.string.ChannelWallpaper), false); + if (currentLevel < getMessagesController().channelWallpaperLevelMin) { + textCell.setLockLevel(false, getMessagesController().channelWallpaperLevelMin); + } + } + break; + case VIEW_TYPE_BUTTON_EMOJI: + EmojiCell emojiCell = (EmojiCell) holder.itemView; + emojiCell.setDivider(false); + if (position == replyEmojiRow) { + emojiCell.setAdaptiveEmojiColor(currentAccount, selectedReplyColor, true); + emojiCell.setText(LocaleController.getString(R.string.ChannelReplyLogo)); + if (currentLevel < getMessagesController().channelBgIconLevelMin) { + emojiCell.setLockLevel(getMessagesController().channelBgIconLevelMin); + } + emojiCell.setEmoji(selectedReplyEmoji, false); + } else if (position == profileEmojiRow) { + emojiCell.setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + emojiCell.setText(LocaleController.getString(R.string.ChannelProfileLogo)); + emojiCell.setDivider(removeProfileColorRow >= 0); + if (currentLevel < getMessagesController().channelProfileIconLevelMin) { + emojiCell.setLockLevel(getMessagesController().channelProfileIconLevelMin); + } + emojiCell.setEmoji(selectedProfileEmoji, false); + } else if (position == statusEmojiRow) { + emojiCell.setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + emojiCell.setText(LocaleController.getString(R.string.ChannelEmojiStatus)); + if (currentLevel < getMessagesController().channelEmojiStatusLevelMin) { + emojiCell.setLockLevel(getMessagesController().channelEmojiStatusLevelMin); + } + emojiCell.setEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), false); + } + break; + case VIEW_TYPE_SHADOW: + TextInfoPrivacyCell infoCell = (TextInfoPrivacyCell) holder.itemView; + infoCell.setFixedSize(0); + if (position == replyHintRow) { + infoCell.setText(LocaleController.getString(R.string.ChannelReplyInfo)); + } else if (position == wallpaperHintRow) { + infoCell.setText(LocaleController.getString(R.string.ChannelWallpaper2Info)); + } else if (position == profileHintRow) { + infoCell.setText(LocaleController.getString(R.string.ChannelProfileInfo)); + } else if (position == statusHintRow) { + infoCell.setText(LocaleController.getString(R.string.ChannelEmojiStatusInfo)); + } else if (position == removeProfileColorShadowRow) { + infoCell.setText(""); + infoCell.setFixedSize(12); + } + infoCell.setBackground(Theme.getThemedDrawableByKey(getContext(), position == statusHintRow ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow, resourceProvider)); + break; + case VIEW_TYPE_PROFILE_PREVIEW: + ProfilePreview profilePreview = (ProfilePreview) holder.itemView; + profilePreview.backgroundView.setColor(currentAccount, selectedProfileColor, false); + profilePreview.profileView.setColor(selectedProfileColor, false); + profilePreview.profileView.setEmoji(selectedProfileEmoji, false); + profilePreview.profileView.setStatusEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), false); + profilePreview.profileView.overrideAvatarColor(selectedReplyColor); + break; + case VIEW_TYPE_COLOR_PROFILE_GRID: + ((PeerColorActivity.PeerColorGrid) holder.itemView).setSelected(selectedProfileColor, false); + break; + case VIEW_TYPE_COLOR_REPLY_GRID: +// ((PeerColorActivity.PeerColorGrid) holder.itemView).setSelected(selectedReplyColor, false); + ((PeerColorPicker) holder.itemView).setSelected(selectedReplyColor, false); + break; + } + } + + @Override + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + if (holder.itemView instanceof ProfilePreview) { + ProfilePreview profilePreview = (ProfilePreview) holder.itemView; + profilePreview.profileView.setColor(selectedProfileColor, false); + profilePreview.profileView.setEmoji(selectedProfileEmoji, false); + profilePreview.profileView.setStatusEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), false); + profilePreview.profileView.overrideAvatarColor(selectedReplyColor); + } else if (holder.itemView instanceof ThemePreviewMessagesCell) { + ThemePreviewMessagesCell messagesCell = (ThemePreviewMessagesCell) holder.itemView; + messagesCell.setOverrideBackground(backgroundDrawable); + } else { + updateColors(holder.itemView); + } + super.onViewAttachedToWindow(holder); + } + + @Override + public int getItemViewType(int position) { + if (position == messagesPreviewRow) { + return VIEW_TYPE_MESSAGE_PREVIEW; + } else if (position == wallpaperThemesRow) { + return VIEW_TYPE_WALLPAPER_THEMES; + } else if (position == profilePreviewRow) { + return VIEW_TYPE_PROFILE_PREVIEW; + } else if (position == replyColorListRow) { + return VIEW_TYPE_COLOR_REPLY_GRID; + } else if (position == profileColorGridRow) { + return VIEW_TYPE_COLOR_PROFILE_GRID; + } else if (position == replyEmojiRow || position == profileEmojiRow || position == statusEmojiRow) { + return VIEW_TYPE_BUTTON_EMOJI; + } else if (position == wallpaperRow || position == removeProfileColorRow) { + return VIEW_TYPE_BUTTON; + } else { + return VIEW_TYPE_SHADOW; + } + } + + @Override + public int getItemCount() { + return rowsCount; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + final int viewType = holder.getItemViewType(); + return viewType == VIEW_TYPE_BUTTON || viewType == VIEW_TYPE_BUTTON_EMOJI; + } + + } + + public void updateMessagesPreview(boolean animated) { + View messagesPreview = findChildAt(messagesPreviewRow); + View colorPicker = findChildAt(replyColorListRow); + View emojiPicker = findChildAt(replyEmojiRow); + View wallpaperPicker = findChildAt(wallpaperThemesRow); + + if (messagesPreview instanceof ThemePreviewMessagesCell) { + ThemePreviewMessagesCell messagesCellPreview = (ThemePreviewMessagesCell) messagesPreview; + ChatMessageCell[] cells = messagesCellPreview.getCells(); + for (int i = 0; i < cells.length; ++i) { + if (cells[i] != null) { + MessageObject msg = cells[i].getMessageObject(); + if (msg != null) { + msg.overrideLinkColor = selectedReplyColor; + msg.overrideLinkEmoji = selectedReplyEmoji; + cells[i].setAvatar(msg); + cells[i].invalidate(); + } + } + } + messagesCellPreview.setOverrideBackground(backgroundDrawable = PreviewView.getBackgroundDrawable(backgroundDrawable, currentAccount, selectedWallpaper, isDark)); + } + if (colorPicker instanceof PeerColorActivity.PeerColorGrid) { + ((PeerColorActivity.PeerColorGrid) colorPicker).setSelected(selectedReplyColor, animated); + } else if (colorPicker instanceof PeerColorPicker) { + ((PeerColorPicker) colorPicker).setSelected(selectedReplyColor, animated); + } + if (emojiPicker instanceof EmojiCell) { + ((EmojiCell) emojiPicker).setAdaptiveEmojiColor(currentAccount, selectedReplyColor, true); + ((EmojiCell) emojiPicker).setEmoji(selectedReplyEmoji, animated); + } + if (wallpaperPicker instanceof ThemeChooser) { + ((ThemeChooser) wallpaperPicker).setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(selectedWallpaper), animated); + ((ThemeChooser) wallpaperPicker).setGalleryWallpaper(galleryWallpaper); + } + } + + public void updateProfilePreview(boolean animated) { + View profilePreview = findChildAt(profilePreviewRow); + View colorPicker = findChildAt(profileColorGridRow); + View emojiPicker = findChildAt(profileEmojiRow); + View emojiStatusPicker = findChildAt(statusEmojiRow); + + if (profilePreview instanceof ProfilePreview) { + ((ProfilePreview) profilePreview).setColor(selectedProfileColor, animated); + ((ProfilePreview) profilePreview).setEmoji(selectedProfileEmoji, animated); + ((ProfilePreview) profilePreview).setEmojiStatus(selectedStatusEmoji, animated); + ((ProfilePreview) profilePreview).profileView.overrideAvatarColor(selectedReplyColor); + } + if (colorPicker instanceof PeerColorActivity.PeerColorGrid) { + ((PeerColorActivity.PeerColorGrid) colorPicker).setSelected(selectedProfileColor, animated); + } else if (colorPicker instanceof PeerColorPicker) { + ((PeerColorPicker) colorPicker).setSelected(selectedReplyColor, animated); + } + if (emojiPicker instanceof EmojiCell) { + ((EmojiCell) emojiPicker).setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + ((EmojiCell) emojiPicker).setEmoji(selectedProfileEmoji, animated); + } + if (emojiStatusPicker instanceof EmojiCell) { + ((EmojiCell) emojiStatusPicker).setAdaptiveEmojiColor(currentAccount, selectedProfileColor, false); + ((EmojiCell) emojiStatusPicker).setEmoji(DialogObject.getEmojiStatusDocumentId(selectedStatusEmoji), animated); + } + + updateRows(); + } + + public View findChildAt(int position) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == position) { + return child; + } + } + return null; + } + + private class ProfilePreview extends FrameLayout { + public final PeerColorActivity.ColoredActionBar backgroundView; + public final PeerColorActivity.ProfilePreview profileView; + public ProfilePreview(Context context) { + super(context); + backgroundView = new PeerColorActivity.ColoredActionBar(getContext(), resourceProvider); + backgroundView.setProgressToGradient(1f); + backgroundView.ignoreMeasure = true; + addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 134, Gravity.FILL)); + profileView = new PeerColorActivity.ProfilePreview(getContext(), currentAccount, dialogId, resourceProvider); + addView(profileView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.BOTTOM)); + } + + public void setColor(int colorId, boolean animated) { + profileView.setColor(colorId, animated); + backgroundView.setColor(currentAccount, colorId, animated); + } + public void setEmoji(long emojiId, boolean animated) { + profileView.setEmoji(emojiId, animated); + } + public void setEmojiStatus(TLRPC.EmojiStatus emojiStatus, boolean animated) { + profileView.setStatusEmoji(DialogObject.getEmojiStatusDocumentId(emojiStatus), animated); + } + } + + private static class EmojiCell extends FrameLayout { + + private SimpleTextView textView; + private Text offText; + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; + private Theme.ResourcesProvider resourcesProvider; + + public EmojiCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + + this.resourcesProvider = resourcesProvider; + + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + + textView = new SimpleTextView(context); + textView.setTextSize(16); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 23, 0, 48, 0)); + + imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + } + + private boolean needDivider = false; + public void setDivider(boolean divider) { + setWillNotDraw(!(this.needDivider = divider)); + } + + public void setLockLevel(int lvl) { + if (lvl <= 0) { + textView.setRightDrawable(null); + } else { + textView.setRightDrawable(new PeerColorActivity.LevelLock(getContext(), lvl, resourcesProvider)); + textView.setDrawablePadding(dp(6)); + } + } + + private int color; + public void setAdaptiveEmojiColor(int currentAccount, int colorId, boolean isReply) { + if (colorId < 0) { + if (AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)) > .8f) { + color = Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider); + } else if (AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)) < .2f) { + color = Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourcesProvider), .5f); + } else { + color = Theme.blendOver(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), Theme.multAlpha(PeerColorActivity.adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)), .7f)); + } + } else if (colorId < 7) { + color = Theme.getColor(Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); + } else { + MessagesController.PeerColors peerColors = isReply ? MessagesController.getInstance(currentAccount).peerColors : MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (peerColor != null) { + color = peerColor.getColor(0, resourcesProvider); + } else { + color = Theme.getColor(Theme.keys_avatar_nameInMessage[0], resourcesProvider); + } + } + invalidate(); + } + + public void setText(CharSequence text) { + textView.setText(text); + } + + public void setEmoji(long documentId, boolean animated) { + if (documentId == 0) { + imageDrawable.set((Drawable) null, animated); + if (offText == null) { + offText = new Text(LocaleController.getString(R.string.ChannelReplyIconOff), 16); + } + } else { + imageDrawable.set(documentId, animated); + offText = null; + } + } + + public void updateColors() { + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + } + + public void updateImageBounds() { + imageDrawable.setBounds( + getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), + (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, + getWidth() - dp(21), + (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 + ); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + updateImageBounds(); + imageDrawable.setColor(color); + if (offText != null) { + offText.draw(canvas, getMeasuredWidth() - offText.getWidth() - dp(19), getMeasuredHeight() / 2f, Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), 1f); + } else { + imageDrawable.draw(canvas); + } + + if (needDivider) { + Paint dividerPaint = resourcesProvider != null ? resourcesProvider.getPaint(Theme.key_paint_divider) : Theme.dividerPaint; + if (dividerPaint != null) { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(23), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(23) : 0), getMeasuredHeight() - 1, dividerPaint); + } + } + } + + public int getColor() { + return color; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY) + ); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + imageDrawable.detach(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + imageDrawable.attach(); + } + } + + public static class ThemeChooser extends FrameLayout { + + private final int currentAccount; + private final Theme.ResourcesProvider resourcesProvider; + public final List items = new ArrayList<>(); + private final RecyclerListView listView; + private FlickerLoadingView progressView; + + private final RecyclerListView.SelectionAdapter adapter; + + private boolean dataLoaded; + + private Utilities.Callback onEmoticonSelected; + private String currentEmoticon; + + public void setOnEmoticonSelected(Utilities.Callback callback) { + onEmoticonSelected = callback; + } + + public void setSelectedEmoticon(String emoticon, boolean animated) { + currentEmoticon = emoticon; + + int selectedPosition = -1; + for (int i = 0; i < items.size(); ++i) { + ChatThemeBottomSheet.ChatThemeItem item = items.get(i); + item.isSelected = TextUtils.equals(currentEmoticon, item.getEmoticon()) || TextUtils.isEmpty(emoticon) && item.chatTheme.showAsDefaultStub; + if (item.isSelected) { + selectedPosition = i; + } + } + if (selectedPosition >= 0 && !animated && listView.getLayoutManager() instanceof LinearLayoutManager) { + ((LinearLayoutManager) listView.getLayoutManager()).scrollToPositionWithOffset(selectedPosition, (AndroidUtilities.displaySize.x - dp(83)) / 2); + } + updateSelected(); + } + + private TLRPC.WallPaper fallbackWallpaper; + public void setGalleryWallpaper(TLRPC.WallPaper wallPaper) { + this.fallbackWallpaper = wallPaper; + AndroidUtilities.forEachViews(listView, child -> { + if (child instanceof ThemeSmallPreviewView) { + ((ThemeSmallPreviewView) child).setFallbackWallpaper(fallbackWallpaper); + } + }); + } + + private void updateSelected() { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child instanceof ThemeSmallPreviewView) { + int position = listView.getChildAdapterPosition(child); + if (position >= 0 && position < items.size()) { + ChatThemeBottomSheet.ChatThemeItem item = items.get(position); + ((ThemeSmallPreviewView) child).setSelected(item.isSelected, true); + } + } + } + } + + public boolean isDark() { + return resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); + } + + public ThemeChooser(Context context, boolean grid, int currentAccount, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + + if (!grid) { + progressView = new FlickerLoadingView(getContext(), resourcesProvider); + progressView.setViewType(FlickerLoadingView.CHAT_THEMES_TYPE); + progressView.setVisibility(View.VISIBLE); + addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 16, 13, 16, 6)); + } + + listView = new RecyclerListView(context, resourcesProvider) { + @Override + public Integer getSelectorColor(int position) { + return 0; + } + }; + listView.setClipToPadding(false); + listView.setPadding(dp(16), dp(13), dp(16), dp(grid ? 13 : 6)); + if (grid) { + listView.setHasFixedSize(false); + GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 3); + gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return 1; + } + }); + listView.setLayoutManager(gridLayoutManager); + } else { + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); + layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + listView.setLayoutManager(layoutManager); + listView.setAlpha(0f); + } + listView.setAdapter(adapter = new RecyclerListView.SelectionAdapter() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RecyclerListView.Holder(new ThemeSmallPreviewView(parent.getContext(), currentAccount, resourcesProvider, grid ? ThemeSmallPreviewView.TYPE_GRID_CHANNEL : ThemeSmallPreviewView.TYPE_CHANNEL) { + @Override + protected String noThemeString() { + return LocaleController.getString(R.string.ChannelNoWallpaper); + } + + @Override + protected int noThemeStringTextSize() { + if (!grid) { + return 13; + } + return super.noThemeStringTextSize(); + } + }); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + ThemeSmallPreviewView view = (ThemeSmallPreviewView) holder.itemView; + Theme.ThemeInfo themeInfo = items.get(position).chatTheme.getThemeInfo(items.get(position).themeIndex); + if (themeInfo != null && themeInfo.pathToFile != null && !themeInfo.previewParsed) { + File file = new File(themeInfo.pathToFile); + boolean fileExists = file.exists(); + if (fileExists) { + parseTheme(themeInfo); + } + } + ChatThemeBottomSheet.ChatThemeItem newItem = items.get(position); + view.setEnabled(true); + view.setBackgroundColor(Theme.getColor(Theme.key_dialogBackgroundGray)); + view.setItem(newItem, false); + view.setSelected(newItem.isSelected, false); + view.setFallbackWallpaper(fallbackWallpaper); + } + + @Override + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + final int position = holder.getAdapterPosition(); + if (position < 0 || position >= items.size()) { + return; + } + ChatThemeBottomSheet.ChatThemeItem newItem = items.get(position); + ((ThemeSmallPreviewView) holder.itemView).setSelected(newItem.isSelected, false); + ((ThemeSmallPreviewView) holder.itemView).setFallbackWallpaper(fallbackWallpaper); + } + + @Override + public int getItemCount() { + return items.size(); + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, grid ? LayoutHelper.MATCH_PARENT : 13 + 111 + 6)); + listView.setOnItemClickListener((view, position) -> { + if (position < 0 || position >= items.size()) { + return; + } + ChatThemeBottomSheet.ChatThemeItem thisItem = items.get(position); + if (!grid) { + setSelectedEmoticon(thisItem.getEmoticon(), true); + if (view.getLeft() < listView.getPaddingLeft() + dp(24)) { + listView.smoothScrollBy((int) -(listView.getPaddingLeft() + dp(48) - view.getLeft()), 0); + } else if (view.getLeft() + view.getWidth() > listView.getMeasuredWidth() - listView.getPaddingRight() - dp(24)) { + listView.smoothScrollBy((int) (view.getLeft() + view.getWidth() - (listView.getMeasuredWidth() - listView.getPaddingRight() - dp(48))), 0); + } + } + if (onEmoticonSelected != null) { + onEmoticonSelected.run(thisItem.getEmoticon()); + } + }); + + ChatThemeController chatThemeController = ChatThemeController.getInstance(currentAccount); + chatThemeController.preloadAllWallpaperThumbs(true); + chatThemeController.preloadAllWallpaperThumbs(false); + chatThemeController.preloadAllWallpaperImages(true); + chatThemeController.preloadAllWallpaperImages(false); + chatThemeController.requestAllChatThemes(new ResultCallback>() { + @Override + public void onComplete(List result) { +// if (result != null && !result.isEmpty()) { +// themeDelegate.setCachedThemes(result); +// } + NotificationCenter.getInstance(currentAccount).doOnIdle(() -> { + onDataLoaded(result); + }); + } + + @Override + public void onError(TLRPC.TL_error error) { + Toast.makeText(getContext(), error.text, Toast.LENGTH_SHORT).show(); + } + }, true); + + updateState(false); + } + + public void updateColors() { + final boolean isDark = isDark(); + for (int i = 0; i < items.size(); ++i) { + ChatThemeBottomSheet.ChatThemeItem item = items.get(i); + item.themeIndex = isDark ? 1 : 0; + } + AndroidUtilities.forEachViews(listView, view -> { + ((ThemeSmallPreviewView) view).setBackgroundColor(Theme.getColor(Theme.key_dialogBackgroundGray, resourcesProvider)); + }); + adapter.notifyDataSetChanged(); + } + + private void onDataLoaded(List result) { + if (result == null || result.isEmpty()) { + return; + } + + dataLoaded = true; + items.clear(); + + ChatThemeBottomSheet.ChatThemeItem noThemeItem = new ChatThemeBottomSheet.ChatThemeItem(result.get(0)); + items.add(0, noThemeItem); + + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); + for (int i = 1; i < result.size(); ++i) { + EmojiThemes chatTheme = result.get(i); + ChatThemeBottomSheet.ChatThemeItem item = new ChatThemeBottomSheet.ChatThemeItem(chatTheme); + + chatTheme.loadPreviewColors(currentAccount); + + item.themeIndex = isDark ? 1 : 0; + items.add(item); + } + + int selectedPosition = -1; + for (int i = 0; i < items.size(); ++i) { + ChatThemeBottomSheet.ChatThemeItem item = items.get(i); + item.isSelected = TextUtils.equals(currentEmoticon, item.getEmoticon()) || TextUtils.isEmpty(currentEmoticon) && item.chatTheme.showAsDefaultStub; + if (item.isSelected) { + selectedPosition = i; + } + } + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + +// resetToPrimaryState(false); + listView.animate().alpha(1f).setDuration(150).start(); + updateState(true); + + if (selectedPosition >= 0 && listView.getLayoutManager() instanceof LinearLayoutManager) { + ((LinearLayoutManager) listView.getLayoutManager()).scrollToPositionWithOffset(selectedPosition, (AndroidUtilities.displaySize.x - dp(83)) / 2); + } + } + + private final HashMap loadingThemes = new HashMap<>(); + private final HashMap loadingWallpapers = new HashMap<>(); + private boolean parseTheme(Theme.ThemeInfo themeInfo) { + if (themeInfo == null || themeInfo.pathToFile == null) { + return false; + } + boolean finished = false; + File file = new File(themeInfo.pathToFile); + try (FileInputStream stream = new FileInputStream(file)) { + int currentPosition = 0; + int idx; + int read; + int linesRead = 0; + while ((read = stream.read(ThemesHorizontalListCell.bytes)) != -1) { + int previousPosition = currentPosition; + int start = 0; + for (int a = 0; a < read; a++) { + if (ThemesHorizontalListCell.bytes[a] == '\n') { + linesRead++; + int len = a - start + 1; + String line = new String(ThemesHorizontalListCell.bytes, start, len - 1, "UTF-8"); + if (line.startsWith("WLS=")) { + String wallpaperLink = line.substring(4); + Uri uri = Uri.parse(wallpaperLink); + themeInfo.slug = uri.getQueryParameter("slug"); + themeInfo.pathToWallpaper = new File(ApplicationLoader.getFilesDirFixed(), Utilities.MD5(wallpaperLink) + ".wp").getAbsolutePath(); + + String mode = uri.getQueryParameter("mode"); + if (mode != null) { + mode = mode.toLowerCase(); + String[] modes = mode.split(" "); + if (modes != null && modes.length > 0) { + for (int b = 0; b < modes.length; b++) { + if ("blur".equals(modes[b])) { + themeInfo.isBlured = true; + break; + } + } + } + } + String pattern = uri.getQueryParameter("pattern"); + if (!TextUtils.isEmpty(pattern)) { + try { + String bgColor = uri.getQueryParameter("bg_color"); + if (!TextUtils.isEmpty(bgColor)) { + themeInfo.patternBgColor = Integer.parseInt(bgColor.substring(0, 6), 16) | 0xff000000; + if (bgColor.length() >= 13 && AndroidUtilities.isValidWallChar(bgColor.charAt(6))) { + themeInfo.patternBgGradientColor1 = Integer.parseInt(bgColor.substring(7, 13), 16) | 0xff000000; + } + if (bgColor.length() >= 20 && AndroidUtilities.isValidWallChar(bgColor.charAt(13))) { + themeInfo.patternBgGradientColor2 = Integer.parseInt(bgColor.substring(14, 20), 16) | 0xff000000; + } + if (bgColor.length() == 27 && AndroidUtilities.isValidWallChar(bgColor.charAt(20))) { + themeInfo.patternBgGradientColor3 = Integer.parseInt(bgColor.substring(21), 16) | 0xff000000; + } + } + } catch (Exception ignore) { + + } + try { + String rotation = uri.getQueryParameter("rotation"); + if (!TextUtils.isEmpty(rotation)) { + themeInfo.patternBgGradientRotation = Utilities.parseInt(rotation); + } + } catch (Exception ignore) { + + } + String intensity = uri.getQueryParameter("intensity"); + if (!TextUtils.isEmpty(intensity)) { + themeInfo.patternIntensity = Utilities.parseInt(intensity); + } + if (themeInfo.patternIntensity == 0) { + themeInfo.patternIntensity = 50; + } + } + } else if (line.startsWith("WPS")) { + themeInfo.previewWallpaperOffset = currentPosition + len; + finished = true; + break; + } else { + if ((idx = line.indexOf('=')) != -1) { + int key = ThemeColors.stringKeyToInt(line.substring(0, idx)); + if (key == Theme.key_chat_inBubble || key == Theme.key_chat_outBubble || key == Theme.key_chat_wallpaper || key == Theme.key_chat_wallpaper_gradient_to1 || key == Theme.key_chat_wallpaper_gradient_to2 || key == Theme.key_chat_wallpaper_gradient_to3) { + String param = line.substring(idx + 1); + int value; + if (param.length() > 0 && param.charAt(0) == '#') { + try { + value = Color.parseColor(param); + } catch (Exception ignore) { + value = Utilities.parseInt(param); + } + } else { + value = Utilities.parseInt(param); + } + if (key == Theme.key_chat_inBubble) { + themeInfo.setPreviewInColor(value); + } else if (key == Theme.key_chat_outBubble) { + themeInfo.setPreviewOutColor(value); + } else if (key == Theme.key_chat_wallpaper) { + themeInfo.setPreviewBackgroundColor(value); + } else if (key == Theme.key_chat_wallpaper_gradient_to1) { + themeInfo.previewBackgroundGradientColor1 = value; + } else if (key == Theme.key_chat_wallpaper_gradient_to2) { + themeInfo.previewBackgroundGradientColor2 = value; + } else if (key == Theme.key_chat_wallpaper_gradient_to3) { + themeInfo.previewBackgroundGradientColor3 = value; + } + } + } + } + start += len; + currentPosition += len; + } + } + if (finished || previousPosition == currentPosition) { + break; + } + stream.getChannel().position(currentPosition); + } + } catch (Throwable e) { + FileLog.e(e); + } + + if (themeInfo.pathToWallpaper != null && !themeInfo.badWallpaper) { + file = new File(themeInfo.pathToWallpaper); + if (!file.exists()) { + if (!loadingWallpapers.containsKey(themeInfo)) { + loadingWallpapers.put(themeInfo, themeInfo.slug); + TLRPC.TL_account_getWallPaper req = new TLRPC.TL_account_getWallPaper(); + TLRPC.TL_inputWallPaperSlug inputWallPaperSlug = new TLRPC.TL_inputWallPaperSlug(); + inputWallPaperSlug.slug = themeInfo.slug; + req.wallpaper = inputWallPaperSlug; + ConnectionsManager.getInstance(themeInfo.account).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_wallPaper) { + TLRPC.WallPaper wallPaper = (TLRPC.WallPaper) response; + String name = FileLoader.getAttachFileName(wallPaper.document); + if (!loadingThemes.containsKey(name)) { + loadingThemes.put(name, themeInfo); + FileLoader.getInstance(themeInfo.account).loadFile(wallPaper.document, wallPaper, FileLoader.PRIORITY_NORMAL, 1); + } + } else { + themeInfo.badWallpaper = true; + } + })); + } + return false; + } + } + themeInfo.previewParsed = true; + return true; + } + + private void updateState(boolean animated) { + if (!dataLoaded) { + AndroidUtilities.updateViewVisibilityAnimated(progressView, true, 1f, true, animated); + } else { + AndroidUtilities.updateViewVisibilityAnimated(progressView, false, 1f, true, animated); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + } + + private BaseFragment bulletinFragment; + public ChannelColorActivity setOnApplied(BaseFragment bulletinFragment) { + this.bulletinFragment = bulletinFragment; + return this; + } + + private void showBulletin() { + if (bulletinFragment != null) { + if (bulletinFragment instanceof ChatEditActivity) { + ((ChatEditActivity) bulletinFragment).updateColorCell(); + } + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + R.raw.contact_check, + LocaleController.getString(R.string.ChannelAppearanceUpdated) + ).show(); + bulletinFragment = null; + } + } + + public void updateColors() { + actionBar.setBackgroundColor(getThemedColor(Theme.key_actionBarDefault)); + actionBar.setTitleColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); + actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSelector), false); + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + adapter.notifyDataSetChanged(); + AndroidUtilities.forEachViews(listView, this::updateColors); + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + button.updateColors(); + setNavigationBarColor(getNavigationBarColor()); + } + + public boolean hasUnsavedChanged() { + return ( + currentReplyColor != selectedReplyColor || + currentReplyEmoji != selectedReplyEmoji || + currentProfileColor != selectedProfileColor || + currentProfileEmoji != selectedProfileEmoji || + !DialogObject.emojiStatusesEqual(currentStatusEmoji, selectedStatusEmoji) || + !ChatThemeController.wallpaperEquals(currentWallpaper, selectedWallpaper) + ); + } + + private void updateColors(View view) { + if (view instanceof TextInfoPrivacyCell) { + ((TextInfoPrivacyCell) view).setBackground(Theme.getThemedDrawableByKey(getContext(), listView.getChildAdapterPosition(view) == statusHintRow ? R.drawable.greydivider_bottom : R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow, resourceProvider)); + } else { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + if (view instanceof EmojiCell) { + ((EmojiCell) view).updateColors(); + } else if (view instanceof TextCell) { + ((TextCell) view).updateColors(); + } else if (view instanceof PeerColorPicker) { + ((PeerColorPicker) view).updateColors(); + } else if (view instanceof ThemeChooser) { + ((ThemeChooser) view).updateColors(); + } + } + } + + private static class PeerColorPicker extends FrameLayout { + private final Theme.ResourcesProvider resourcesProvider; + public final RecyclerListView listView; + public final LinearLayoutManager layoutManager; + public final RecyclerListView.SelectionAdapter adapter; + private final int currentAccount; + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1) || canScrollHorizontally(1)); + } + return super.onInterceptTouchEvent(e); + } + + public PeerColorPicker(Context context, final int currentAccount, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + + listView = new RecyclerListView(context, resourcesProvider) { + @Override + public Integer getSelectorColor(int position) { + return 0; + } + }; + listView.setPadding(dp(6), dp(5), dp(6), 0); + listView.setClipToPadding(false); + + listView.setAdapter(adapter = new RecyclerListView.SelectionAdapter() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RecyclerListView.Holder(new ColorCell(context)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + ColorCell cell = (ColorCell) holder.itemView; + cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + cell.setSelected(position == selectedPosition, false); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + if (peerColors != null && position >= 0 && position < peerColors.colors.size()) { + cell.set(peerColors.colors.get(position)); + } + } + + @Override + public int getItemCount() { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + return (peerColors == null ? 0 : peerColors.colors.size()); + } + }); + layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + listView.setLayoutManager(layoutManager); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + private int selectedPosition; + public void setSelected(int color, boolean animated) { + setSelectedPosition(toPosition(color), animated); + } + + public void setSelectedPosition(int position, boolean animated) { + if (position != selectedPosition) { + selectedPosition = position; + if (!animated) { + layoutManager.scrollToPositionWithOffset(position, (AndroidUtilities.displaySize.x - dp(56)) / 2); + } + AndroidUtilities.forEachViews(listView, child -> ((ColorCell) child).setSelected(listView.getChildAdapterPosition(child) == selectedPosition, animated)); + } + } + + public int getColorId() { + return toColorId(selectedPosition); + } + + public int toPosition(final int colorId) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + if (peerColors == null) { + return 0; + } + for (int i = 0; i < peerColors.colors.size(); ++i) { + if (peerColors.colors.get(i).id == colorId) { + return i; + } + } + return 0; + } + + public void updateColors() { + final MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof ColorCell) { + ((ColorCell) view).setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + int position = listView.getChildAdapterPosition(view); + if (peerColors != null && position >= 0 && position < peerColors.colors.size()) { + ((ColorCell) view).set(peerColors.colors.get(position)); + } + } + }); + } + + public int toColorId(int position) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; + if (peerColors == null || position < 0 || position >= peerColors.colors.size()) { + return 0; + } + return peerColors.colors.get(position).id; + } + + private class ColorCell extends View { + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint paint3 = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path circlePath = new Path(); + private final Path color2Path = new Path(); + private boolean hasColor2, hasColor3; + + private final ButtonBounce bounce = new ButtonBounce(this); + + public ColorCell(Context context) { + super(context); + backgroundPaint.setStyle(Paint.Style.STROKE); + } + + public void setBackgroundColor(int backgroundColor) { + backgroundPaint.setColor(backgroundColor); + } + + public void set(int color) { + hasColor2 = hasColor3 = false; + paint1.setColor(color); + } + + public void set(int color1, int color2) { + hasColor2 = true; + hasColor3 = false; + paint1.setColor(color1); + paint2.setColor(color2); + } + + public void set(MessagesController.PeerColor color) { + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); + if (isDark && color.hasColor2() && !color.hasColor3()) { + paint1.setColor(color.getColor(1, resourcesProvider)); + paint2.setColor(color.getColor(0, resourcesProvider)); + } else { + paint1.setColor(color.getColor(0, resourcesProvider)); + paint2.setColor(color.getColor(1, resourcesProvider)); + } + paint3.setColor(color.getColor(2, resourcesProvider)); + hasColor2 = color.hasColor2(); + hasColor3 = color.hasColor3(); + } + + private boolean selected; + private final AnimatedFloat selectedT = new AnimatedFloat(this, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); + public void setSelected(boolean selected, boolean animated) { + this.selected = selected; + if (!animated) { + selectedT.set(selected, true); + } + invalidate(); + } + + private static final int VIEW_SIZE_DP = 56; + private static final int CIRCLE_RADIUS_DP = 20; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(dp(VIEW_SIZE_DP), dp(VIEW_SIZE_DP)); + + circlePath.rewind(); + circlePath.addCircle(getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, dp(CIRCLE_RADIUS_DP), Path.Direction.CW); + + color2Path.rewind(); + color2Path.moveTo(getMeasuredWidth(), 0); + color2Path.lineTo(getMeasuredWidth(), getMeasuredHeight()); + color2Path.lineTo(0, getMeasuredHeight()); + color2Path.close(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + final float s = bounce.getScale(.05f); + canvas.scale(s, s, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + + canvas.save(); + canvas.clipPath(circlePath); + canvas.drawPaint(paint1); + if (hasColor2) { + canvas.drawPath(color2Path, paint2); + } + canvas.restore(); + + if (hasColor3) { + canvas.save(); + AndroidUtilities.rectTmp.set( + (getMeasuredWidth() - dp(12.4f)) / 2f, + (getMeasuredHeight() - dp(12.4f)) / 2f, + (getMeasuredWidth() + dp(12.4f)) / 2f, + (getMeasuredHeight() + dp(12.4f)) / 2f + ); + canvas.rotate(45f, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2.33f), dp(2.33f), paint3); + canvas.restore(); + } + + final float selectT = selectedT.set(selected); + + if (selectT > 0) { + backgroundPaint.setStrokeWidth(dpf2(2)); + canvas.drawCircle( + getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, + AndroidUtilities.lerp( + dp(CIRCLE_RADIUS_DP) + backgroundPaint.getStrokeWidth() * .5f, + dp(CIRCLE_RADIUS_DP) - backgroundPaint.getStrokeWidth() * 2f, + selectT + ), + backgroundPaint + ); + } + + canvas.restore(); + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + bounce.setPressed(pressed); + } + } + } + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + @SuppressLint("NotifyDataSetChanged") + public void toggleTheme() { + FrameLayout decorView1 = (FrameLayout) getParentActivity().getWindow().getDecorView(); + Bitmap bitmap = Bitmap.createBitmap(decorView1.getWidth(), decorView1.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + dayNightItem.setAlpha(0f); + decorView1.draw(bitmapCanvas); + dayNightItem.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + dayNightItem.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + dayNightItem.getMeasuredWidth() / 2f; + float cy = y + dayNightItem.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isDark) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + dayNightItem.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setDuration(400); + changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad); + changeDayNightViewAnimator.start(); + + decorView1.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + if (resourceProvider instanceof ThemeDelegate) { + ((ThemeDelegate) resourceProvider).toggle(); + } else { + isDark = !isDark; + updateThemeColors(); + } + setForceDark(isDark, true); + updateColors(); + }); + } + + private boolean forceDark = isDark; + public void setForceDark(boolean isDark, boolean playAnimation) { + if (forceDark == isDark) { + return; + } + forceDark = isDark; + if (playAnimation) { + sunDrawable.setCustomEndFrame(isDark ? sunDrawable.getFramesCount() : 0); + if (sunDrawable != null) { + sunDrawable.start(); + } + } else { + int frame = isDark ? sunDrawable.getFramesCount() - 1 : 0; + sunDrawable.setCurrentFrame(frame, false, true); + sunDrawable.setCustomEndFrame(frame); + if (dayNightItem != null) { + dayNightItem.invalidate(); + } + } + } + + private Theme.ResourcesProvider parentResourcesProvider; + private final SparseIntArray currentColors = new SparseIntArray(); + private final Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + dividerPaint.setStrokeWidth(1); + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourceProvider)); + } + + public void updateThemeColors() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("themeconfig", Activity.MODE_PRIVATE); + String dayThemeName = preferences.getString("lastDayTheme", "Blue"); + if (Theme.getTheme(dayThemeName) == null || Theme.getTheme(dayThemeName).isDark()) { + dayThemeName = "Blue"; + } + String nightThemeName = preferences.getString("lastDarkTheme", "Dark Blue"); + if (Theme.getTheme(nightThemeName) == null || !Theme.getTheme(nightThemeName).isDark()) { + nightThemeName = "Dark Blue"; + } + Theme.ThemeInfo themeInfo = Theme.getActiveTheme(); + if (dayThemeName.equals(nightThemeName)) { + if (themeInfo.isDark() || dayThemeName.equals("Dark Blue") || dayThemeName.equals("Night")) { + dayThemeName = "Blue"; + } else { + nightThemeName = "Dark Blue"; + } + } + + if (isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } + + currentColors.clear(); + final String[] wallpaperLink = new String[1]; + final SparseIntArray themeColors; + if (themeInfo.assetName != null) { + themeColors = Theme.getThemeFileValues(null, themeInfo.assetName, wallpaperLink); + } else { + themeColors = Theme.getThemeFileValues(new File(themeInfo.pathToFile), null, wallpaperLink); + } + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); + } + } + if (themeColors != null) { + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } + Theme.ThemeAccent accent = themeInfo.getAccent(false); + if (accent != null) { + accent.fillAccentColors(themeColors, currentColors); + } + } + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourceProvider)); + + backgroundDrawable = PreviewView.getBackgroundDrawable(backgroundDrawable, currentAccount, selectedWallpaper, isDark); + View messagesCellPreview = findChildAt(messagesPreviewRow); + if (messagesCellPreview instanceof ThemePreviewMessagesCell) { + ((ThemePreviewMessagesCell) messagesCellPreview).setOverrideBackground(backgroundDrawable); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java new file mode 100644 index 000000000..4bda72b24 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelWallpaperActivity.java @@ -0,0 +1,491 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatThemeController; +import org.telegram.messenger.DialogObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.ChatThemeBottomSheet; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.Locale; + +public class ChannelWallpaperActivity extends BaseFragment { + + public final long dialogId; + public int currentLevel; + public TL_stories.TL_premium_boostsStatus boostsStatus; + public TLRPC.WallPaper galleryWallpaper; + public TLRPC.WallPaper currentWallpaper, selectedWallpaper; + + public ChannelWallpaperActivity(long dialogId, TL_stories.TL_premium_boostsStatus boostsStatus) { + super(); + this.dialogId = dialogId; + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat != null) { + currentLevel = chat.level; + } + this.boostsStatus = boostsStatus; + if (boostsStatus == null) { + MessagesController.getInstance(currentAccount).getBoostsController().getBoostsStats(dialogId, loadedBoostsStatus -> { + this.boostsStatus = loadedBoostsStatus; + if (boostsStatus != null) { + this.currentLevel = boostsStatus.level; + if (chat != null) { + chat.flags |= 1024; + chat.level = currentLevel; + } + } + }); + } else { + currentLevel = boostsStatus.level; + } + + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + currentWallpaper = selectedWallpaper = chatFull.wallpaper; + if (ChatThemeController.isNotEmoticonWallpaper(selectedWallpaper)) { + galleryWallpaper = selectedWallpaper; + } + } + } + + public void setSelectedWallpaper(TLRPC.WallPaper wallpaper, TLRPC.WallPaper galleryWallpaper) { + selectedWallpaper = wallpaper; + this.galleryWallpaper = galleryWallpaper; + } + + private Utilities.Callback3 onSelectedWallpaperChange; + public void setOnSelectedWallpaperChange(Utilities.Callback3 listener) { + onSelectedWallpaperChange = listener; + } + + public FrameLayout contentView; + public RecyclerListView listView; + public Adapter adapter; + public boolean isDark() { + return resourceProvider != null ? resourceProvider.isDark() : Theme.isCurrentThemeDark(); + } + + private RLottieDrawable sunDrawable; + private ActionBarMenuItem dayNightItem; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setTitle(LocaleController.getString(R.string.ChannelWallpaper)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == 1) { + toggleTheme(); + } + } + }); + + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (!isDark()) { + sunDrawable.setCustomEndFrame(0); + sunDrawable.setCurrentFrame(0); + } else { + sunDrawable.setCurrentFrame(35); + sunDrawable.setCustomEndFrame(36); + } + sunDrawable.beginApplyLayerColors(); + int color = Theme.getColor(Theme.key_chats_menuName, resourceProvider); + sunDrawable.setLayerColor("Sunny.**", color); + sunDrawable.setLayerColor("Path 6.**", color); + sunDrawable.setLayerColor("Path.**", color); + sunDrawable.setLayerColor("Path 5.**", color); + if (resourceProvider instanceof ChannelColorActivity.ThemeDelegate) { + dayNightItem = actionBar.createMenu().addItem(1, sunDrawable); + } + + contentView = new FrameLayout(context); + + updateRows(); + listView = new RecyclerListView(context, resourceProvider); + listView.setAdapter(adapter = new Adapter()); + listView.setLayoutManager(new LinearLayoutManager(context)); + contentView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + listView.setOnItemClickListener((view, position) -> { + if (position == removeRow) { + galleryWallpaper = null; + selectedWallpaper = null; + if (onSelectedWallpaperChange != null) { + onSelectedWallpaperChange.run(currentWallpaper, selectedWallpaper, galleryWallpaper); + } + + View themesView = findChildAt(themesRow); + if (themesView instanceof ChannelColorActivity.ThemeChooser) { + ((ChannelColorActivity.ThemeChooser) themesView).setGalleryWallpaper(galleryWallpaper); + } + updateRows(); + } else if (position == galleryRow) { + ChatThemeBottomSheet.openGalleryForBackground(getParentActivity(), this, dialogId, resourceProvider, wallpaper -> { + galleryWallpaper = currentWallpaper = selectedWallpaper = wallpaper; + if (onSelectedWallpaperChange != null) { + onSelectedWallpaperChange.run(currentWallpaper, selectedWallpaper, galleryWallpaper); + } + finishFragment(); + }, toggleThemeDelegate, boostsStatus); + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); + + updateColors(); + + return fragmentView = contentView; + } + + public View findChildAt(int position) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == position) { + return child; + } + } + return null; + } + + public static final int VIEW_TYPE_BUTTON = 0; + public static final int VIEW_TYPE_INFO = 1; + public static final int VIEW_TYPE_THEMES = 2; + + public int rowsCount = 0; + public int galleryRow = -1; + public int removeRow = -1; + public int infoRow = -1; + public int themesRow = -1; + + public void updateRows() { + rowsCount = 0; + galleryRow = rowsCount++; + final int wasRemoveRow = removeRow; + if (galleryWallpaper != null) { + removeRow = rowsCount++; + } else { + removeRow = -1; + } + if (adapter != null) { + if (removeRow != -1 && wasRemoveRow == -1) { + adapter.notifyItemInserted(removeRow); + } + if (removeRow == -1 && wasRemoveRow != -1) { + adapter.notifyItemRemoved(wasRemoveRow); + } + } + infoRow = rowsCount++; + themesRow = rowsCount++; + } + + public class Adapter extends RecyclerListView.SelectionAdapter { + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_BUTTON) { + TextCell textCell = new TextCell(getContext(), resourceProvider); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + } else if (viewType == VIEW_TYPE_THEMES) { + ChannelColorActivity.ThemeChooser themesWallpaper = new ChannelColorActivity.ThemeChooser(getContext(), true, currentAccount, resourceProvider); + themesWallpaper.setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(selectedWallpaper), false); + themesWallpaper.setGalleryWallpaper(galleryWallpaper); + themesWallpaper.setOnEmoticonSelected(emoticon -> { + if (emoticon == null) { + selectedWallpaper = galleryWallpaper; + themesWallpaper.setSelectedEmoticon(null, false); + if (onSelectedWallpaperChange != null) { + onSelectedWallpaperChange.run(currentWallpaper, selectedWallpaper, galleryWallpaper); + } + updateRows(); + return; + } + + ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.EmojiWallpaper(emoticon), null) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + themePreviewActivity.boostsStatus = boostsStatus; + themePreviewActivity.setOnSwitchDayNightDelegate(toggleThemeDelegate); + themePreviewActivity.setResourceProvider(resourceProvider); + themePreviewActivity.setInitialModes(false, false, .20f); + themePreviewActivity.setDialogId(dialogId); + themePreviewActivity.setDelegate(wallPaper -> { + selectedWallpaper = new TLRPC.TL_wallPaperNoFile(); + selectedWallpaper.id = 0; + selectedWallpaper.flags |= 4; + selectedWallpaper.settings = new TLRPC.TL_wallPaperSettings(); + selectedWallpaper.settings.emoticon = emoticon; + themesWallpaper.setSelectedEmoticon(emoticon, false); + if (onSelectedWallpaperChange != null) { + onSelectedWallpaperChange.run(currentWallpaper, selectedWallpaper, galleryWallpaper); + } + updateRows(); + finishFragment(); + }); + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + params.occupyNavigationBar = true; + showAsSheet(themePreviewActivity, params); + }); + themesWallpaper.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = themesWallpaper; + } else { + view = new TextInfoPrivacyCell(getContext()); + } + return new RecyclerListView.Holder(view); + } + + @Override + public int getItemViewType(int position) { + if (position == galleryRow || position == removeRow) { + return VIEW_TYPE_BUTTON; + } + if (position == themesRow) { + return VIEW_TYPE_THEMES; + } + return VIEW_TYPE_INFO; + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position == galleryRow) { + ((TextCell) holder.itemView).setTextAndIcon(LocaleController.getString(R.string.ChooseFromGallery2), R.drawable.msg_background, removeRow != -1); + ((TextCell) holder.itemView).setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); + } else if (position == removeRow) { + ((TextCell) holder.itemView).setTextAndIcon(LocaleController.getString(R.string.ChannelWallpaperRemove), R.drawable.msg_delete, false); + ((TextCell) holder.itemView).setColors(Theme.key_text_RedRegular, Theme.key_text_RedRegular); + } else if (position == infoRow) { + ((TextInfoPrivacyCell) holder.itemView).setText(LocaleController.getString(R.string.ChannelWallpaperInfo)); + ((TextInfoPrivacyCell) holder.itemView).setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + ((TextInfoPrivacyCell) holder.itemView).setForeground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow, resourceProvider)); + } else if (position == themesRow) { + ((ChannelColorActivity.ThemeChooser) holder.itemView).setGalleryWallpaper(galleryWallpaper); + } + } + + @Override + public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { + if (holder.itemView instanceof ChannelColorActivity.ThemeChooser) { + ((ChannelColorActivity.ThemeChooser) holder.itemView).setGalleryWallpaper(galleryWallpaper); + } + super.onViewAttachedToWindow(holder); + } + + @Override + public int getItemCount() { + return rowsCount; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_BUTTON; + } + } + + public void updateColors() { + actionBar.setBackgroundColor(getThemedColor(Theme.key_actionBarDefault)); + actionBar.setTitleColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); + actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSelector), false); + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + adapter.notifyDataSetChanged(); + AndroidUtilities.forEachViews(listView, this::updateColors); + setNavigationBarColor(getNavigationBarColor()); + contentView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + } + + private void updateColors(View view) { + if (view instanceof TextInfoPrivacyCell) { + ((TextInfoPrivacyCell) view).setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + ((TextInfoPrivacyCell) view).setForeground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow, resourceProvider)); + } else { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + if (view instanceof TextCell) { + ((TextCell) view).updateColors(); + } else if (view instanceof ChannelColorActivity.ThemeChooser) { + ((ChannelColorActivity.ThemeChooser) view).updateColors(); + } + } + } + + public ThemePreviewActivity.DayNightSwitchDelegate toggleThemeDelegate = new ThemePreviewActivity.DayNightSwitchDelegate() { + @Override + public boolean isDark() { + return ChannelWallpaperActivity.this.isDark(); + } + + @Override + public void switchDayNight(boolean animated) { + if (resourceProvider instanceof ChannelColorActivity.ThemeDelegate) { + ((ChannelColorActivity.ThemeDelegate) resourceProvider).toggle(); + } + setForceDark(isDark(), false); + updateColors(); + } + + @Override + public boolean supportsAnimation() { + return false; + } + }; + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + @SuppressLint("NotifyDataSetChanged") + public void toggleTheme() { + FrameLayout decorView1 = (FrameLayout) getParentActivity().getWindow().getDecorView(); + Bitmap bitmap = Bitmap.createBitmap(decorView1.getWidth(), decorView1.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + dayNightItem.setAlpha(0f); + decorView1.draw(bitmapCanvas); + dayNightItem.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + dayNightItem.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + dayNightItem.getMeasuredWidth() / 2f; + float cy = y + dayNightItem.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isDark()) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + dayNightItem.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setDuration(400); + changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad); + changeDayNightViewAnimator.start(); + + decorView1.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + if (resourceProvider instanceof ChannelColorActivity.ThemeDelegate) { + ((ChannelColorActivity.ThemeDelegate) resourceProvider).toggle(); + } + setForceDark(isDark(), true); + updateColors(); + }); + } + + public void setForceDark(boolean isDark, boolean playAnimation) { + if (playAnimation) { + sunDrawable.setCustomEndFrame(isDark ? sunDrawable.getFramesCount() : 0); + if (sunDrawable != null) { + sunDrawable.start(); + } + } else { + int frame = isDark ? sunDrawable.getFramesCount() - 1 : 0; + sunDrawable.setCurrentFrame(frame, false, true); + sunDrawable.setCustomEndFrame(frame); + if (dayNightItem != null) { + dayNightItem.invalidate(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java index 4d8313fcf..521358921 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java @@ -73,17 +73,17 @@ public class ChartHorizontalLinesData { boolean skipFloatValues = step / k < 1; for (int i = 0; i < n; i++) { values[i] = newMinHeight + (int) (i * step); - valuesStr[i] = AndroidUtilities.formatWholeNumber(values[i], dif); + valuesStr[i] = AndroidUtilities.formatWholeNumber(values[i], 0); if (k > 0) { float v = (values[i] / k); if (skipFloatValues) { if (v - ((int) v) < 0.01f) { - valuesStr2[i] = AndroidUtilities.formatWholeNumber((int) v, (int) (dif / k)); + valuesStr2[i] = AndroidUtilities.formatWholeNumber((int) v, 0); } else { valuesStr2[i] = ""; } } else { - valuesStr2[i] = AndroidUtilities.formatWholeNumber((int) v, (int) (dif / k)); + valuesStr2[i] = AndroidUtilities.formatWholeNumber((int) v, 0); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index c6dcf3daa..5f02c4186 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -50,6 +50,7 @@ import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -199,122 +200,33 @@ import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.MentionCell; +import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Cells.StickerCell; import org.telegram.ui.Cells.TextSelectionHelper; -import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.AnimatedEmojiDrawable; -import org.telegram.ui.Components.AnimatedEmojiSpan; -import org.telegram.ui.Components.AnimatedFileDrawable; -import org.telegram.ui.Components.AnimationProperties; -import org.telegram.ui.Components.AttachBotIntroTopView; -import org.telegram.ui.Components.AudioPlayerAlert; -import org.telegram.ui.Components.AutoDeletePopupWrapper; -import org.telegram.ui.Components.BackButtonMenu; -import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.Components.BlurBehindDrawable; -import org.telegram.ui.Components.BluredView; -import org.telegram.ui.Components.BlurredFrameLayout; -import org.telegram.ui.Components.BotCommandsMenuView; -import org.telegram.ui.Components.BotWebViewSheet; -import org.telegram.ui.Components.Bulletin; -import org.telegram.ui.Components.BulletinFactory; -import org.telegram.ui.Components.ChatActivityEnterTopView; -import org.telegram.ui.Components.ChatActivityEnterView; -import org.telegram.ui.Components.ChatActivityInterface; -import org.telegram.ui.Components.ChatAttachAlert; -import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; -import org.telegram.ui.Components.ChatAvatarContainer; -import org.telegram.ui.Components.ChatBigEmptyView; -import org.telegram.ui.Components.ChatGreetingsView; -import org.telegram.ui.Components.ChatNotificationsPopupWrapper; -import org.telegram.ui.Components.ChatScrimPopupContainerLayout; -import org.telegram.ui.Components.ChatThemeBottomSheet; -import org.telegram.ui.Components.ChecksHintView; -import org.telegram.ui.Components.CircularProgressDrawable; -import org.telegram.ui.Components.ClippingImageView; -import org.telegram.ui.Components.CombinedDrawable; -import org.telegram.ui.Components.CounterView; -import org.telegram.ui.Components.CrossfadeDrawable; -import org.telegram.ui.Components.CubicBezierInterpolator; -import org.telegram.ui.Components.EditTextBoldCursor; -import org.telegram.ui.Components.EditTextCaption; -import org.telegram.ui.Components.EmbedBottomSheet; -import org.telegram.ui.Components.EmojiPacksAlert; -import org.telegram.ui.Components.EmojiView; -import org.telegram.ui.Components.ExtendedGridLayoutManager; -import org.telegram.ui.Components.FireworksOverlay; +import org.telegram.ui.Components.*; 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.FragmentContextView; -import org.telegram.ui.Components.GigagroupConvertAlert; -import org.telegram.ui.Components.HideViewAfterAnimation; -import org.telegram.ui.Components.HintView; -import org.telegram.ui.Components.ImageUpdater; -import org.telegram.ui.Components.ImportingAlert; -import org.telegram.ui.Components.InstantCameraView; -import org.telegram.ui.Components.InviteMembersBottomSheet; -import org.telegram.ui.Components.JoinGroupAlert; -import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.LinkSpanDrawable; -import org.telegram.ui.Components.MediaActivity; -import org.telegram.ui.Components.MentionsContainerView; -import org.telegram.ui.Components.MessageBackgroundDrawable; -import org.telegram.ui.Components.MessageContainsEmojiButton; -import org.telegram.ui.Components.MessagePreviewView; -import org.telegram.ui.Components.MotionBackgroundDrawable; -import org.telegram.ui.Components.NumberTextView; -import org.telegram.ui.Components.PhonebookShareAlert; -import org.telegram.ui.Components.PinnedLineView; -import org.telegram.ui.Components.PipRoundVideoView; -import org.telegram.ui.Components.PollVotesAlert; -import org.telegram.ui.Components.PopupSwipeBackLayout; 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; import org.telegram.ui.Components.Premium.boosts.GiftInfoBottomSheet; -import org.telegram.ui.Components.RLottieDrawable; -import org.telegram.ui.Components.RLottieImageView; -import org.telegram.ui.Components.RadialProgressView; -import org.telegram.ui.Components.ReactedHeaderView; -import org.telegram.ui.Components.ReactedUsersListView; -import org.telegram.ui.Components.ReactionTabHolderView; +import org.telegram.ui.Components.Premium.boosts.PremiumPreviewGiftLinkBottomSheet; import org.telegram.ui.Components.Reactions.ChatSelectionReactionMenuOverlay; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; -import org.telegram.ui.Components.ReactionsContainerLayout; -import org.telegram.ui.Components.RecyclerAnimationScrollHelper; -import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.Components.ReportAlert; -import org.telegram.ui.Components.SearchCounterView; -import org.telegram.ui.Components.ShareAlert; -import org.telegram.ui.Components.SharedMediaLayout; -import org.telegram.ui.Components.SizeNotifierFrameLayout; -import org.telegram.ui.Components.StickersAlert; -import org.telegram.ui.Components.SuggestEmojiView; -import org.telegram.ui.Components.TextSelectionHint; -import org.telegram.ui.Components.TextStyleSpan; -import org.telegram.ui.Components.ThemeEditorView; -import org.telegram.ui.Components.TranscribeButton; -import org.telegram.ui.Components.TranslateAlert2; -import org.telegram.ui.Components.TranslateButton; -import org.telegram.ui.Components.TrendingStickersAlert; -import org.telegram.ui.Components.TypefaceSpan; -import org.telegram.ui.Components.URLSpanBotCommand; -import org.telegram.ui.Components.URLSpanMono; -import org.telegram.ui.Components.URLSpanNoUnderline; -import org.telegram.ui.Components.URLSpanReplacement; -import org.telegram.ui.Components.URLSpanUserMention; -import org.telegram.ui.Components.UndoView; -import org.telegram.ui.Components.UnreadCounterTextView; -import org.telegram.ui.Components.ViewHelper; 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.PreviewView; +import org.telegram.ui.Stories.recorder.StoryEntry; +import org.telegram.ui.Stories.recorder.StoryRecorder; import java.io.BufferedWriter; import java.io.File; @@ -393,6 +305,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ActionBarMenuItem.Item closeTopicItem; private ActionBarMenuItem.Item openForumItem; private ClippingImageView animatingImageView; + private ThanosEffect chatListThanosEffect; private RecyclerListView chatListView; private ChatListItemAnimator chatListItemAnimator; private GridLayoutManagerFixed chatLayoutManager; @@ -920,8 +833,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean openImport; - private float chatListViewPaddingTop; - private int chatListViewPaddingVisibleOffset; + public float chatListViewPaddingTop; + public int chatListViewPaddingVisibleOffset; private int contentPaddingTop; private float contentPanTranslation; @@ -965,6 +878,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }; private ChatSelectionReactionMenuOverlay selectionReactionsOverlay; + private SecretVoicePlayer secretVoicePlayer; private boolean isPauseOnThemePreview; private ChatThemeBottomSheet chatThemeBottomSheet; @@ -1209,7 +1123,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } })); } - return items; } @@ -1696,7 +1609,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.getEmojiView().onMessageSend(); } - if (!getMessagesController().premiumLocked && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && !TextUtils.isEmpty(message) && messages != null) { + if (!getMessagesController().premiumFeaturesBlocked() && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && !TextUtils.isEmpty(message) && messages != null) { for (int i = 1; i < Math.min(5, messages.size()); ++i) { MessageObject msg = messages.get(i); if (msg != null && !msg.isOutOwner() && (msg.isVoice() || msg.isRoundVideo()) && msg.isContentUnread()) { @@ -1992,7 +1905,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { + public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { checkInstantCameraView(); if (instantCameraView != null) { if (state == 0) { @@ -2000,7 +1913,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.stopScroll(); chatAdapter.updateRowsSafe(); } else if (state == 1 || state == 3 || state == 4) { - instantCameraView.send(state, notify, scheduleDate); + instantCameraView.send(state, notify, scheduleDate, ttl); } else if (state == 2 || state == 5) { instantCameraView.cancel(state == 2); } @@ -2134,6 +2047,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checkAdjustResize(); } + @Override + public boolean onceVoiceAvailable() { + return currentUser != null && !UserObject.isUserSelf(currentUser) && !currentUser.bot && currentEncryptedChat == null && chatMode == 0; + } + @Override public ReplyQuote getReplyQuote() { return replyingQuote; @@ -2561,7 +2479,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } themeDelegate = new ThemeDelegate(); - if (themeDelegate.isThemeChangeAvailable()) { + if (themeDelegate.isThemeChangeAvailable(false)) { NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.needSetDayNightTheme); } @@ -3566,7 +3484,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat != null && !isTopic) { viewAsTopics = headerItem.lazilyAddSubItem(view_as_topics, R.drawable.msg_topics, LocaleController.getString("TopicViewAsTopics", R.string.TopicViewAsTopics)); } - if (themeDelegate.isThemeChangeAvailable()) { + if (themeDelegate.isThemeChangeAvailable(true)) { headerItem.lazilyAddSubItem(change_colors, R.drawable.msg_colors, LocaleController.getString("SetWallpapers", R.string.SetWallpapers)); } if (!isTopic) { @@ -3767,6 +3685,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + protected boolean allowSelectChildAtPosition(View child) { + if (child != null && child.getVisibility() == View.INVISIBLE) return false; + return super.allowSelectChildAtPosition(child); + } + @Override protected void onMeasure(int widthSpec, int heightSpec) { saveScrollPosition(); @@ -4625,6 +4549,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0; a < count; a++) { View child = getChildAt(a); + if (child.getVisibility() == View.INVISIBLE || child.getVisibility() == View.GONE) { + continue; + } if (chatAdapter.isBot && child instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) child; float top = (getMeasuredHeight() - chatListViewPaddingTop - blurredViewBottomOffset) / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; @@ -4756,7 +4683,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not View child = chatListView.getChildAt(i); if (child instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) child; - if (child.getY() > chatListView.getHeight() || child.getY() + child.getHeight() < 0) { + if (child.getY() > chatListView.getHeight() || child.getY() + child.getHeight() < 0 || cell.getVisibility() == View.GONE) { continue; } MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); @@ -4889,7 +4816,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ChatActionCell actionCell = null; float cilpTop = chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4); - if (child.getY() > getMeasuredHeight() || child.getY() + child.getMeasuredHeight() < cilpTop) { + if (child.getY() > getMeasuredHeight() || child.getY() + child.getMeasuredHeight() < cilpTop || child.getVisibility() == View.INVISIBLE || child.getVisibility() == View.GONE) { skipDraw = true; } @@ -5031,7 +4958,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ImageReceiver imageReceiver = cell.getAvatarImage(); if (imageReceiver != null) { MessageObject.GroupedMessages groupedMessages = getValidGroupedMessage(message); - if (cell.getMessageObject().deleted) { + if (cell.getMessageObject().deleted && !cell.getMessageObject().deletedByThanos) { if (child.getTranslationY() != 0) { canvas.restore(); } @@ -5361,6 +5288,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } }; + chatListItemAnimator.setOnSnapMessage(this::supportsThanosEffect, this::getChatThanosEffect); } chatLayoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, true) { @@ -5662,6 +5590,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { chatListView.invalidate(); + if (chatListThanosEffect != null) { + chatListThanosEffect.scroll(dx, dy); + } scrollUp = dy < 0; int firstVisibleItem = chatLayoutManager.findFirstVisibleItemPosition(); if (dy != 0 && (scrollByTouch && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) || recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) { @@ -11211,6 +11142,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } textToCheck = charSequence; } + final String firstUrl = urls == null || urls.isEmpty() ? null : urls.get(0).toString(); if (currentEncryptedChat != null && messagesController.secretWebpagePreview == 2) { AndroidUtilities.runOnUIThread(() -> { @@ -11983,7 +11915,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageObjectToReply = messageObjectsToForward.get(0); } } else if (type == MessageObject.TYPE_GIVEAWAY) { - text = LocaleController.getString("BoostingGiveaway", R.string.BoostingGiveaway);; + text = LocaleController.getString("BoostingGiveaway", R.string.BoostingGiveaway); + } else if (type == MessageObject.TYPE_GIVEAWAY_RESULTS) { + text = LocaleController.getString("BoostingGiveawayResults", R.string.BoostingGiveawayResults); } else if (type == MessageObject.TYPE_GEO) { text = LocaleController.formatPluralString("PreviewForwardLocation", messageObjectsToForward.size()); } else if (type == MessageObject.TYPE_VIDEO) { @@ -13546,6 +13480,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public class ChatActivityFragmentView extends SizeNotifierFrameLayout { + public ChatActivity getChatActivity() { + return ChatActivity.this; + } + public ChatActivityFragmentView(Context context, INavigationLayout parentLayout) { super(context, parentLayout); adjustPanLayoutHelper = new AdjustPanLayoutHelper(this) { @@ -14491,7 +14429,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int contentHeightSpec = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY); child.measure(contentWidthSpec, contentHeightSpec); - } else if (child == chatListView) { + } else if (child == chatListView || child == chatListThanosEffect) { int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int h = heightSize - listViewTopHeight - (inPreviewMode && Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) + blurredViewTopOffset + blurredViewBottomOffset; if (keyboardSize > AndroidUtilities.dp(20) && getLayoutParams().height < 0) { @@ -14710,7 +14648,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (child == gifHintTextView || child == voiceHintTextView || child == mediaBanTooltip || child == emojiHintTextView) { childTop -= inputFieldHeight; - } else if (child == chatListView || child == floatingDateView || child == infoTopView) { + } else if (child == chatListView || child == chatListThanosEffect || child == floatingDateView || child == infoTopView) { childTop -= blurredViewTopOffset; if (!inPreviewMode) { childTop -= (inputFieldHeight - AndroidUtilities.dp(51)); @@ -15569,7 +15507,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (chatMode == MODE_PINNED) { avatarContainer.setTitle(LocaleController.formatPluralString("PinnedMessagesCount", getPinnedMessagesCount())); } else if (currentChat != null) { - avatarContainer.setTitle(currentChat.title, currentChat.scam, currentChat.fake, currentChat.verified, false, null, animated); + avatarContainer.setTitle(currentChat.title, currentChat.scam, currentChat.fake, currentChat.verified, false, currentChat.emoji_status, animated); } else if (currentUser != null) { if (currentUser.self) { avatarContainer.setTitle(LocaleController.getString("SavedMessages", R.string.SavedMessages)); @@ -18825,7 +18763,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (chatActivityEnterView != null) { chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands, true); - hasBotWebView = getMessagesController().getUser(info.user_id).bot_menu_webview; + TLRPC.User bot = getMessagesController().getUser(info.user_id); + hasBotWebView = bot != null && bot.bot_menu_webview; chatActivityEnterView.updateBotWebView(true); } } @@ -20802,6 +20741,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void processDeletedMessages(ArrayList markAsDeletedMessages, long channelId) { ArrayList removedIndexes = new ArrayList<>(); + ArrayList messagesIndexes = new ArrayList<>(); int loadIndex = 0; if (ChatObject.isChannel(currentChat)) { if (channelId == 0 && mergeDialogId != 0) { @@ -20902,6 +20842,10 @@ 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); + removed.deletedByThanos = LiteMode.isEnabled(LiteMode.FLAG_CHAT_THANOS); + } } if (removed.getGroupId() != 0) { MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(removed.getGroupId()); @@ -21017,7 +20961,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int prevLoadingUpRow = chatAdapter.loadingUpRow; int prevLoadingDownRow = chatAdapter.loadingDownRow; for (int a = 0, N = removedIndexes.size(); a < N; a++) { - chatAdapter.notifyItemRemoved(removedIndexes.get(a)); + final int pos = removedIndexes.get(a); + chatAdapter.notifyItemRemoved(pos, messagesIndexes.contains(pos)); } if (!isThreadChat() || messages.size() <= 3) { removeUnreadPlane(false); @@ -21383,7 +21328,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onBecomeFullyHidden() { - if (!getMessagesController().premiumLocked && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && messages != null) { + if (!getMessagesController().premiumFeaturesBlocked() && getMessagesController().transcribeAudioTrialWeeklyNumber <= 0 && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && messages != null) { for (int i = 0; i < messages.size(); ++i) { MessageObject msg = messages.get(i); if (msg != null && !msg.isOutOwner() && (msg.isVoice() || msg.isRoundVideo()) && !msg.isUnread() && (msg.isContentUnread() || ChatObject.isChannelAndNotMegaGroup(currentChat))) { @@ -23174,7 +23119,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean showTranslate = ( getUserConfig().isPremium() ? getMessagesController().getTranslateController().isDialogTranslatable(getDialogId()) && !getMessagesController().getTranslateController().isTranslateDialogHidden(getDialogId()) : - !getMessagesController().premiumLocked && preferences.getInt("dialog_show_translate_count" + did, 5) <= 0 + !getMessagesController().premiumFeaturesBlocked() && preferences.getInt("dialog_show_translate_count" + did, 5) <= 0 ); if (showRestartTopic) { shownRestartTopic = true; @@ -24459,13 +24404,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final int type = getMessageType(message); if (single) { boolean isGiveawayResultsMessage = false; - if (message.messageOwner.action instanceof TLRPC.TL_messageActionCustomAction) { - TLRPC.TL_messageActionCustomAction customAction = (TLRPC.TL_messageActionCustomAction) message.messageOwner.action; - if (customAction.message != null && customAction.message.contains("giveaway")) { - //fallback for old versions - isGiveawayResultsMessage = true; - } - } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + if (message.messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { isGiveawayResultsMessage = true; } if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || isGiveawayResultsMessage) { @@ -24520,7 +24459,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { - showChatThemeBottomSheet(); + if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { + showChatThemeBottomSheet(); + } return true; } } @@ -24606,7 +24547,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.msg_user_search); } - if (!getUserConfig().isPremium() && !getMessagesController().premiumLocked && 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()))) { items.add(LocaleController.getString(R.string.PremiumSpeedPromo)); options.add(OPTION_SPEED_PROMO); icons.add(R.drawable.msg_speed); @@ -24680,7 +24621,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageTextToTranslate = null; } - if (message.isSponsored() && !getMessagesController().premiumLocked) { + if (message.isSponsored() && !getUserConfig().isPremium() && !getMessagesController().premiumFeaturesBlocked()) { items.add(LocaleController.getString("HideAd", R.string.HideAd)); options.add(OPTION_HIDE_SPONSORED_MESSAGE); icons.add(R.drawable.msg_block2); @@ -26056,7 +25997,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - if (stickerSets.size() > 0 && !getMessagesController().premiumLocked) { + if (stickerSets.size() > 0 && !getMessagesController().premiumFeaturesBlocked()) { View gap = new FrameLayout(contentView.getContext()); gap.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuSeparator)); popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); @@ -27617,7 +27558,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean onBackPressed() { - if (closeStoryViewer()) { + if (secretVoicePlayer != null && secretVoicePlayer.isShown()) { + secretVoicePlayer.dismiss(); + return false; + } else if (closeStoryViewer()) { return false; } else if (selectionReactionsOverlay != null && !selectionReactionsOverlay.onBackPressed()) { return false; @@ -27856,7 +27800,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject.getDialogId() == mergeDialogId && startMessageObject.getDialogId() != mergeDialogId) { continue; } - if ((currentEncryptedChat == null && messageObject.getId() > messageId || currentEncryptedChat != null && messageObject.getId() < messageId) && (messageObject.isVoice() || messageObject.isRoundVideo()) && (!playingUnreadMedia || messageObject.isContentUnread() && !messageObject.isOut())) { + if ((currentEncryptedChat == null && messageObject.getId() > messageId || currentEncryptedChat != null && messageObject.getId() < messageId) && (messageObject.isVoice() || messageObject.isRoundVideo()) && !messageObject.isVoiceOnce() && !messageObject.isRoundOnce() && (!playingUnreadMedia || messageObject.isContentUnread() && !messageObject.isOut())) { messageObjects.add(messageObject); } } @@ -29238,14 +29182,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((ChatActionCell) view).setInvalidateColors(true); ((ChatActionCell) view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { @Override - public void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, boolean animateConfetti) { - showDialog(new PremiumPreviewBottomSheet(ChatActivity.this, currentAccount, getCurrentUser(), new GiftPremiumBottomSheet.GiftTier(giftOption), themeDelegate) - .setAnimateConfetti(animateConfetti) - .setOutboundGift(cell.getMessageObject().isOut())); + public void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, String slug, boolean animateConfetti) { + if (slug != null) { + initGiftProgressDialog(cell); + PremiumPreviewGiftLinkBottomSheet.show(slug, giftOption, getCurrentUser(), progressDialogCurrent); + } else { + showDialog(new PremiumPreviewBottomSheet(ChatActivity.this, currentAccount, getCurrentUser(), new GiftPremiumBottomSheet.GiftTier(giftOption), themeDelegate) + .setAnimateConfetti(animateConfetti) + .setOutboundGift(cell.getMessageObject().isOut())); + } } @Override public void didOpenPremiumGiftChannel(ChatActionCell cell, String slug, boolean animateConfetti) { + initGiftProgressDialog(cell); + GiftInfoBottomSheet.show(getBaseFragment(), slug, progressDialogCurrent); + } + + private void initGiftProgressDialog(ChatActionCell cell) { if (progressDialogCurrent != null) { progressDialogCurrent.cancel(true); } @@ -29270,7 +29224,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }; - GiftInfoBottomSheet.show(getBaseFragment(), slug, progressDialogCurrent); } @Override @@ -29320,7 +29273,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (cell.hasButton()) { ThemePreviewActivity.showFor(ChatActivity.this, message); - } else { + } else if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { showChatThemeBottomSheet(); } return; @@ -30263,6 +30216,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + public void notifyItemRemoved(int position, boolean thanos) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("notify item removed " + position + (thanos ? " with thanos effect" : "")); + } + if (!fragmentBeginToShow) { + chatListView.setItemAnimator(null); + } else if (chatListView.getItemAnimator() != chatListItemAnimator) { + chatListView.setItemAnimator(chatListItemAnimator); + } + if (thanos && chatListItemAnimator != null && chatListView.getItemAnimator() == chatListItemAnimator) { + chatListItemAnimator.prepareThanos(chatListView.findViewHolderForAdapterPosition(position)); + } + updateRowsInternal(); + try { + super.notifyItemRemoved(position); + } catch (Exception e) { + FileLog.e(e); + } + } + @Override public void notifyItemRangeRemoved(int positionStart, int itemCount) { if (BuildVars.LOGS_ENABLED) { @@ -30555,7 +30528,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not arrayList = new ArrayList<>(); arrayList.add(messageObject); } - showDialog(new ShareAlert(getContext(), ChatActivity.this, arrayList, null, null, ChatObject.isChannel(currentChat), null, null, false, false, false, themeDelegate) { + final boolean includeStory = getMessagesController().storiesEnabled() && StoryEntry.canRepostMessage(messageObject); + showDialog(new ShareAlert(getContext(), ChatActivity.this, arrayList, null, null, ChatObject.isChannel(currentChat), null, null, false, false, includeStory, themeDelegate) { + { includeStoryFromMessage = includeStory; } @Override public void dismissInternal() { super.dismissInternal(); @@ -30565,6 +30540,50 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + protected void onShareStory(View cell) { + StoryRecorder.SourceView sourceView = null; + if (cell instanceof ShareDialogCell) { + sourceView = StoryRecorder.SourceView.fromShareCell((ShareDialogCell) cell); + } + final ArrayList messageObjects = new ArrayList<>(); + MessageObject.GroupedMessages groupedMessages = messageObject.getGroupId() != 0 ? groupedMessagesMap.get(messageObject.getGroupId()) : null; + if (groupedMessages != null) { + messageObjects.addAll(groupedMessages.messages); + } else { + messageObjects.add(messageObject); + } + StoryRecorder editor = StoryRecorder.getInstance(getParentActivity(), currentAccount); + editor.setOnPrepareCloseListener((t, close, sent, did) -> { + if (sent) { + AndroidUtilities.runOnUIThread(() -> { + String chatTitle = ""; + if (did < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-did); + if (chat != null) { + chatTitle = chat.title; + } + } + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.contact_check, AndroidUtilities.replaceTags( + TextUtils.isEmpty(chatTitle) ? + LocaleController.getString(R.string.RepostedToProfile) : + LocaleController.formatString(R.string.RepostedToChannelProfile, chatTitle) + )).show(); + }); + dismiss(); + editor.replaceSourceView(null); + } else { + StoryRecorder.SourceView sourceView2 = null; + if (cell instanceof ShareDialogCell && cell.isAttachedToWindow()) { + sourceView2 = StoryRecorder.SourceView.fromShareCell((ShareDialogCell) cell); + } + editor.replaceSourceView(sourceView2); + } + AndroidUtilities.runOnUIThread(close); + }); + editor.openRepost(sourceView, StoryEntry.repostMessage(messageObjects)); + } + @Override protected void onSend(LongSparseArray dids, int count, TLRPC.TL_forumTopic topic) { createUndoView(); @@ -30584,8 +30603,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public boolean needPlayMessage(MessageObject messageObject, boolean muted) { - if (messageObject.isVoice() || messageObject.isRoundVideo()) { + public boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { + if (messageObject.isVoiceOnce()) { + if (secretVoicePlayer != null && secretVoicePlayer.isShown()) return false; + try { + AudioManager audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE); + int stream = AudioManager.STREAM_MUSIC; + int volume = audioManager.getStreamVolume(stream); + if (volume == 0) { + audioManager.adjustStreamVolume(stream, volume, AudioManager.FLAG_SHOW_UI); + if (!messageObject.isOutOwner()) { + BulletinFactory.of(ChatActivity.this).createImageBulletin(R.drawable.tooltip_sound, LocaleController.getString(R.string.VoiceOnceTurnOnSound)).show(true); + return false; + } + } + } catch (Exception ignore) {} + secretVoicePlayer = new SecretVoicePlayer(getContext()); + secretVoicePlayer.setCell( + cell, + !messageObject.isOutOwner() ? sendSecretMessageRead(messageObject, true) : null, + !messageObject.isOutOwner() ? sendSecretMediaDelete(messageObject) : null + ); + showDialog(secretVoicePlayer); + return false; + } else if (messageObject.isVoice() || messageObject.isRoundVideo()) { boolean result = MediaController.getInstance().playMessage(messageObject, muted); MediaController.getInstance().setVoiceMessagesPlaylist(result ? createVoiceMessagesPlaylist(messageObject, false) : null, false); return result; @@ -31286,7 +31327,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean didPressAnimatedEmoji(ChatMessageCell cell, AnimatedEmojiSpan span) { - if (getMessagesController().premiumLocked || span == null || span.standard) { + if (getMessagesController().premiumFeaturesBlocked() || span == null || span.standard) { return false; } long documentId = span.getDocumentId(); @@ -31350,6 +31391,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (uri == null) { return; } + if (!safe && Browser.isTelegraphUrl(url, false)) { + safe = true; + } if (progressDialogCurrent != null) { progressDialogCurrent.cancel(true); } @@ -31842,14 +31886,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didPressGiveawayChatButton(ChatMessageCell cell, int pressedPos) { - TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) cell.getMessageObject().messageOwner.media; - long channelId = giveaway.channels.get(pressedPos); - if (dialog_id != -channelId) { - presentFragment(ChatActivity.of(-channelId)); - } else { - ViewGroup v = getChatListView(); - AndroidUtilities.shakeViewSpring(v, 5); - BotWebViewVibrationEffect.APP_ERROR.vibrate(); + if (cell.getMessageObject().messageOwner.media instanceof TLRPC.TL_messageMediaGiveaway) { + TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) cell.getMessageObject().messageOwner.media; + long channelId = giveaway.channels.get(pressedPos); + if (dialog_id != -channelId) { + presentFragment(ChatActivity.of(-channelId)); + } else { + ViewGroup v = getChatListView(); + AndroidUtilities.shakeViewSpring(v, 5); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + } + } + if (cell.getMessageObject().messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + TLRPC.TL_messageMediaGiveawayResults giveaway = (TLRPC.TL_messageMediaGiveawayResults) cell.getMessageObject().messageOwner.media; + long id = giveaway.winners.get(pressedPos); + presentFragment(ProfileActivity.of(id)); } } @@ -32366,7 +32417,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{msgOutDrawable, msgOutMediaDrawable}, null, Theme.key_chat_outBubble)); - if (!themeDelegate.isThemeChangeAvailable()) { + if (!themeDelegate.isThemeChangeAvailable(false)) { themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{msgOutDrawable, msgOutMediaDrawable}, null, Theme.key_chat_outBubbleGradient1)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{msgOutDrawable, msgOutMediaDrawable}, null, Theme.key_chat_outBubbleGradient2)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{msgOutDrawable, msgOutMediaDrawable}, null, Theme.key_chat_outBubbleGradient3)); @@ -32540,7 +32591,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_psaHelpDrawable[0]}, null, Theme.key_chat_inViews)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_psaHelpDrawable[1]}, null, Theme.key_chat_outViews)); - if (!themeDelegate.isThemeChangeAvailable()) { + if (!themeDelegate.isThemeChangeAvailable(false)) { themeDescriptions.add(new ThemeDescription(messagesSearchListView, 0, new Class[]{DialogCell.class}, null, Theme.avatarDrawables, null, Theme.key_avatar_text)); themeDescriptions.add(new ThemeDescription(messagesSearchListView, 0, new Class[]{DialogCell.class}, Theme.dialogs_countPaint, null, null, Theme.key_chats_unreadCounter)); themeDescriptions.add(new ThemeDescription(messagesSearchListView, 0, new Class[]{DialogCell.class}, null, new Paint[]{Theme.dialogs_namePaint[0], Theme.dialogs_namePaint[1], Theme.dialogs_searchNamePaint}, null, null, Theme.key_chats_name)); @@ -33030,6 +33081,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void showChatThemeBottomSheet() { + if (currentChat != null) { + presentFragment(new ChannelColorActivity(getDialogId()).setOnApplied(ChatActivity.this)); + return; + } chatThemeBottomSheet = new ChatThemeBottomSheet(ChatActivity.this, themeDelegate); chatListView.setOnInterceptTouchListener(event -> true); setChildrenEnabled(contentView, false); @@ -33059,9 +33114,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (userInfo != null) { emoticon = userInfo.theme_emoticon; } - if (emoticon == null && chatInfo != null) { - emoticon = chatInfo.theme_emoticon; - } +// if (emoticon == null && chatInfo != null) { +// emoticon = chatInfo.theme_emoticon; +// } setChatThemeEmoticon(emoticon); }); } @@ -33077,13 +33132,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDelegate.setCurrentTheme(result, themeDelegate.wallpaper,openAnimationStartTime != 0, null); }); } - TLRPC.WallPaper wallPaper = null; - if (dialog_id >= 0) { - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialog_id); - if (userFull != null) { - wallPaper = userFull.wallpaper; - } - } + TLRPC.WallPaper wallPaper = chatThemeController.getDialogWallpaper(dialog_id); themeDelegate.setCurrentTheme(themeDelegate.chatTheme, wallPaper, openAnimationStartTime != 0, null); } @@ -33143,7 +33192,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ThemeDelegate() { isDark = Theme.getActiveTheme().isDark(); boolean setup = false; - if (isThemeChangeAvailable()) { + if (isThemeChangeAvailable(false)) { chatTheme = ChatThemeController.getInstance(currentAccount).getDialogTheme(dialog_id); wallpaper = ChatThemeController.getInstance(currentAccount).getDialogWallpaper(dialog_id); if (chatTheme != null || wallpaper != null) { @@ -33257,8 +33306,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return chatTheme != null || backgroundDrawable != null ? currentPaints.get(paintKey) : null; } - public boolean isThemeChangeAvailable() { - return currentChat == null && currentEncryptedChat == null && !currentUser.bot && dialog_id >= 0; + public boolean isThemeChangeAvailable(boolean canEdit) { + return currentEncryptedChat == null && ( + (!canEdit /*|| currentChat != null && ChatObject.isChannelAndNotMegaGroup(currentChat) && ChatObject.canChangeChatInfo(currentChat)*/) || + currentChat == null && currentUser != null && !currentUser.bot + ); } public EmojiThemes getCurrentTheme() { @@ -33287,7 +33339,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not String newEmoticon = chatTheme != null ? chatTheme.getEmoticon() : null; String oldEmoticon = this.chatTheme != null ? this.chatTheme.getEmoticon() : null; TLRPC.WallPaper oldWallpaper = this.wallpaper; - if (!force && (!isThemeChangeAvailable() || (TextUtils.equals(oldEmoticon, newEmoticon) && this.isDark == newIsDark && ChatThemeController.equals(newWallpaper, oldWallpaper)))) { + if (!force && (!isThemeChangeAvailable(false) || (TextUtils.equals(oldEmoticon, newEmoticon) && this.isDark == newIsDark && ChatThemeController.equals(newWallpaper, oldWallpaper)))) { return; } @@ -33323,6 +33375,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } animationSettings.applyTheme = false; + if (dialog_id < 0) + animationSettings.applyTrulyTheme = false; animationSettings.afterStartDescriptionsAddedRunnable = () -> { setupChatTheme(chatTheme, newWallpaper, animated, true); initServiceMessageColors(backgroundDrawable); @@ -33422,7 +33476,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { currentColors = chatTheme.createColors(currentAccount, isDark ? 1 : 0); } - if (wallPaper != null) { + if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(wallpaper))) { + backgroundDrawable = PreviewView.getBackgroundDrawable(backgroundDrawable, currentAccount, wallpaper, isDark); + } else if (wallPaper != null) { backgroundDrawable = ChatBackgroundDrawable.getOrCreate(backgroundDrawable, wallPaper, isDark); } else { backgroundDrawable = getBackgroundDrawableFromTheme(chatTheme, prevPhase); @@ -33464,7 +33520,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not patternAlphaAnimator.start(); } - if (chatTheme == null) { + if (chatTheme == null && dialog_id >= 0) { Theme.ThemeInfo activeTheme; if (Theme.getActiveTheme().isDark() == isDark) { activeTheme = Theme.getActiveTheme(); @@ -34023,4 +34079,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + + public boolean supportsThanosEffect() { + return ThanosEffect.supports() && LiteMode.isEnabled(LiteMode.FLAG_CHAT_THANOS); + } + + public ThanosEffect getChatThanosEffect() { + if (!LiteMode.isEnabled(LiteMode.FLAG_CHAT_THANOS) || !ThanosEffect.supports()) { + return null; + } + if (chatListThanosEffect == null) { + if (getContext() == null || !ThanosEffect.supports() || chatListView == null || contentView == null) { + return null; + } + chatListThanosEffect = new ThanosEffect(getContext(), () -> { + ThanosEffect thisThanosEffect = chatListThanosEffect; + if (thisThanosEffect != null) { + chatListThanosEffect = null; + contentView.removeView(thisThanosEffect); + } + }); + contentView.addView(chatListThanosEffect, 1 + contentView.indexOfChild(chatListView), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + return chatListThanosEffect; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java index fff49d045..3db6c721e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java @@ -154,7 +154,7 @@ public class ChatBackgroundDrawable extends Drawable { } } } else { - if (wallPaper.settings.intensity < 0) { + if (wallPaper.settings == null || wallPaper.settings.intensity < 0) { thumb = bitmapDrawableOf(new ColorDrawable(Color.BLACK)); } else { if (wallPaper.settings.second_background_color == 0) { //one color diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 45d4d12d1..9e5936526 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -45,6 +45,7 @@ import android.widget.ScrollView; import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChannelBoostsController; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; @@ -888,11 +889,15 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } if (ChatObject.isChannelAndNotMegaGroup(currentChat) && ChatObject.canChangeChatInfo(currentChat)) { - colorCell = new PeerColorActivity.ChangeNameColorCell(currentAccount, true, context, getResourceProvider()); + colorCell = new PeerColorActivity.ChangeNameColorCell(currentAccount, -currentChat.id, context, getResourceProvider()); colorCell.setBackgroundDrawable(Theme.getSelectorDrawable(true)); typeEditContainer.addView(colorCell, LayoutHelper.createLinear(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); colorCell.setOnClickListener(v -> { - presentFragment(new PeerColorActivity(-currentChat.id).setOnApplied(this)); + presentFragment(new ChannelColorActivity(-currentChat.id).setOnApplied(this)); + + MessagesController.getInstance(currentAccount).getMainSettings().edit().putInt("boostingappearance", + MessagesController.getInstance(currentAccount).getMainSettings().getInt("boostingappearance", 0) + 1 + ).apply(); }); } @@ -1925,7 +1930,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } } - private void updateColorCell() { + public void updateColorCell() { if (colorCell != null) { colorCell.set(currentChat, (historyCell != null && historyCell.getVisibility() == View.VISIBLE) || (signCell != null && signCell.getVisibility() == View.VISIBLE) || (forumsCell != null && forumsCell.getVisibility() == View.VISIBLE)); } @@ -2034,11 +2039,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } else { finalString = LocaleController.getString("ReactionsAll", R.string.ReactionsAll); } - if (isChannelAndNotMegaGroup) { - reactionsCell.setTextAndValueAndIcon(TextCell.applyNewSpan(LocaleController.getString("Reactions", R.string.Reactions)), finalString, animated, R.drawable.msg_reactions2, true); - } else { - reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, animated, R.drawable.msg_reactions2, true); - } + reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, animated, R.drawable.msg_reactions2, true); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 15b931a21..478761aa7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -263,6 +263,9 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe if (id == -1) { finishFragment(); } else if (id == done_button) { + if (doneButtonDrawable != null && doneButtonDrawable.getProgress() > 0) { + return; + } processDone(); } } @@ -683,10 +686,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe private void processDone() { AndroidUtilities.runOnUIThread(enableDoneLoading, 200); - if (currentChat.noforwards != isSaveRestricted) { - getMessagesController().toggleChatNoForwards(chatId, currentChat.noforwards = isSaveRestricted); - } - if (trySetUsername() && tryUpdateJoinSettings()) { + if (trySetUsername() && trySetRestrict() && tryUpdateJoinSettings()) { finishFragment(); } } @@ -1117,6 +1117,26 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe } } + private boolean trySetRestrict() { + if (currentChat.noforwards != isSaveRestricted) { + if (!ChatObject.isChannel(currentChat)) { + updateDoneProgress(true); + getMessagesController().convertToMegaGroup(getParentActivity(), chatId, this, param -> { + if (param != 0) { + chatId = param; + currentChat = getMessagesController().getChat(param); + getMessagesController().toggleChatNoForwards(chatId, currentChat.noforwards = isSaveRestricted); + processDone(); + } + }); + return false; + } else { + getMessagesController().toggleChatNoForwards(chatId, currentChat.noforwards = isSaveRestricted); + } + } + return true; + } + private boolean trySetUsername() { if (getParentActivity() == null) { return false; @@ -1165,7 +1185,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe private boolean deactivatingLinks = false; private boolean tryDeactivateAllLinks() { - if (!isPrivate || currentChat.usernames == null) { + if (!isPrivate || currentChat.usernames == null || currentChat.usernames.isEmpty()) { return true; } if (deactivatingLinks) { @@ -1182,7 +1202,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe if (hasActive) { TLRPC.TL_channels_deactivateAllUsernames req = new TLRPC.TL_channels_deactivateAllUsernames(); req.channel = MessagesController.getInputChannel(currentChat); - getConnectionsManager().sendRequest(req, (res, err) -> { + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { if (res instanceof TLRPC.TL_boolTrue) { for (int i = 0; i < currentChat.usernames.size(); ++i) { final TLRPC.TL_username username = currentChat.usernames.get(i); @@ -1193,7 +1213,9 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe } deactivatingLinks = false; AndroidUtilities.runOnUIThread(this::processDone); - }); + })); + } else { + deactivatingLinks = false; } return !hasActive; } 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 3a8c648c9..5b7d35667 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -5768,28 +5768,32 @@ public class AlertsCreator { } } - boolean isGiveawayAndOwner = false; + boolean isActiveGiveawayAndOwner = false; String giveawayEndDate = null; if (selectedMessage != null) { - isGiveawayAndOwner = selectedMessage.isGiveaway() && !selectedMessage.isForwarded(); - if (isGiveawayAndOwner) { + isActiveGiveawayAndOwner = selectedMessage.isGiveaway() && !selectedMessage.isForwarded(); + if (isActiveGiveawayAndOwner) { TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) selectedMessage.messageOwner.media; - giveawayEndDate = LocaleController.getInstance().formatterGiveawayMonthDayYear.format(new Date(giveaway.until_date * 1000L)); + long untilDate = giveaway.until_date * 1000L; + giveawayEndDate = LocaleController.getInstance().formatterGiveawayMonthDayYear.format(new Date(untilDate)); + isActiveGiveawayAndOwner = System.currentTimeMillis() < untilDate; } } else if (count == 1) { for (int a = 1; a >= 0; a--) { for (int b = 0; b < selectedMessages[a].size(); b++) { MessageObject msg = selectedMessages[a].valueAt(b); - isGiveawayAndOwner = msg.isGiveaway() && !msg.isForwarded(); - if (isGiveawayAndOwner) { + isActiveGiveawayAndOwner = msg.isGiveaway() && !msg.isForwarded(); + if (isActiveGiveawayAndOwner) { TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) msg.messageOwner.media; - giveawayEndDate = LocaleController.getInstance().formatterGiveawayMonthDayYear.format(new Date(giveaway.until_date * 1000L)); + long untilDate = giveaway.until_date * 1000L; + giveawayEndDate = LocaleController.getInstance().formatterGiveawayMonthDayYear.format(new Date(untilDate)); + isActiveGiveawayAndOwner = System.currentTimeMillis() < untilDate; } } } } - if (isGiveawayAndOwner) { + if (isActiveGiveawayAndOwner) { 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); 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 145ea3762..bf959b9cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -71,6 +71,7 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW = 14; public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB = 16; + public static final int CACHE_TYPE_EMOJI_CALL = 17; public int rawDrawIndex; @@ -463,7 +464,7 @@ public class AnimatedEmojiDrawable extends Drawable { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[2].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[2].descent())) * 1.15f / AndroidUtilities.density); } else if (this.cacheType == STANDARD_LOTTIE_FRAME) { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[0].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[0].descent())) * 1.15f / AndroidUtilities.density); - } else if (cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { + } else if (cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 || cacheType == CACHE_TYPE_EMOJI_CALL) { sizedp = 100; } else { sizedp = 34; @@ -528,10 +529,10 @@ public class AnimatedEmojiDrawable extends Drawable { if (cacheType == CACHE_TYPE_RENDERING_VIDEO) { filter += "_d_nostream"; } - if (cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { + if (cacheType != CACHE_TYPE_EMOJI_CALL && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { filter += "_pcache"; } - if (cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { + if (cacheType != CACHE_TYPE_EMOJI_CALL && cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { filter += "_compress"; } if (cacheType == STANDARD_LOTTIE_FRAME) { @@ -585,7 +586,11 @@ public class AnimatedEmojiDrawable extends Drawable { imageReceiver.setImage(ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } } else { - imageReceiver.setImage(mediaLocation, mediaFilter, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + ImageLocation thumbLocation = null; + if (cacheType == CACHE_TYPE_EMOJI_CALL) { + thumbLocation = ImageLocation.getForDocument(thumb, document); + } + imageReceiver.setImage(mediaLocation, mediaFilter, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } } @@ -622,6 +627,8 @@ public class AnimatedEmojiDrawable extends Drawable { 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) { imageReceiver.setAutoRepeatCount(1); + } else if (cacheType == CACHE_TYPE_EMOJI_CALL){ + imageReceiver.setAutoRepeatCount(0); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java index 4ee2471ca..b2aec0db8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java @@ -30,6 +30,13 @@ public class BitmapShaderTools { updateBounds(); } + public BitmapShaderTools(int width, int height) { + bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + canvas = new Canvas(bitmap); + paint.setShader(shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + updateBounds(); + } + public Bitmap getBitmap() { return bitmap; } @@ -64,4 +71,12 @@ public class BitmapShaderTools { AndroidUtilities.rectTmp.set(left, top, right, bottom); setBounds(AndroidUtilities.rectTmp); } + + public void setMatrix(float offsetX, float offsetY, float scale, float degrees) { + matrix.reset(); + matrix.postRotate(degrees, bitmap.getWidth() / 2f, bitmap.getHeight() / 2f); + matrix.postScale(scale, scale); + matrix.postTranslate(offsetX, offsetY); + shader.setLocalMatrix(matrix); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java index c05dcaf77..d2519fab2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java @@ -40,26 +40,26 @@ public class BlobDrawable { private Path path = new Path(); public Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - private float[] radius; - private float[] angle; - private float[] radiusNext; - private float[] angleNext; - private float[] progress; - private float[] speed; + protected float[] radius; + protected float[] angle; + protected float[] radiusNext; + protected float[] angleNext; + protected float[] progress; + protected float[] speed; private float[] pointStart = new float[4]; private float[] pointEnd = new float[4]; - final Random random = new Random(); + protected final Random random = new Random(); - private final float N; + protected final float N; private final float L; public float cubicBezierK = 1f; private final Matrix m = new Matrix(); - private final int liteFlag; + protected final int liteFlag; public BlobDrawable(int n) { this(n, LiteMode.FLAG_CALLS_ANIMATIONS); @@ -85,7 +85,7 @@ public class BlobDrawable { this.liteFlag = liteFlag; } - private void generateBlob(float[] radius, float[] angle, int i) { + protected void generateBlob(float[] radius, float[] angle, int i) { float angleDif = 360f / N * 0.05f; float radDif = maxRadius - minRadius; radius[i] = minRadius + Math.abs(((random.nextInt() % 100f) / 100f)) * radDif; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java index 4dd5fa3b1..a086e0d95 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java @@ -555,7 +555,10 @@ public class BlurringShader { private int i = 0; public void setFallbackBlur(Bitmap bitmap, int orientation) { - fallbackBitmap = thumbBlurer.getBitmap(bitmap, "" + i++, orientation, 0); + setFallbackBlur(bitmap, orientation, false); + } + public void setFallbackBlur(Bitmap bitmap, int orientation, boolean recycleAfter) { + fallbackBitmap = thumbBlurer.getBitmap(bitmap, "" + i++, orientation, 0, recycleAfter); } public void resetBitmap() { @@ -603,7 +606,7 @@ public class BlurringShader { thumbBitmap = null; } - public Bitmap getBitmap(Bitmap bitmap, String key, int orientation, int invert) { + public Bitmap getBitmap(Bitmap bitmap, String key, int orientation, int invert, boolean recycleAfter) { if (bitmap == null) { return null; } @@ -666,6 +669,10 @@ public class BlurringShader { } else { resultBitmap.recycle(); } + + if (recycleAfter) { + bitmap.recycle(); + } }); }); return thumbBitmap; @@ -675,14 +682,14 @@ public class BlurringShader { if (imageReceiver == null) { return null; } - return getBitmap(imageReceiver.getBitmap(), imageReceiver.getImageKey(), imageReceiver.getOrientation(), imageReceiver.getInvert()); + return getBitmap(imageReceiver.getBitmap(), imageReceiver.getImageKey(), imageReceiver.getOrientation(), imageReceiver.getInvert(), false); } public Bitmap getBitmap(ImageReceiver.BitmapHolder bitmapHolder) { if (bitmapHolder == null) { return null; } - return getBitmap(bitmapHolder.bitmap, bitmapHolder.getKey(), bitmapHolder.orientation, 0); + return getBitmap(bitmapHolder.bitmap, bitmapHolder.getKey(), bitmapHolder.orientation, 0, false); } } @@ -698,6 +705,7 @@ public class BlurringShader { public static final int BLUR_TYPE_EMOJI_VIEW = 7; public static final int BLUR_TYPE_REPLY_BACKGROUND = 8; public static final int BLUR_TYPE_REPLY_TEXT_XFER = 9; + public static final int BLUR_TYPE_ACTION_BACKGROUND = 10; private final BlurManager manager; private final View view; @@ -758,6 +766,10 @@ public class BlurringShader { AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.4f); AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.45f); // AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 1.4f); + } else if (type == BLUR_TYPE_ACTION_BACKGROUND) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, wasDark ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, wasDark ? +.12f : -.06f); } paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); oldPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); @@ -829,6 +841,22 @@ public class BlurringShader { updateBounds(); } + private boolean wasDark = false; + public StoryBlurDrawer adapt(boolean isDark) { + if (wasDark != isDark) { + wasDark = isDark; + if (type == BLUR_TYPE_ACTION_BACKGROUND) { + final ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, wasDark ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, wasDark ? +.12f : -.06f); + paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + oldPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + } + } + return this; + } + @Nullable public Paint getPaint(float alpha) { return getPaint(alpha, 0, 0); @@ -913,6 +941,7 @@ public class BlurringShader { View view = this.view; do { matrix.preScale(1f / view.getScaleX(), 1f / view.getScaleY(), view.getPivotX(), view.getPivotY()); + matrix.preRotate(-view.getRotation(), view.getPivotX(), view.getPivotY()); matrix.preTranslate(-view.getX(), -view.getY()); if (view.getParent() instanceof View) { view = (View) view.getParent(); @@ -930,6 +959,7 @@ public class BlurringShader { } matrix.postTranslate(child.getX(), child.getY()); matrix.postScale(1f / child.getScaleX(), 1f / child.getScaleY(), child.getPivotX(), child.getPivotY()); + matrix.postRotate(child.getRotation(), child.getPivotX(), child.getPivotY()); index++; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java index 71b51360d..6c01912e1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -1200,7 +1200,11 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewTheme); swipeContainer.stickTo(swipeContainer.getHeight() + frameLayout.measureKeyboardHeight(), ()->{ - super.dismiss(); + try { + super.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } if (callback != null) { callback.run(); } 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 eb1e8d095..9737c1699 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java @@ -251,6 +251,9 @@ public abstract class BottomSheetWithRecyclerListView extends BottomSheet { headerShadowDrawable.setBounds(backgroundPaddingLeft, actionBar.getBottom(), parentView.getMeasuredWidth() - backgroundPaddingLeft, actionBar.getBottom() + headerShadowDrawable.getIntrinsicHeight()); headerShadowDrawable.setAlpha((int) (255 * actionBar.getAlpha() * shadowAlpha)); headerShadowDrawable.draw(canvas); + if (headerShadowDrawable.getAlpha() < 255) { + parentView.invalidate(); + } } wasDrawn = true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index d5a99c865..ac623d3dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -674,7 +674,11 @@ public class Bulletin { } protected void setBackground(int color) { - background = Theme.createRoundRectDrawable(AndroidUtilities.dp(10), color); + setBackground(color, 10); + } + + public void setBackground(int color, int rounding) { + background = Theme.createRoundRectDrawable(AndroidUtilities.dp(rounding), color); } public final static FloatPropertyCompat IN_OUT_OFFSET_Y = new FloatPropertyCompat("offsetY") { @@ -1085,9 +1089,17 @@ public class Bulletin { this.resourcesProvider = resourcesProvider; } + private boolean wrapWidth; + public void setWrapWidth() { + wrapWidth = true; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { childrenMeasuredWidth = 0; + if (wrapWidth) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); + } super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (button != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { setMeasuredDimension(childrenMeasuredWidth + button.getMeasuredWidth(), getMeasuredHeight()); 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 9d003eb01..59673d5de 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -41,6 +41,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.recorder.HintView2; import java.util.ArrayList; import java.util.List; @@ -189,6 +190,20 @@ public final class BulletinFactory { return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + public Bulletin createImageBulletin(int iconRawId, CharSequence title) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + layout.setBackground(Theme.getColor(Theme.key_undo_background, resourcesProvider), 12); + layout.imageView.setImageResource(iconRawId); + layout.textView.setText(title); + layout.textView.setSingleLine(false); + layout.textView.setLines(2); + layout.textView.setMaxLines(4); + layout.textView.setMaxWidth(HintView2.cutInFancyHalf(layout.textView.getText(), layout.textView.getPaint())); + ((ViewGroup.MarginLayoutParams) layout.textView.getLayoutParams()).rightMargin = AndroidUtilities.dp(12); + layout.setWrapWidth(); + return create(layout, Bulletin.DURATION_PROLONG); + } + public Bulletin createSimpleLargeBulletin(int iconRawId, CharSequence title, CharSequence subtitle) { final Bulletin.TwoLineLayout layout = new Bulletin.TwoLineLayout(getContext(), resourcesProvider); layout.imageView.setImageResource(iconRawId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java index 5c5bf8b02..41276e7ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java @@ -303,7 +303,7 @@ public class CaptionPhotoViewer extends CaptionContainerView { @Override public void updateColors(Theme.ResourcesProvider resourcesProvider) { super.updateColors(resourcesProvider); - timerDrawable.updateColors(0xffffffff, Theme.getColor(Theme.key_chat_editMediaButton, resourcesProvider)); + timerDrawable.updateColors(0xffffffff, Theme.getColor(Theme.key_chat_editMediaButton, resourcesProvider), 0xffffffff); } @Override 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 3b886b8e6..5c4a8bf6e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -59,9 +59,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.style.DynamicDrawableSpan; import android.text.style.ImageSpan; -import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.ActionMode; @@ -115,7 +113,6 @@ import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; -import org.telegram.messenger.CodeHighlighting; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; @@ -126,7 +123,6 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; @@ -137,7 +133,6 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; -import org.telegram.messenger.XiaomiUtilities; import org.telegram.messenger.browser.Browser; import org.telegram.messenger.camera.CameraController; import org.telegram.tgnet.ConnectionsManager; @@ -161,11 +156,13 @@ import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.DialogsActivity; import org.telegram.ui.GroupStickersActivity; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.MultiContactsSelectorBottomSheet; import org.telegram.ui.PhotoViewer; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; import org.telegram.ui.StickersActivity; -import org.telegram.ui.TopicsFragment; +import org.telegram.ui.Stories.recorder.CaptionContainerView; +import org.telegram.ui.Stories.recorder.HintView2; import java.io.File; import java.io.FileOutputStream; @@ -199,6 +196,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private boolean sendButtonEnabled = true; private TLRPC.UserFull userInfo; + public boolean voiceOnce; + public boolean onceVisible; + public void drawRecordedPannel(Canvas canvas) { if (getAlpha() == 0 || recordedAudioPanel == null || recordedAudioPanel.getParent() == null || recordedAudioPanel.getVisibility() != View.VISIBLE) { return; @@ -242,7 +242,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific void didPressAttachButton(); - void needStartRecordVideo(int state, boolean notify, int scheduleDate); + void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl); void needChangeVideoPreviewState(int state, float seekProgress); @@ -323,6 +323,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific default void onKeyboardRequested() { } + + default boolean onceVoiceAvailable() { + return false; + } } public final static int RECORD_STATE_ENTER = 0; @@ -527,6 +531,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private AnimatorSet scheduledButtonAnimation; @Nullable private RecordCircle recordCircle; + private OnceButton onceButton; private CloseProgressDrawable2 progressDrawable; private Paint dotPaint; private MediaActionDrawable playPauseDrawable; @@ -728,7 +733,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific @Override public void run() { if (delegate != null) { - delegate.needStartRecordVideo(0, true, 0); + delegate.needStartRecordVideo(0, true, 0, 0); } } }; @@ -855,6 +860,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific drawable.beginApplyLayerColors(); drawable.setLayerColor("Cup Red.**", dotColor); drawable.setLayerColor("Box.**", dotColor); + drawable.setLayerColor("Line 1.**", background); + drawable.setLayerColor("Line 2.**", background); + drawable.setLayerColor("Line 3.**", background); drawable.commitApplyLayerColors(); if (playPauseDrawable != null) { playPauseDrawable.setColor(getThemedColor(Theme.key_chat_recordedVoicePlayPause)); @@ -1009,9 +1017,147 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }; + public class OnceButton extends FrameLayout { + + private HintView2 hintView; + + private CaptionContainerView.PeriodDrawable periodDrawable; + private Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public OnceButton(Context context) { + super(context); + + periodDrawable = new CaptionContainerView.PeriodDrawable(); + periodDrawable.setCallback(this); + periodDrawable.setValue(1, voiceOnce, false); + + setWillNotDraw(false); + updateColors(); + } + + 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))); + hintView.setMaxWidthPx(HintView2.cutInFancyHalf(hintView.getText(), hintView.getTextPaint())); + if (voiceOnce) { + hintView.setIcon(R.raw.fire_on); + } else { + MessagesController.getGlobalMainSettings().edit().putInt("voiceoncehint", MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) + 1).apply(); + } + addView(hintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 54, 58)); + final HintView2 thisHintView = hintView; + hintView.setOnHiddenListener(() -> { + removeView(thisHintView); + if (hintView == thisHintView) { + hintView = null; + } + }); + hintView.show(); + } + + public void hideHintView() { + if (hintView != null) { + HintView2 oldHintView = hintView; + oldHintView.setOnHiddenListener(() -> removeView(oldHintView)); + oldHintView.hide(); + hintView = null; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + widthMeasureSpec, + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(194 + 48 + 12), MeasureSpec.EXACTLY) + ); + } + + private final RectF rectF = new RectF(); + public final RectF onceRect = new RectF(); + + @Override + protected void onDraw(Canvas canvas) { + if (recordCircle == null) return; + + int cx = getMeasuredWidth() - AndroidUtilities.dp2(26); + + 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; + if (onceVisible) { + final float onceOffset = AndroidUtilities.dpf2(AndroidUtilities.lerp(4, 12, recordCircle.moveProgress)); + rectF.set( + rectF.left, rectF.top - AndroidUtilities.dpf2(36) - onceOffset, rectF.right, rectF.top - onceOffset + ); + if (hintView != null) { + hintView.setJointPx(0, rectF.centerY()); + hintView.invalidate(); + } + 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()); + 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); + periodDrawable.setBounds((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom); + periodDrawable.draw(canvas); + canvas.restore(); + } + } + + public void updateColors() { + periodDrawable.updateColors( + getThemedColor(Theme.key_chat_messagePanelVoiceLock), + getThemedColor(Theme.key_chat_messagePanelVoiceBackground), + 0xFFFFFFFF + ); + lockBackgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelVoiceLockBackground)); + } + + private boolean pressed; + @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(); + } + } + return true; + } + } + return false; + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == periodDrawable || super.verifyDrawable(who); + } + } + public class RecordCircle extends View { - private float scale; + public float scale; private float amplitude; private float animateToAmplitude; private float animateAmplitudeDiff; @@ -1023,7 +1169,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private boolean pressed; private float transformToSeekbar; private float exitTransition; - private float progressToSeekbarStep3; + public float progressToSeekbarStep3; private float progressToSendButton; public float iconScale; @@ -1057,8 +1203,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private int paintAlpha; private float touchSlop; - private float slideToCancelProgress; - private float slideToCancelLockProgress; + public float slideToCancelProgress; + public float slideToCancelLockProgress; + private float progressToSeekbarStep1, progressToSeekbarStep2; private int slideDelta; private boolean canceledByGesture; @@ -1225,9 +1372,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (event.getAction() == MotionEvent.ACTION_UP) { if (pauseRect.contains(x, y)) { if (isInVideoMode()) { - delegate.needStartRecordVideo(3, true, 0); + delegate.needStartRecordVideo(3, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { - MediaController.getInstance().stopRecording(2, true, 0); + MediaController.getInstance().stopRecording(2, true, 0, voiceOnce); delegate.needStartRecordAudio(0); } if (slideText != null) { @@ -1270,6 +1417,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific slideDelta = (int) (-distance * (1f - slideToCancelProgress)); } + public float moveProgress; + public float lockY, lockSize; + public float translationDy; + @Override protected void onDraw(Canvas canvas) { if (skipDraw) { @@ -1364,6 +1515,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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); @@ -1396,7 +1549,7 @@ 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 = 1.0f - yAdd / AndroidUtilities.dp(57); + float moveProgress = this.moveProgress = 1.0f - yAdd / AndroidUtilities.dp(57); float lockSize; float lockY; @@ -1511,8 +1664,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } if (isSendButtonVisible()) { - lockSize = AndroidUtilities.dp(36); - lockY = AndroidUtilities.dp(60) + multilinTooltipOffset + AndroidUtilities.dpf2(30) * (1.0f - sc) - yAdd + AndroidUtilities.dpf2(14f) * moveProgress; + 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); @@ -1522,15 +1675,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific transformToPauseProgress = moveProgress; } else { - lockSize = AndroidUtilities.dp(36) + (int) (AndroidUtilities.dp(14) * moveProgress); - lockY = AndroidUtilities.dp(60) + multilinTooltipOffset + (int) (AndroidUtilities.dp(30) * (1.0f - sc)) - (int) yAdd + (moveProgress) * idleProgress * -AndroidUtilities.dp(8); + 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; @@ -1623,10 +1775,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } float maxTranslationDy = AndroidUtilities.dpf2(72); - float dy = maxTranslationDy * translation - AndroidUtilities.dpf2(20) * (progressToSeekbarStep1) * (1f - translation) + maxTranslationDy * (1f - slideToCancelLockProgress); + 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); @@ -1689,6 +1846,14 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific drawingCircleRadius = radius; } + @Override + public void invalidate() { + super.invalidate(); + if (onceButton != null) { + onceButton.invalidate(); + } + } + public void drawIcon(Canvas canvas, int cx, int cy, float alpha) { Drawable drawable; Drawable replaceDrawable = null; @@ -2228,12 +2393,12 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (!hasRecordVideo || calledRecordRunnable) { startedDraggingX = -1; if (hasRecordVideo && isInVideoMode()) { - delegate.needStartRecordVideo(1, true, 0); + delegate.needStartRecordVideo(1, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { if (recordingAudioVideo && isInScheduleMode()) { - AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate), () -> MediaController.getInstance().stopRecording(0, false, 0), resourcesProvider); + AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate, false), () -> MediaController.getInstance().stopRecording(0, false, 0, false), resourcesProvider); } - MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0); + MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0, voiceOnce); delegate.needStartRecordAudio(0); } recordingAudioVideo = false; @@ -2267,10 +2432,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (recordCircle.slideToCancelProgress < 0.7f) { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2, true, 0); + delegate.needStartRecordVideo(2, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0); + MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); @@ -2293,10 +2458,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (alpha < 0.45) { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2, true, 0); + delegate.needStartRecordVideo(2, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0); + MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); @@ -2315,15 +2480,15 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific startedDraggingX = -1; if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(1, true, 0); + delegate.needStartRecordVideo(1, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else if (!sendVoiceEnabled) { delegate.needShowMediaBanHint(); } else { if (recordingAudioVideo && isInScheduleMode()) { - AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate), () -> MediaController.getInstance().stopRecording(0, false, 0), resourcesProvider); + AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate, false), () -> MediaController.getInstance().stopRecording(0, false, 0, false), resourcesProvider); } delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0); + MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0, voiceOnce); } recordingAudioVideo = false; messageTransitionIsRunning = false; @@ -2375,10 +2540,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (alpha == 0) { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2, true, 0); + delegate.needStartRecordVideo(2, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0); + MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL_BY_GESTURE); @@ -3096,7 +3261,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private void resetRecordedState() { if (videoToSendMessageObject != null) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(2, true, 0); + delegate.needStartRecordVideo(2, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); if (playing != null && playing == audioToSendMessageObject) { @@ -3471,6 +3636,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } private void createRecordCircle() { + createOnceButton(); if (recordCircle != null) { return; } @@ -3479,6 +3645,18 @@ 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) { + 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)); + } + private void showRestrictedHint() { if (DialogObject.isChatDialog(dialog_id)) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); @@ -4570,7 +4748,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } checkBotMenu(); - if (editingCaption && !captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumLocked && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codePointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { + if (editingCaption && !captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codePointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { captionLimitBulletinShown = true; if (heightShouldBeChanged) { AndroidUtilities.runOnUIThread(()->showCaptionLimitBulletin(), 300); @@ -4641,10 +4819,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void cancelRecordingAudioVideo() { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(5, true, 0); + delegate.needStartRecordVideo(5, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0); + MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL); @@ -5498,20 +5676,24 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific updateEmojiButtonParams(); recordPannelAnimation = new AnimatorSet(); - recordPannelAnimation.playTogether( - ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), - ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_SCALE, 1.0f), - ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_X, 0.0f), - ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 0.0f), + ArrayList animators = new ArrayList<>(); + animators.add(ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_ALPHA, emojiButtonRestricted ? 0.5f : 1.0f)); + animators.add(ObjectAnimator.ofFloat(emojiButton, EMOJI_BUTTON_SCALE, 1.0f)); + animators.add(ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_X, 0.0f)); + animators.add(ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 0.0f)); - ObjectAnimator.ofFloat(recordedAudioPanel, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(attachButton, View.ALPHA, 1.0f), - ObjectAnimator.ofFloat(attachButton, View.SCALE_X, 1.0f), - ObjectAnimator.ofFloat(attachButton, View.SCALE_Y, 1.0f), - ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 1f), - ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0) - ); + animators.add(ObjectAnimator.ofFloat(recordedAudioPanel, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(attachButton, View.ALPHA, 1.0f)); + animators.add(ObjectAnimator.ofFloat(attachButton, View.SCALE_X, 1.0f)); + 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(); + } + recordPannelAnimation.playTogether(animators); if (botCommandsMenuButton != null) { botCommandsMenuButton.setAlpha(0f); @@ -5544,12 +5726,16 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } AnimatorSet exitAnimation = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); if (isInVideoMode()) { - exitAnimation.playTogether( - ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(videoTimelineView, View.TRANSLATION_X, -AndroidUtilities.dp(20)), - ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0) - ); + animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.TRANSLATION_X, -AndroidUtilities.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(); + } + exitAnimation.playTogether(animators); if (emojiButtonPaddingAlpha == 1f) { exitAnimation.playTogether(ObjectAnimator.ofFloat(messageEditText, View.ALPHA, 1f)); } else { @@ -5571,16 +5757,19 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific messageEditTextAniamtor.setDuration(200); exitAnimation.playTogether(messageEditTextAniamtor); } - exitAnimation.playTogether( - ObjectAnimator.ofFloat(recordedAudioSeekBar, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordedAudioPlayButton, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordedAudioBackground, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(recordedAudioSeekBar, View.TRANSLATION_X, -AndroidUtilities.dp(20)), - ObjectAnimator.ofFloat(recordedAudioPlayButton, View.TRANSLATION_X, -AndroidUtilities.dp(20)), - ObjectAnimator.ofFloat(recordedAudioBackground, View.TRANSLATION_X, -AndroidUtilities.dp(20)), - ObjectAnimator.ofFloat(recordedAudioTimeTextView, View.TRANSLATION_X, -AndroidUtilities.dp(20)) - ); + animators.add(ObjectAnimator.ofFloat(recordedAudioSeekBar, View.ALPHA, 0.0f)); + 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(); + } + exitAnimation.playTogether(animators); } exitAnimation.setDuration(200); @@ -5655,6 +5844,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (recordPannelAnimation != null) { recordPannelAnimation.start(); } + if (onceButton != null) { + onceButton.invalidate(); + } } private void hideRecordedAudioPanelInternal() { @@ -5738,7 +5930,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific return; } if (videoToSendMessageObject != null) { - delegate.needStartRecordVideo(4, notify, scheduleDate); + delegate.needStartRecordVideo(4, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0); hideRecordedAudioPanel(true); checkSendButton(true); return; @@ -5747,7 +5939,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (playing != null && playing == audioToSendMessageObject) { MediaController.getInstance().cleanupPlayer(true, true); } - SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), null, null, null, null, notify, scheduleDate, 0, null, null, false); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), null, null, null, null, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0, null, null, false); applyStoryToSendMessageParams(params); SendMessagesHelper.getInstance(currentAccount).sendMessage(params); if (delegate != null) { @@ -5921,7 +6113,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } catch (Exception ignored) {} } - if (!MessagesController.getInstance(currentAccount).premiumLocked && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codePointCount) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codePointCount) { showCaptionLimitBulletin(); } return; @@ -6916,6 +7108,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (recordInterfaceState == 1) { return; } + voiceOnce = false; + if (onceButton != null) { + onceButton.periodDrawable.setValue(1, false, false); + } createRecordAudioPanel(); recordInterfaceState = 1; if (emojiView != null) { @@ -6954,6 +7150,9 @@ 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 (recordDot != null) { recordDot.resetAlpha(); @@ -6987,6 +7186,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(slideText, View.TRANSLATION_X, 0), ObjectAnimator.ofFloat(slideText, View.ALPHA, 1) ); + if (onceButton != null) { + iconChanges.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 1)); + } if (audioVideoSendButton != null) { iconChanges.playTogether(ObjectAnimator.ofFloat(audioVideoSendButton, View.ALPHA, 0)); } @@ -7103,6 +7305,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific ObjectAnimator.ofFloat(messageEditText, MESSAGE_TEXT_TRANSLATION_X, 0), ObjectAnimator.ofFloat(recordCircle, "slideToCancelProgress", 1f) ); + if (onceButton != null) { + runningAnimationAudio.playTogether(ObjectAnimator.ofFloat(onceButton, View.ALPHA, 0)); + onceButton.hideHintView(); + } if (botCommandsMenuButton != null) { runningAnimationAudio.playTogether( ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_Y, 1), @@ -7319,6 +7525,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific botCommandsMenuButton.setScaleX(0f); botCommandsMenuButton.setScaleY(0f); } + + if (onceButton != null && onceVisible && MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3) { + onceButton.showHintView(); + } } }); @@ -7334,6 +7544,10 @@ 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 (botCommandsMenuButton != null) { iconsAnimator.playTogether( @@ -7481,6 +7695,10 @@ 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 (botCommandsMenuButton != null) { iconsAnimator.playTogether( ObjectAnimator.ofFloat(botCommandsMenuButton, View.SCALE_Y, 1), @@ -8164,7 +8382,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } public void updateGiftButton(boolean animated) { - boolean visible = !MessagesController.getInstance(currentAccount).premiumLocked && MessagesController.getInstance(currentAccount).giftAttachMenuIcon && + boolean visible = !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && MessagesController.getInstance(currentAccount).giftAttachMenuIcon && MessagesController.getInstance(currentAccount).giftTextFieldIcon && getParentFragment() != null && getParentFragment().getCurrentUser() != null && !BuildVars.IS_BILLING_UNAVAILABLE && !getParentFragment().getCurrentUser().self && !getParentFragment().getCurrentUser().premium && getParentFragment().getCurrentUserInfo() != null && !getParentFragment().getCurrentUserInfo().premium_gifts.isEmpty() && !isInScheduleMode() && @@ -8759,6 +8977,21 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } else if (button instanceof TLRPC.TL_keyboardButtonRequestPeer) { TLRPC.TL_keyboardButtonRequestPeer btn = (TLRPC.TL_keyboardButtonRequestPeer) button; if (btn.peer_type != null && messageObject != null && messageObject.messageOwner != null) { + if (btn.peer_type instanceof TLRPC.TL_requestPeerTypeUser && btn.max_quantity > 1) { + MultiContactsSelectorBottomSheet.open(btn.max_quantity, ids -> { + if (ids != null && !ids.isEmpty()) { + TLRPC.TL_messages_sendBotRequestedPeer req = new TLRPC.TL_messages_sendBotRequestedPeer(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.messageOwner.peer_id); + req.msg_id = messageObject.getId(); + req.button_id = btn.button_id; + for (Long id : ids) { + req.requested_peers.add(MessagesController.getInstance(currentAccount).getInputPeer(id)); + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + } + }); + return false; + } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER); @@ -8774,20 +9007,17 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific FileLog.e(e); } DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { - @Override - public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param, TopicsFragment topicsFragment) { - if (dids != null && !dids.isEmpty()) { - TLRPC.TL_messages_sendBotRequestedPeer req = new TLRPC.TL_messages_sendBotRequestedPeer(); - req.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.messageOwner.peer_id); - req.msg_id = messageObject.getId(); - req.button_id = btn.button_id; - req.requested_peer = MessagesController.getInstance(currentAccount).getInputPeer(dids.get(0).dialogId); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); - } - fragment.finishFragment(); - return true; + fragment.setDelegate((dialogFragment, dids, message, param, topicsFragment) -> { + if (dids != null && !dids.isEmpty()) { + TLRPC.TL_messages_sendBotRequestedPeer req = new TLRPC.TL_messages_sendBotRequestedPeer(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.messageOwner.peer_id); + req.msg_id = messageObject.getId(); + req.button_id = btn.button_id; + req.requested_peers.add(MessagesController.getInstance(currentAccount).getInputPeer(dids.get(0).dialogId)); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); } + dialogFragment.finishFragment(); + return true; }); parentFragment.presentFragment(fragment); return false; @@ -10553,10 +10783,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific public void onCancelButtonPressed() { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(5, true, 0); + delegate.needStartRecordVideo(5, true, 0, voiceOnce ? 0x7FFFFFFF : 0); } else { delegate.needStartRecordAudio(0); - MediaController.getInstance().stopRecording(0, false, 0); + MediaController.getInstance().stopRecording(0, false, 0, voiceOnce); } recordingAudioVideo = false; updateRecordInterface(RECORD_STATE_CANCEL); @@ -10814,7 +11044,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific if (isInVideoMode()) { if (t >= 59500 && !stoppedInternal) { startedDraggingX = -1; - delegate.needStartRecordVideo(3, true, 0); + delegate.needStartRecordVideo(3, true, 0, voiceOnce ? 0x7FFFFFFF : 0); stoppedInternal = true; } } 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 40d6645d5..4513c0c63 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -2557,7 +2557,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N sendButtonColorAnimator.setDuration(150).start(); } -// if (!captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumLocked && !UserConfig.getInstance(currentAccount).isPremium() && codepointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codepointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { +// if (!captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !UserConfig.getInstance(currentAccount).isPremium() && codepointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codepointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { // captionLimitBulletinShown = true; // showCaptionLimitBulletin(parentFragment); // } @@ -2623,7 +2623,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } catch (Exception ignored) { } - if (!MessagesController.getInstance(currentAccount).premiumLocked && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codepointCount) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codepointCount) { showCaptionLimitBulletin(parentFragment); } return; 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 ed9bf0315..2232ad2f1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -33,6 +33,7 @@ import androidx.core.content.ContextCompat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; @@ -487,6 +488,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent titleTextLargerCopyView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleTextLargerCopyView.setLeftDrawableTopPadding(-AndroidUtilities.dp(1.3f)); titleTextLargerCopyView.setRightDrawable(titleTextView.getRightDrawable()); + titleTextLargerCopyView.setRightDrawable2(titleTextView.getRightDrawable2()); titleTextLargerCopyView.setRightDrawableOutside(titleTextView.getRightDrawableOutside()); titleTextLargerCopyView.setLeftDrawable(titleTextView.getLeftDrawable()); titleTextLargerCopyView.setText(titleTextView.getText()); @@ -618,16 +620,17 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private boolean rightDrawableIsScamOrVerified = false; private String rightDrawableContentDescription = null; + private String rightDrawable2ContentDescription = null; public void setTitleIcons(Drawable leftIcon, Drawable mutedIcon) { titleTextView.setLeftDrawable(leftIcon); if (!rightDrawableIsScamOrVerified) { if (mutedIcon != null) { - rightDrawableContentDescription = LocaleController.getString("NotificationsMuted", R.string.NotificationsMuted); + rightDrawable2ContentDescription = LocaleController.getString("NotificationsMuted", R.string.NotificationsMuted); } else { - rightDrawableContentDescription = null; + rightDrawable2ContentDescription = null; } - titleTextView.setRightDrawable(mutedIcon); + titleTextView.setRightDrawable2(mutedIcon); } } @@ -644,9 +647,9 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent if (!(titleTextView.getRightDrawable() instanceof ScamDrawable)) { ScamDrawable drawable = new ScamDrawable(11, scam ? 0 : 1); drawable.setColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); - titleTextView.setRightDrawable(drawable); + titleTextView.setRightDrawable2(drawable); // titleTextView.setRightPadding(0); - rightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); + rightDrawable2ContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); rightDrawableIsScamOrVerified = true; } } else if (verified) { @@ -655,37 +658,34 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent Drawable verifiedCheck = getResources().getDrawable(R.drawable.verified_check).mutate(); verifiedCheck.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_profile_verifiedCheck), PorterDuff.Mode.MULTIPLY)); Drawable verifiedDrawable = new CombinedDrawable(verifiedBackground, verifiedCheck); - titleTextView.setRightDrawable(verifiedDrawable); -// titleTextView.setRightPadding(titleTextView.getPaddingRight()); + titleTextView.setRightDrawable2(verifiedDrawable); rightDrawableIsScamOrVerified = true; - rightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); - } else if (premium) { - boolean isStatus = emojiStatus instanceof TLRPC.TL_emojiStatus || emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000); -// if (premiumIconHiddable) { -// titleTextView.setCanHideRightDrawable(!isStatus); -// } + rightDrawable2ContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); + } else if (titleTextView.getRightDrawable() instanceof ScamDrawable) { + titleTextView.setRightDrawable2(null); + rightDrawableIsScamOrVerified = false; + rightDrawable2ContentDescription = null; + } + if (premium || DialogObject.getEmojiStatusDocumentId(emojiStatus) != 0) { if (titleTextView.getRightDrawable() instanceof AnimatedEmojiDrawable.WrapSizeDrawable && ((AnimatedEmojiDrawable.WrapSizeDrawable) titleTextView.getRightDrawable()).getDrawable() instanceof AnimatedEmojiDrawable) { ((AnimatedEmojiDrawable) ((AnimatedEmojiDrawable.WrapSizeDrawable) titleTextView.getRightDrawable()).getDrawable()).removeView(titleTextView); } - if (emojiStatus instanceof TLRPC.TL_emojiStatus) { - emojiStatusDrawable.set(((TLRPC.TL_emojiStatus) emojiStatus).document_id, animated); - } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { - emojiStatusDrawable.set(((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id, animated); - } else { + if (DialogObject.getEmojiStatusDocumentId(emojiStatus) != 0) { + emojiStatusDrawable.set(DialogObject.getEmojiStatusDocumentId(emojiStatus), animated); + } else if (premium) { Drawable drawable = ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_premium_liststar).mutate(); drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_profile_verifiedBackground), PorterDuff.Mode.MULTIPLY)); emojiStatusDrawable.set(drawable, animated); + } else { + emojiStatusDrawable.set((Drawable) null, animated); } emojiStatusDrawable.setColor(getThemedColor(Theme.key_profile_verifiedBackground)); titleTextView.setRightDrawable(emojiStatusDrawable); -// titleTextView.setRightPadding(titleTextView.getPaddingRight()); - rightDrawableIsScamOrVerified = true; - rightDrawableContentDescription = LocaleController.getString("AccDescrPremium", R.string.AccDescrPremium); - } else if (titleTextView.getRightDrawable() instanceof ScamDrawable) { - titleTextView.setRightDrawable(null); -// titleTextView.setRightPadding(0); rightDrawableIsScamOrVerified = false; + rightDrawableContentDescription = LocaleController.getString("AccDescrPremium", R.string.AccDescrPremium); + } else { + titleTextView.setRightDrawable(null); rightDrawableContentDescription = null; } } @@ -1146,6 +1146,10 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent sb.append(", "); sb.append(rightDrawableContentDescription); } + if (rightDrawable2ContentDescription != null) { + sb.append(", "); + sb.append(rightDrawable2ContentDescription); + } sb.append("\n"); sb.append(subtitleTextView.getText()); info.setContentDescription(sb); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java index 1923c90b8..4f2ad0a0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -20,6 +22,8 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; @@ -51,10 +55,12 @@ import org.telegram.messenger.MediaDataController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.ResultCallback; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; @@ -66,7 +72,9 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.DrawerProfileCell; import org.telegram.ui.Cells.ThemesHorizontalListCell; import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.PhotoViewer; +import org.telegram.ui.StatisticActivity; import org.telegram.ui.ThemePreviewActivity; import org.telegram.ui.WallpapersListActivity; @@ -101,6 +109,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen private final LinearSmoothScroller scroller; private final View applyButton; private AnimatedTextView applyTextView; + private AnimatedTextView applySubTextView; private TextView chooseBackgroundTextView; private ChatThemeItem selectedItem; private boolean forceDark; @@ -113,7 +122,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen HintView hintView; private boolean dataLoaded; private EmojiThemes currentTheme; - ThemePreviewActivity overlayFragment; + BaseFragment overlayFragment; public ChatAttachAlert chatAttachAlert; private FrameLayout chatAttachButton; private AnimatedTextView chatAttachButtonText; @@ -150,10 +159,10 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen titleView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(6), AndroidUtilities.dp(12), AndroidUtilities.dp(8)); + titleView.setPadding(dp(12), dp(6), dp(12), dp(8)); backButtonView = new ImageView(getContext()); - int padding = AndroidUtilities.dp(10); + int padding = dp(10); backButtonView.setPadding(padding, padding, padding, padding); backButtonDrawable = new BackDrawable(false); backButtonView.setImageDrawable(backButtonDrawable); @@ -169,7 +178,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen rootLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.START, 44, 0, 62, 0)); int drawableColor = getThemedColor(Theme.key_featuredStickers_addButton); - int drawableSize = AndroidUtilities.dp(28); + int drawableSize = dp(28); darkThemeDrawable = new RLottieDrawable(R.raw.sun_outline, "" + R.raw.sun_outline, drawableSize, drawableSize, false, null); forceDark = !Theme.getActiveTheme().isDark(); setForceDark(Theme.getActiveTheme().isDark(), false); @@ -213,7 +222,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen recyclerView.setItemAnimator(null); recyclerView.setNestedScrollingEnabled(false); recyclerView.setLayoutManager(layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); - recyclerView.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0); + recyclerView.setPadding(dp(12), 0, dp(12), 0); recyclerView.setOnItemClickListener((view, position) -> { if (adapter.items.get(position) == selectedItem || changeDayNightView != null) { return; @@ -255,7 +264,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen rootLayout.addView(recyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 0, 44, 0, 0)); applyButton = new View(getContext()); - applyButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); + applyButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(6), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed))); applyButton.setOnClickListener((view) -> applySelectedTheme()); rootLayout.addView(applyButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16)); @@ -284,10 +293,19 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen applyTextView.adaptWidth = false; applyTextView.setGravity(Gravity.CENTER); applyTextView.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); - applyTextView.setTextSize(AndroidUtilities.dp(15)); + applyTextView.setTextSize(dp(15)); applyTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); rootLayout.addView(applyTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16)); + applySubTextView = new AnimatedTextView(getContext(), true, true, true); + applySubTextView.getDrawable().setEllipsizeByGradient(true); + applySubTextView.adaptWidth = false; + applySubTextView.setGravity(Gravity.CENTER); + applySubTextView.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); + applySubTextView.setTextSize(dp(12)); + applySubTextView.setAlpha(0f); + applySubTextView.setTranslationY(dp(11)); + rootLayout.addView(applySubTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16)); if (currentWallpaper != null) { cancelOrResetTextView = new TextView(getContext()); @@ -315,7 +333,13 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen themeHintTextView.setGravity(Gravity.CENTER); themeHintTextView.setLines(1); themeHintTextView.setSingleLine(true); - themeHintTextView.setText(LocaleController.formatString("ChatThemeApplyHint", R.string.ChatThemeApplyHint, chatActivity.getCurrentUser().first_name)); + String name = ""; + if (chatActivity.getCurrentUser() != null) { + name = UserObject.getFirstName(chatActivity.getCurrentUser()); + } else if (chatActivity.getCurrentChat() != null) { + name = chatActivity.getCurrentChat().title; + } + themeHintTextView.setText(LocaleController.formatString("ChatThemeApplyHint", R.string.ChatThemeApplyHint, name)); themeHintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); rootLayout.addView(themeHintTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 214, 16, 12)); } @@ -326,11 +350,11 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen private void updateButtonColors() { if (themeHintTextView != null) { themeHintTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray)); - themeHintTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); + themeHintTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); } if (cancelOrResetTextView != null) { cancelOrResetTextView.setTextColor(getThemedColor(Theme.key_text_RedRegular)); - cancelOrResetTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_text_RedRegular), (int) (0.3f * 255)))); + cancelOrResetTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_text_RedRegular), (int) (0.3f * 255)))); } backButtonView.setBackground(Theme.createSelectorDrawable(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_dialogTextBlack), 30), 1)); backButtonDrawable.setColor(getThemedColor(Theme.key_dialogTextBlack)); @@ -339,7 +363,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen darkThemeView.setBackground(Theme.createSelectorDrawable(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), 30), 1)); chooseBackgroundTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlue)); - chooseBackgroundTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); + chooseBackgroundTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); } @@ -357,7 +381,12 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } } + private ColoredImageSpan lockSpan; private void updateState(boolean animated) { + TLRPC.Chat chat = chatActivity.getCurrentChat(); + if (chat != null) { + checkBoostsLevel(); + } if (!dataLoaded) { backButtonDrawable.setRotation(1f, animated); applyButton.setEnabled(false); @@ -365,6 +394,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen AndroidUtilities.updateViewVisibilityAnimated(cancelOrResetTextView, false, 0.9f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(applyButton, false, 1f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(applyTextView, false, 0.9f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(applySubTextView, false, 0.9f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(themeHintTextView, false, 0.9f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(progressView, true, 1f, true, animated); } else { @@ -372,16 +402,30 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen if (hasChanges()) { backButtonDrawable.setRotation(0, animated); applyButton.setEnabled(true); - AndroidUtilities.updateViewVisibilityAnimated(chooseBackgroundTextView, false, 0.9f, false, animated); - AndroidUtilities.updateViewVisibilityAnimated(cancelOrResetTextView, false, 0.9f, false, animated); - AndroidUtilities.updateViewVisibilityAnimated(applyButton, true, 1f, false, animated); - AndroidUtilities.updateViewVisibilityAnimated(applyTextView, true, 0.9f, false, animated); - AndroidUtilities.updateViewVisibilityAnimated(themeHintTextView, true, 0.9f, false, animated); + boolean showSubText = false; if (selectedItem != null && selectedItem.chatTheme != null && selectedItem.chatTheme.showAsDefaultStub && selectedItem.chatTheme.wallpaper == null) { applyTextView.setText(LocaleController.getString("ChatResetTheme", R.string.ChatResetTheme)); } else { applyTextView.setText(LocaleController.getString("ChatApplyTheme", R.string.ChatApplyTheme)); + if (chat != null && boostsStatus != null && boostsStatus.level < chatActivity.getMessagesController().channelWallpaperLevelMin) { + showSubText = true; + SpannableStringBuilder text = new SpannableStringBuilder("l"); + if (lockSpan == null) { + lockSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); + lockSpan.setTopOffset(1); + } + text.setSpan(lockSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.append(" ").append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", chatActivity.getMessagesController().channelWallpaperLevelMin)); + applySubTextView.setText(text); + } } + updateApplySubTextTranslation(showSubText, animated && applyTextView.getAlpha() > .8f); + AndroidUtilities.updateViewVisibilityAnimated(chooseBackgroundTextView, false, 0.9f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(cancelOrResetTextView, false, 0.9f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(applyButton, true, 1f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(applyTextView, true, 0.9f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(applySubTextView, showSubText, 0.9f, false, 0.7f, animated); + AndroidUtilities.updateViewVisibilityAnimated(themeHintTextView, true, 0.9f, false, animated); } else { backButtonDrawable.setRotation(1f, animated); applyButton.setEnabled(false); @@ -389,11 +433,54 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen AndroidUtilities.updateViewVisibilityAnimated(cancelOrResetTextView, true, 0.9f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(applyButton, false, 1f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(applyTextView, false, 0.9f, false, animated); + AndroidUtilities.updateViewVisibilityAnimated(applySubTextView, false, 0.9f, false, animated); AndroidUtilities.updateViewVisibilityAnimated(themeHintTextView, false, 0.9f, false, animated); } } } + private boolean checkingBoostsLevel = false, checkedBoostsLevel = false; + private TL_stories.TL_premium_boostsStatus boostsStatus; + private void checkBoostsLevel() { + if (chatActivity == null || checkingBoostsLevel || checkedBoostsLevel || boostsStatus != null) { + return; + } + checkingBoostsLevel = true; + chatActivity.getMessagesController().getBoostsController().getBoostsStats(chatActivity.getDialogId(), boostsStatus -> { + this.boostsStatus = boostsStatus; + checkedBoostsLevel = true; + updateState(true); + checkingBoostsLevel = false; + }); + } + + private float subTextTranslation = 0; + private ValueAnimator subTextTranslationAnimator; + private void updateApplySubTextTranslation(boolean subtextShown, boolean animated) { + if (subTextTranslationAnimator != null) { + subTextTranslationAnimator.cancel(); + subTextTranslationAnimator = null; + } + if (animated) { + subTextTranslationAnimator = ValueAnimator.ofFloat(subTextTranslation, subtextShown ? 1 : 0); + subTextTranslationAnimator.addUpdateListener(anm -> { + subTextTranslation = (float) anm.getAnimatedValue(); + applyTextView.setTranslationY(-dp(7) * subTextTranslation); + }); + subTextTranslationAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + subTextTranslation = subtextShown ? 1 : 0; + applyTextView.setTranslationY(-dp(7) * subTextTranslation); + } + }); + subTextTranslationAnimator.start(); + } else { + subTextTranslation = subtextShown ? 1 : 0; + applyTextView.setTranslationY(-dp(7) * subTextTranslation); + } + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -433,7 +520,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen hintView = new HintView(getContext(), 9, chatActivity.getResourceProvider()); hintView.setVisibility(View.INVISIBLE); hintView.setShowingDuration(5000); - hintView.setBottomOffset(-AndroidUtilities.dp(8)); + hintView.setBottomOffset(-dp(8)); if (forceDark) { hintView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ChatThemeDaySwitchTooltip", R.string.ChatThemeDaySwitchTooltip))); } else { @@ -538,7 +625,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } updateButtonColors(); if (chatAttachButton != null) { - chatAttachButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(0), getThemedColor(Theme.key_windowBackgroundWhite), ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); + chatAttachButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(0), getThemedColor(Theme.key_windowBackgroundWhite), ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); } if (chatAttachButtonText != null) { chatAttachButtonText.setTextColor(getThemedColor(Theme.key_featuredStickers_addButton)); @@ -550,8 +637,8 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } }; ArrayList themeDescriptions = new ArrayList<>(); - if (chatActivity.forceDisallowRedrawThemeDescriptions && overlayFragment != null) { - themeDescriptions.addAll(overlayFragment.getThemeDescriptionsInternal()); + if (chatActivity.forceDisallowRedrawThemeDescriptions && overlayFragment instanceof ThemePreviewActivity) { + themeDescriptions.addAll(((ThemePreviewActivity) overlayFragment).getThemeDescriptionsInternal()); return themeDescriptions; } if (chatAttachAlert != null) { @@ -833,6 +920,35 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } private void applySelectedTheme() { + if (checkingBoostsLevel) { + return; + } + if (boostsStatus != null && boostsStatus.level < chatActivity.getMessagesController().channelWallpaperLevelMin) { + chatActivity.getMessagesController().getBoostsController().userCanBoostChannel(chatActivity.getDialogId(), boostsStatus, canApplyBoost -> { + if (getContext() == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(chatActivity, getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_WALLPAPER, currentAccount, resourcesProvider); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(chatActivity.getDialogId()); + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = chatActivity.getMessagesController().getChat(-chatActivity.getDialogId()); + Bundle args = new Bundle(); + args.putLong("chat_id", -chatActivity.getDialogId()); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = chatActivity.getMessagesController().getChatFull(-chatActivity.getDialogId()); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + }; + StatisticActivity fragment = new StatisticActivity(args); + showAsSheet(fragment); + }); + limitReachedBottomSheet.show(); + }); + return; + } Bulletin bulletin = null; EmojiThemes newTheme = selectedItem.chatTheme; if (selectedItem != null && newTheme != currentTheme) { @@ -1124,6 +1240,147 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } } + public static void openGalleryForBackground( + Activity activity, + BaseFragment fragment, + long dialogId, + Theme.ResourcesProvider resourcesProvider, + Utilities.Callback onSet, + ThemePreviewActivity.DayNightSwitchDelegate toggleTheme, + TL_stories.TL_premium_boostsStatus cachedBoostsStatus + ) { + ChatAttachAlert chatAttachAlert = new ChatAttachAlert(activity, fragment, false, false, false, resourcesProvider); + chatAttachAlert.drawNavigationBar = true; + chatAttachAlert.setupPhotoPicker(LocaleController.getString("ChooseBackground", R.string.ChooseBackground)); + chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + long start; + @Override + public boolean selectItemOnClicking() { + start = System.currentTimeMillis(); + return true; + } + + @Override + public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { + try { + HashMap photos = chatAttachAlert.getPhotoLayout().getSelectedPhotos(); + if (!photos.isEmpty()) { + MediaController.PhotoEntry entry = (MediaController.PhotoEntry) photos.values().iterator().next(); + String path; + if (entry.imagePath != null) { + path = entry.imagePath; + } else { + path = entry.path; + } + if (path != null) { + File currentWallpaperPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.random.nextInt() + ".jpg"); + Point screenSize = AndroidUtilities.getRealScreenSize(); + Bitmap bitmap = ImageLoader.loadBitmap(path, null, screenSize.x, screenSize.y, true); + FileOutputStream stream = new FileOutputStream(currentWallpaperPath); + bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + + ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.FileWallpaper("", currentWallpaperPath, currentWallpaperPath), bitmap) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + themePreviewActivity.boostsStatus = cachedBoostsStatus; + themePreviewActivity.setResourceProvider(resourcesProvider); + themePreviewActivity.setOnSwitchDayNightDelegate(toggleTheme); + themePreviewActivity.setInitialModes(false, false, .20f); + themePreviewActivity.setDialogId(dialogId); + themePreviewActivity.setDelegate(wallPaper -> { + chatAttachAlert.dismissInternal(); + if (onSet != null) { + onSet.run(wallPaper); + } + }); + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + params.occupyNavigationBar = true; + fragment.showAsSheet(themePreviewActivity, params); + + chatAttachAlert.dismiss(); + } + } + } catch (Throwable e) { + FileLog.e(e); + } + } + + @Override + public void onWallpaperSelected(Object object) { + ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + wallpaperActivity.boostsStatus = cachedBoostsStatus; + wallpaperActivity.setResourceProvider(resourcesProvider); + wallpaperActivity.setOnSwitchDayNightDelegate(toggleTheme); + wallpaperActivity.setDialogId(dialogId); + wallpaperActivity.setDelegate(wallPaper -> { + chatAttachAlert.dismissInternal(); + if (onSet != null) { + onSet.run(wallPaper); + } + }); + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + params.occupyNavigationBar = true; + fragment.showAsSheet(wallpaperActivity, params); + } + }); + chatAttachAlert.setMaxSelectedPhotos(1, false); + chatAttachAlert.init(); + chatAttachAlert.getPhotoLayout().loadGalleryPhotos(); + chatAttachAlert.show(); + + FrameLayout chatAttachButton = new FrameLayout(activity) { + + Paint paint = new Paint(); + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(48), MeasureSpec.EXACTLY)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + paint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + canvas.drawRect(0, 0, getMeasuredWidth(), 1, paint); + } + }; + AnimatedTextView chatAttachButtonText = new AnimatedTextView(activity, true, true, true); + chatAttachButtonText.setTextSize(dp(14)); + chatAttachButtonText.setText(LocaleController.getString(R.string.SetColorAsBackground)); + chatAttachButtonText.setGravity(Gravity.CENTER); + chatAttachButtonText.setTextColor(Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider)); + chatAttachButton.addView(chatAttachButtonText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + chatAttachButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(0), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), (int) (0.3f * 255)))); + chatAttachButton.setOnClickListener(v -> { + if (chatAttachAlert.getCurrentAttachLayout() == chatAttachAlert.getPhotoLayout()) { + chatAttachButtonText.setText(LocaleController.getString(R.string.ChooseBackgroundFromGallery)); + chatAttachAlert.openColorsLayout(); +// chatAttachAlert.colorsLayout.updateColors(forceDark); + } else { + chatAttachButtonText.setText(LocaleController.getString(R.string.SetColorAsBackground)); + chatAttachAlert.showLayout(chatAttachAlert.getPhotoLayout()); + } +// WallpapersListActivity wallpapersListActivity = new WallpapersListActivity(WallpapersListActivity.TYPE_ALL, chatActivity.getDialogId()); +// chatActivity.presentFragment(wallpapersListActivity); +// chatAttachAlert.dismiss(); +// dismiss(); + }); + chatAttachAlert.sizeNotifierFrameLayout.addView(chatAttachButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + } + + private void openGalleryForBackground() { chatAttachAlert = new ChatAttachAlert(chatActivity.getParentActivity(), chatActivity, false, false, false, chatActivity.getResourceProvider()); chatAttachAlert.drawNavigationBar = true; @@ -1161,9 +1418,10 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen return true; } }; + themePreviewActivity.boostsStatus = boostsStatus; themePreviewActivity.setInitialModes(false, false, .20f); themePreviewActivity.setDialogId(chatActivity.getDialogId()); - themePreviewActivity.setDelegate(() -> { + themePreviewActivity.setDelegate(wallPaper -> { chatAttachAlert.dismissInternal(); dismiss(); }); @@ -1183,8 +1441,9 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen return true; } }; + wallpaperActivity.boostsStatus = boostsStatus; wallpaperActivity.setDialogId(chatActivity.getDialogId()); - wallpaperActivity.setDelegate(() -> { + wallpaperActivity.setDelegate(wallPaper -> { chatAttachAlert.dismissInternal(); dismiss(); }); @@ -1202,7 +1461,7 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(48), MeasureSpec.EXACTLY)); } @Override @@ -1213,12 +1472,12 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } }; chatAttachButtonText = new AnimatedTextView(getContext(), true, true, true); - chatAttachButtonText.setTextSize(AndroidUtilities.dp(14)); + chatAttachButtonText.setTextSize(dp(14)); chatAttachButtonText.setText(LocaleController.getString("SetColorAsBackground", R.string.SetColorAsBackground)); chatAttachButtonText.setGravity(Gravity.CENTER); chatAttachButtonText.setTextColor(getThemedColor(Theme.key_featuredStickers_addButton)); chatAttachButton.addView(chatAttachButtonText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); - chatAttachButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(0), getThemedColor(Theme.key_windowBackgroundWhite), ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); + chatAttachButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(0), getThemedColor(Theme.key_windowBackgroundWhite), ColorUtils.setAlphaComponent(getThemedColor(Theme.key_featuredStickers_addButton), (int) (0.3f * 255)))); chatAttachButton.setOnClickListener(v -> { if (chatAttachAlert.getCurrentAttachLayout() == chatAttachAlert.getPhotoLayout()) { chatAttachButtonText.setText(LocaleController.getString("ChooseBackgroundFromGallery", R.string.ChooseBackgroundFromGallery)); @@ -1261,6 +1520,27 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen } } + private void showAsSheet(BaseFragment fragment) { + if (fragment == null) { + return; + } + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + fragment.setResourceProvider(chatActivity.getResourceProvider()); + params.onOpenAnimationFinished = () -> { + PhotoViewer.getInstance().closePhoto(false, false); + }; + params.onPreFinished = () -> { + fixColorsAfterAnotherWindow(); + }; + params.onDismiss = () -> { + overlayFragment = null; + }; + params.occupyNavigationBar = true; + chatActivity.showAsSheet(overlayFragment = fragment, params); + } + private void showAsSheet(ThemePreviewActivity themePreviewActivity) { BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); params.transitionFromLeft = true; @@ -1274,6 +1554,11 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen return forceDark; } + @Override + public boolean supportsAnimation() { + return true; + } + @Override public void switchDayNight(boolean animated) { forceDark = !forceDark; @@ -1316,5 +1601,12 @@ public class ChatThemeBottomSheet extends BottomSheet implements NotificationCen public ChatThemeItem(EmojiThemes chatTheme) { this.chatTheme = chatTheme; } + + public String getEmoticon() { + if (chatTheme == null || chatTheme.showAsDefaultStub) { + return null; + } + return chatTheme.getEmoticon(); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DotDividerSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DotDividerSpan.java index b886854f1..b8e820c77 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/DotDividerSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DotDividerSpan.java @@ -14,7 +14,7 @@ public class DotDividerSpan extends ReplacementSpan { Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); int color; int topPadding; - private int size = 3; + private float size = 3; @Override public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i1, @Nullable Paint.FontMetricsInt fontMetricsInt) { @@ -35,7 +35,7 @@ public class DotDividerSpan extends ReplacementSpan { this.topPadding = topPadding; } - public void setSize(int size) { + public void setSize(float size) { this.size = size; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java index 8af807ab9..26c4620d7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -231,7 +231,7 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not editText.setHintTextColor(getThemedColor(Theme.key_windowBackgroundWhiteHintText)); editText.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); editText.setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); - editText.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), AndroidUtilities.dp(8)); + editText.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), AndroidUtilities.dp(11)); addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 11 : 0, 1, LocaleController.isRTL ? 0 : 11, 0)); } else if (style == STYLE_STORY || style == STYLE_PHOTOVIEWER) { editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); @@ -276,7 +276,7 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not if (style == STYLE_FRAGMENT) { emojiIconDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_messagePanelIcons), PorterDuff.Mode.MULTIPLY)); emojiIconDrawable.setIcon(R.drawable.smiles_tab_smiles, false); - addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT), 0, 0, 0, 7)); + addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT), 0, 0, 0, 5)); } else if (style == STYLE_STORY || style == STYLE_PHOTOVIEWER) { emojiIconDrawable.setColorFilter(new PorterDuffColorFilter(0x8cffffff, PorterDuff.Mode.MULTIPLY)); emojiIconDrawable.setIcon(R.drawable.input_smile, false); @@ -367,10 +367,11 @@ public class EditTextEmoji extends FrameLayout implements NotificationCenter.Not public void setEnabled(boolean enabled) { editText.setEnabled(enabled); emojiButton.setVisibility(enabled ? VISIBLE : GONE); + int bottomPadding = AndroidUtilities.dp(currentStyle == STYLE_FRAGMENT ? 11 : 8); if (enabled) { - editText.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), AndroidUtilities.dp(8)); + editText.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(40) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(40), bottomPadding); } else { - editText.setPadding(0, 0, 0, AndroidUtilities.dp(8)); + editText.setPadding(0, 0, 0, bottomPadding); } } 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 b0f45edd6..9b4ed0589 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -5774,7 +5774,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } } - if (MessagesController.getInstance(currentAccount).premiumLocked) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { for (int a = 0; a < favouriteStickers.size(); a++) { if (MessageObject.isPremiumSticker(favouriteStickers.get(a))) { favouriteStickers.remove(a); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java index 5c53c20cb..abcc5a92a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java @@ -1706,7 +1706,7 @@ public class FilterTabsView extends FrameLayout { @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { - if (MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked && (!isEditing || (viewHolder.getAdapterPosition() == 0 && tabs.get(0).isDefault && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium()))) { + if (MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked() && (!isEditing || (viewHolder.getAdapterPosition() == 0 && tabs.get(0).isDefault && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium()))) { return makeMovementFlags(0, 0); } return makeMovementFlags(ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0); @@ -1714,7 +1714,7 @@ public class FilterTabsView extends FrameLayout { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { - if (MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked && ((source.getAdapterPosition() == 0 || target.getAdapterPosition() == 0) && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium())) { + if (MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked() && ((source.getAdapterPosition() == 0 || target.getAdapterPosition() == 0) && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium())) { return false; } adapter.swapElements(source.getAdapterPosition(), target.getAdapterPosition()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FireworksOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FireworksOverlay.java index 917795a89..d285a80d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FireworksOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FireworksOverlay.java @@ -32,11 +32,13 @@ public class FireworksOverlay extends View { private float speedCoef = 1.0f; private int fallingDownCount; private static Drawable[] heartDrawable; + private static Drawable[] starsDrawable; private static final int particlesCount = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW ? 50 : 60; private static final int fallParticlesCount = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW ? 20 : 30; private boolean isFebruary14; + private boolean withStars; - private static int[] colors = new int[] { + private static int[] colors = new int[]{ 0xff2CBCE8, 0xff9E04D0, 0xffFECB02, @@ -45,7 +47,7 @@ public class FireworksOverlay extends View { 0xff59B86C }; - private static int[] heartColors = new int[] { + private static int[] heartColors = new int[]{ 0xffE2557B, 0xff5FCDF2, 0xffFFDA69, @@ -53,6 +55,14 @@ public class FireworksOverlay extends View { 0xffE376B0 }; + private static int[] starsColors = new int[]{ + 0xff1e80ff, + 0xff10c689, + 0xffff5997, + 0xffff9724, + 0xff2fe1f9 + }; + static { paint = new Paint[colors.length]; for (int a = 0; a < paint.length; a++) { @@ -85,15 +95,23 @@ public class FireworksOverlay extends View { canvas.drawRoundRect(rect, AndroidUtilities.dp(2), AndroidUtilities.dp(2), paint[colorType]); canvas.restore(); } else if (type == 2) { - Drawable drawable = heartDrawable[colorType]; - int w = drawable.getIntrinsicWidth() / 2; - int h = drawable.getIntrinsicHeight() / 2; - drawable.setBounds((int) x - w, (int) y - h, (int) x + w, (int) y + h); - canvas.save(); - canvas.rotate(rotation, x, y); - canvas.scale(typeSize / 6.0f, typeSize / 6.0f, x, y); - drawable.draw(canvas); - canvas.restore(); + Drawable drawable = null; + if (starsDrawable != null) { + drawable = starsDrawable[colorType]; + } + if (heartDrawable != null) { + drawable = heartDrawable[colorType]; + } + if (drawable != null) { + int w = drawable.getIntrinsicWidth() / 2; + int h = drawable.getIntrinsicHeight() / 2; + drawable.setBounds((int) x - w, (int) y - h, (int) x + w, (int) y + h); + canvas.save(); + canvas.rotate(rotation, x, y); + canvas.scale(typeSize / 6.0f, typeSize / 6.0f, x, y); + drawable.draw(canvas); + canvas.restore(); + } } } @@ -170,16 +188,27 @@ public class FireworksOverlay extends View { } } + private void loadStarsDrawables() { + if (starsDrawable != null) { + return; + } + starsDrawable = new Drawable[starsColors.length]; + for (int a = 0; a < starsDrawable.length; a++) { + starsDrawable[a] = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_settings_premium).mutate(); + starsDrawable[a].setColorFilter(new PorterDuffColorFilter(starsColors[a], PorterDuff.Mode.MULTIPLY)); + } + } + private int getHeightForAnimation() { if (getMeasuredHeight() == 0) { - return ((View)getParent()).getHeight(); + return ((View) getParent()).getHeight(); } return getMeasuredHeight(); } private int getWidthForAnimation() { if (getMeasuredWidth() == 0) { - return ((View)getParent()).getWidth(); + return ((View) getParent()).getWidth(); } return getMeasuredWidth(); } @@ -190,6 +219,9 @@ public class FireworksOverlay extends View { if (isFebruary14 && particle.type == 0) { particle.type = 2; particle.colorType = (byte) Utilities.random.nextInt(heartColors.length); + } else if (withStars && Utilities.random.nextBoolean()) { + particle.type = 2; + particle.colorType = (byte) Utilities.random.nextInt(starsColors.length); } else { particle.colorType = (byte) Utilities.random.nextInt(colors.length); } @@ -223,11 +255,10 @@ public class FireworksOverlay extends View { return started; } - public void start() { + public void start(boolean withStars) { + this.withStars = withStars; particles.clear(); - if (Build.VERSION.SDK_INT >= 18) { - setLayerType(View.LAYER_TYPE_HARDWARE, null); - } + setLayerType(View.LAYER_TYPE_HARDWARE, null); started = true; startedFall = false; fallingDownCount = 0; @@ -239,6 +270,8 @@ public class FireworksOverlay extends View { isFebruary14 = month == 1 && (BuildVars.DEBUG_PRIVATE_VERSION || day == 14); if (isFebruary14) { loadHeartDrawables(); + } else if (withStars) { + loadStarsDrawables(); } for (int a = 0; a < particlesCount; a++) { particles.add(createParticle(false)); @@ -246,6 +279,10 @@ public class FireworksOverlay extends View { invalidate(); } + public void start() { + start(false); + } + private void startFall() { if (startedFall) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java index 742895ed1..a4a4bce6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java @@ -115,6 +115,9 @@ public class FolderBottomSheet extends BottomSheetWithRecyclerListView { req.chatlist = new TL_chatlists.TL_inputChatlistDialogFilter(); req.chatlist.filter_id = filterId; fragment.getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (fragment.getParentActivity() == null) { + return; + } FolderBottomSheet sheet; if (res instanceof TLRPC.Vector) { ArrayList suggestions = new ArrayList<>(); 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 bb99aa76d..6d6afa2ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -650,7 +650,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (cameraThread != null) { - cameraThread.shutdown(0); + cameraThread.shutdown(0, 0); cameraThread = null; } if (cameraSession != null) { @@ -765,7 +765,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - public void send(int state, boolean notify, int scheduleDate) { + public void send(int state, boolean notify, int scheduleDate, int ttl) { if (textureView == null) { return; } @@ -803,7 +803,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter videoEditedInfo.encryptedFile = encryptedFile; videoEditedInfo.key = key; videoEditedInfo.iv = iv; - delegate.sendMedia(new MediaController.PhotoEntry(0, 0, 0, cameraFile.getAbsolutePath(), 0, true, 0, 0, 0), videoEditedInfo, notify, scheduleDate, false); + MediaController.PhotoEntry entry = new MediaController.PhotoEntry(0, 0, 0, cameraFile.getAbsolutePath(), 0, true, 0, 0, 0); + entry.ttl = ttl; + delegate.sendMedia(entry, videoEditedInfo, notify, scheduleDate, false); if (scheduleDate != 0) { startAnimation(false); } @@ -828,7 +830,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter send = 1; } saveLastCameraBitmap(); - cameraThread.shutdown(send); + cameraThread.shutdown(send, ttl); cameraThread = null; } if (cancelled) { @@ -871,7 +873,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.recordStopped, recordingGuid, byGesture ? 0 : 6); if (cameraThread != null) { saveLastCameraBitmap(); - cameraThread.shutdown(0); + cameraThread.shutdown(0, 0); cameraThread = null; } if (cameraFile != null) { @@ -1562,7 +1564,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter case DO_SHUTDOWN_MESSAGE: finish(); if (recording) { - videoEncoder.stopRecording(inputMessage.arg1); + videoEncoder.stopRecording(inputMessage.arg1, inputMessage.arg2); } Looper looper = Looper.myLooper(); if (looper != null) { @@ -1636,10 +1638,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - public void shutdown(int send) { + public void shutdown(int send, int ttl) { Handler handler = getHandler(); if (handler != null) { - sendMessage(handler.obtainMessage(DO_SHUTDOWN_MESSAGE, send, 0), 0); + sendMessage(handler.obtainMessage(DO_SHUTDOWN_MESSAGE, send, ttl), 0); } } @@ -1682,7 +1684,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter encoder.prepareEncoder(); } catch (Exception e) { FileLog.e(e); - encoder.handleStopRecording(0); + encoder.handleStopRecording(0, 0); Looper.myLooper().quit(); } break; @@ -1691,7 +1693,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (BuildVars.LOGS_ENABLED) { FileLog.e("InstantCamera stop encoder"); } - encoder.handleStopRecording(inputMessage.arg1); + encoder.handleStopRecording(inputMessage.arg1, inputMessage.arg2); break; } case MSG_VIDEOFRAME_AVAILABLE: { @@ -1777,6 +1779,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter private boolean ready; private volatile boolean running; private volatile int sendWhenDone; + private volatile int sendWhenDoneTTL; private long skippedTime; private boolean skippedFirst; @@ -1901,7 +1904,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } catch (Exception e) { FileLog.e(e); } - handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, 0)); + handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, sendWhenDoneTTL)); } }; @@ -1950,8 +1953,8 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter handler.sendMessage(handler.obtainMessage(MSG_START_RECORDING)); } - public void stopRecording(int send) { - handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, send, 0)); + public void stopRecording(int send, int ttl) { + handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, send, ttl)); AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); }); @@ -2279,10 +2282,11 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter } } - private void handleStopRecording(final int send) { + private void handleStopRecording(final int send, final int ttl) { if (running) { FileLog.d("InstantCamera handleStopRecording running=false"); sendWhenDone = send; + sendWhenDoneTTL = ttl; running = false; return; } @@ -2374,13 +2378,17 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter if (send == 1) { if (delegate.isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(delegate.getParentActivity(), delegate.getDialogId(), (notify, scheduleDate) -> { - delegate.sendMedia(new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0), videoEditedInfo, notify, scheduleDate, false); + 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); } else { - delegate.sendMedia(new MediaController.PhotoEntry(0, 0, 0, videoFile.getAbsolutePath(), 0, true, 0, 0, 0), videoEditedInfo, true, 0, false); + 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 { videoPlayer = new VideoPlayer(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java index efe52e57a..7e49a8f61 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java @@ -39,9 +39,9 @@ public class MediaActionDrawable extends Drawable { public static final int ICON_UPDATE = 15; private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + public Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint backPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + public Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint paint3 = new Paint(Paint.ANTI_ALIAS_FLAG); private RectF rect = new RectF(); private ColorFilter colorFilter; @@ -274,7 +274,7 @@ public class MediaActionDrawable extends Drawable { } } - private void applyShaderMatrix(boolean path) { + public void applyShaderMatrix(boolean path) { if (messageDrawable != null && messageDrawable.hasGradient() && !hasOverlayImage) { android.graphics.Rect bounds = getBounds(); Shader shader = messageDrawable.getGradientShader(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java index fa892ea4e..c388ecd0e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java @@ -30,7 +30,7 @@ public class MenuToItemOptions implements Menu { @Override public MenuItem add(int groupId, int itemId, int order, CharSequence title) { - if (premiumLock != null && FloatingToolbar.premiumOptions.contains(itemId) && MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked) { + if (premiumLock != null && FloatingToolbar.premiumOptions.contains(itemId) && MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked()) { return null; } itemOptions.add(title, () -> onMenuClicked.run(itemId)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java index 6fad4fcf0..a4c57f540 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java @@ -910,7 +910,7 @@ public class MessagePreviewView extends FrameLayout { menu.addView(btn1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); } - if (!messagePreviewParams.noforwards) { + if (!messagePreviewParams.noforwards && !messagePreviewParams.hasSecretMessages) { FrameLayout btn2 = new FrameLayout(context); replyAnotherChatButton = new ActionBarMenuSubItem(context, true, false, false, resourcesProvider); replyAnotherChatButton.setTextAndIcon(LocaleController.getString(R.string.ReplyToAnotherChat), R.drawable.msg_forward_replace); @@ -923,7 +923,7 @@ public class MessagePreviewView extends FrameLayout { menu.addView(btn2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); } - if (!messagePreviewParams.isSecret) { + if (!messagePreviewParams.noforwards && !messagePreviewParams.hasSecretMessages) { ActionBarPopupWindow.GapView gap2 = new ActionBarPopupWindow.GapView(context, resourcesProvider); gap2.setTag(R.id.fit_width_tag, 1); menu.addView(gap2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java index 4cade2177..de8d17479 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java @@ -58,7 +58,7 @@ public class MotionBackgroundDrawable extends Drawable { private int translationY; - private boolean isPreview; + public boolean isPreview; public float posAnimationProgress = 1.0f; private int phase; @@ -115,6 +115,8 @@ public class MotionBackgroundDrawable extends Drawable { private float indeterminateSpeedScale = 1f; private boolean isIndeterminateAnimation; private Paint overrideBitmapPaint; + private int bitmapWidth = 60; + private int bitmapHeight = 80; public MotionBackgroundDrawable() { super(); @@ -122,11 +124,19 @@ public class MotionBackgroundDrawable extends Drawable { } public MotionBackgroundDrawable(int c1, int c2, int c3, int c4, boolean preview) { - this(c1, c2, c3 ,c4, 0, preview); + this(c1, c2, c3, c4, 0, preview); } public MotionBackgroundDrawable(int c1, int c2, int c3, int c4, int rotation, boolean preview) { + this(c1, c2, c3, c4, rotation, preview, false); + } + + public MotionBackgroundDrawable(int c1, int c2, int c3, int c4, int rotation, boolean preview, boolean square) { super(); + if (square) { + bitmapWidth = 80; + bitmapHeight = 80; + } isPreview = preview; setColors(c1, c2, c3, c4, rotation, false); init(); @@ -134,13 +144,13 @@ public class MotionBackgroundDrawable extends Drawable { @SuppressLint("NewApi") private void init() { - currentBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); + currentBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); for (int i = 0; i < ANIMATION_CACHE_BITMAPS_COUNT; i++) { - gradientToBitmap[i] = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); + gradientToBitmap[i] = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); } gradientCanvas = new Canvas(currentBitmap); - gradientFromBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); + gradientFromBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); gradientFromCanvas = new Canvas(gradientFromBitmap); Utilities.generateGradient(currentBitmap, true, phase, interpolator.getInterpolation(posAnimationProgress), currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java index 0798d2a61..0ac98ccf3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java @@ -64,6 +64,9 @@ public class EntityView extends FrameLayout { default void onEntityDragEnd(boolean delete) {} default void onEntityDragTrash(boolean enter) {} default void onEntityHandleTouched() {} + default boolean isEntityDeletable() { + return true; + } } private float previousLocationX, previousLocationY; @@ -223,7 +226,11 @@ public class EntityView extends FrameLayout { delegate.onEntityDraggedBottom(position.y + getHeight() / 2f * scale > ((View) getParent()).getHeight() - dp(64 + 50)); } - updateTrash(!multitouch && MathUtils.distance(x, y, ((View) getParent()).getWidth() / 2f, ((View) getParent()).getHeight() - dp(76)) < dp(32)); + updateTrash( + (delegate == null || delegate.isEntityDeletable()) && + !multitouch && + MathUtils.distance(x, y, ((View) getParent()).getWidth() / 2f, ((View) getParent()).getHeight() - dp(76)) < dp(32) + ); bounce.setPressed(false); @@ -709,7 +716,7 @@ public class EntityView extends FrameLayout { updateSelectionView(); } - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { return new Rect(0, 0, 0, 0); } @@ -1006,9 +1013,13 @@ public class EntityView extends FrameLayout { return false; } + protected float getBounceScale() { + return .04f; + } + @Override protected void dispatchDraw(Canvas canvas) { - final float scale = bounce.getScale(.05f); + final float scale = bounce.getScale(getBounceScale()); canvas.save(); canvas.scale(scale, scale, getWidth() / 2f, getHeight() / 2f); if (getParent() instanceof View) { 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 564526e7d..38aff838f 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 @@ -6,7 +6,9 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; @@ -17,6 +19,8 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.SweepGradient; import android.graphics.drawable.GradientDrawable; +import android.location.Address; +import android.location.Geocoder; import android.os.Build; import android.os.Looper; import android.text.Layout; @@ -24,6 +28,7 @@ import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; @@ -48,12 +53,14 @@ import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BuildVars; import org.telegram.messenger.DispatchQueue; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; @@ -65,15 +72,18 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.BubbleActivity; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.ChatActivityEnterViewAnimatedIconView; +import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.IPhotoPaintView; @@ -93,12 +103,19 @@ import org.telegram.ui.Components.Size; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; import org.telegram.ui.Components.StickerMasksAlert; +import org.telegram.ui.Components.ThanosEffect; import org.telegram.ui.PhotoViewer; import org.telegram.ui.Stories.recorder.EmojiBottomSheet; +import org.telegram.ui.Stories.recorder.PaintView; +import org.telegram.ui.ThemePreviewActivity; +import org.telegram.ui.WallpapersListActivity; +import java.io.File; +import java.io.FileOutputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPaintView, PaintToolsView.Delegate, EntityView.EntityViewDelegate, PaintTextOptionsView.Delegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, NotificationCenter.NotificationCenterDelegate { @@ -129,6 +146,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh private View renderInputView; private FrameLayout selectionContainerView; private EntitiesContainerView entitiesView; + private ThanosEffect thanosEffect; private FrameLayout topLayout; public FrameLayout bottomLayout; public FrameLayout overlayLayout; @@ -440,7 +458,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh for (int a = 0, N = entities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = entities.get(a); EntityView view; - if (entity.type == 0) { + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER) { StickerView stickerView = createSticker(entity.parentObject, entity.document, false); if ((entity.subType & 2) != 0) { stickerView.mirror(); @@ -449,7 +467,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.width = entity.viewWidth; layoutParams.height = entity.viewHeight; - } else if (entity.type == 1) { + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT) { TextPaintView textPaintView = createText(false); textPaintView.setType(entity.subType); textPaintView.setTypeface(entity.textTypeface); @@ -474,6 +492,19 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh swatch.color = entity.color; textPaintView.setSwatch(swatch); view = textPaintView; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO) { + PhotoView photoView = createPhoto(entity.text, false); + photoView.preloadSegmented(entity.segmentedPath); + if ((entity.subType & 2) != 0) { + photoView.mirror(); + } + if ((entity.subType & 16) != 0) { + photoView.toggleSegmented(false); + } + view = photoView; + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + layoutParams.width = entity.viewWidth; + layoutParams.height = entity.viewHeight; } else { continue; } @@ -1371,7 +1402,7 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh EmojiBottomSheet emojiBottomSheet = new EmojiBottomSheet(getContext(), false, resourcesProvider) { @Override public boolean canShowWidget(Integer id) { - return false; + return id == WIDGET_PHOTO; } }; emojiBottomSheet.whenDocumentSelected((parentObject, document, isGif) -> { @@ -1380,6 +1411,11 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh stickerView.setScale(1.5f); } }); + emojiBottomSheet.whenWidgetSelected(widget -> { + if (widget == EmojiBottomSheet.WIDGET_PHOTO) { + showPhotoAlert(); + } + }); emojiBottomSheet.setOnDismissListener(di -> { onOpenCloseStickersAlert(false); switchTab(wasSelectedIndex); @@ -1388,6 +1424,132 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh onOpenCloseStickersAlert(true); } + private void showPhotoAlert() { + ChatAttachAlert chatAttachAlert = new ChatAttachAlert(getContext(), new ChatActivity(null) { + @Override + public long getDialogId() { + return 0; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + + @Override + public boolean isKeyboardVisible() { + return false; + } + + @Override + public Activity getParentActivity() { + return AndroidUtilities.findActivity(LPhotoPaintView.this.getContext()); + } + + @Override + public TLRPC.User getCurrentUser() { + return UserConfig.getInstance(currentAccount).getCurrentUser(); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + + }, false, false, false, resourcesProvider); + chatAttachAlert.drawNavigationBar = true; + chatAttachAlert.setupPhotoPicker(LocaleController.getString(R.string.AddImage)); + chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + long start; + @Override + public boolean selectItemOnClicking() { + start = System.currentTimeMillis(); + return true; + } + + @Override + public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { + try { + HashMap photos = chatAttachAlert.getPhotoLayout().getSelectedPhotos(); + if (!photos.isEmpty()) { + MediaController.PhotoEntry entry = (MediaController.PhotoEntry) photos.values().iterator().next(); + String path; + if (entry.imagePath != null) { + path = entry.imagePath; + } else { + path = entry.path; + } + appearAnimation(createPhoto(path, true)); + chatAttachAlert.dismiss(); + } + } catch (Throwable e) { + FileLog.e(e); + } + } + }); + chatAttachAlert.setOnDismissListener(dialog -> { + MediaController.forceBroadcastNewPhotos = false; + }); + chatAttachAlert.setMaxSelectedPhotos(1, false); + chatAttachAlert.init(); + MediaController.forceBroadcastNewPhotos = true; + chatAttachAlert.getPhotoLayout().loadGalleryPhotos(); + chatAttachAlert.show(); + } + + public void appearAnimation(View view) { + float scaleX = view.getScaleX(), scaleY = view.getScaleY(); + view.setScaleX(scaleX * .5f); + view.setScaleY(scaleY * .5f); + view.setAlpha(0f); + view.animate().scaleX(scaleX).scaleY(scaleY).alpha(1f).setInterpolator(new OvershootInterpolator(3f)).setDuration(240).withEndAction(() -> { + if (view instanceof EntityView) { + ((EntityView) view).updateSelectionView(); + selectEntity((EntityView) view); + } + }).start(); + } + + public PhotoView createPhoto(String path, boolean select) { + Size size = basePhotoSize(path); + Pair orientation = AndroidUtilities.getImageOrientation(path); + if ((orientation.first / 90 % 2) == 1) { + float w = size.width; + size.width = size.height; + size.height = w; + } + PhotoView view = new PhotoView(getContext(), centerPositionForEntity(), 0, 1f, size, path, orientation.first, orientation.second); + view.centerImage.setLayerNum(4 + 8); +// view.setHasStickyX(true); +// view.setHasStickyY(true); + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + selectEntity(view); + } + return view; + } + + private Size basePhotoSize(String path) { + float a = 1f; + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, opts); + a = (float) opts.outWidth / opts.outHeight; + } catch (Exception e) { + FileLog.e(e); + } + if (a > 1) { + float side = (float) Math.floor(entitiesView.getMeasuredWidth() * 0.5); + return new Size(side, side / a); + } else { + float side = (float) Math.floor(entitiesView.getMeasuredHeight() * 0.5); + return new Size(side * a, side); + } + } + protected void onOpenCloseStickersAlert(boolean open) {} protected void onTextAdd() {} @@ -1434,6 +1596,11 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh entitiesView.setScaleX(baseScale); entitiesView.setScaleY(baseScale); entitiesView.measure(MeasureSpec.makeMeasureSpec((int) paintingSize.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) paintingSize.height, MeasureSpec.EXACTLY)); + if (thanosEffect != null) { + thanosEffect.measure(MeasureSpec.makeMeasureSpec((int) paintingSize.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) paintingSize.height, MeasureSpec.EXACTLY)); + thanosEffect.setScaleX(baseScale); + thanosEffect.setScaleY(baseScale); + } updateEntitiesSelections(); selectionContainerView.measure(MeasureSpec.makeMeasureSpec((int) renderWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) renderHeight, MeasureSpec.EXACTLY)); measureChild(bottomLayout, widthMeasureSpec, heightMeasureSpec); @@ -1497,6 +1664,9 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh int x2 = x + (renderView.getMeasuredWidth() - entitiesView.getMeasuredWidth()) / 2; int y2 = y + (renderView.getMeasuredHeight() - entitiesView.getMeasuredHeight()) / 2; entitiesView.layout(x2, y2, x2 + entitiesView.getMeasuredWidth(), y2 + entitiesView.getMeasuredHeight()); + if (thanosEffect != null) { + thanosEffect.layout(x2, y2, x2 + entitiesView.getMeasuredWidth(), y2 + entitiesView.getMeasuredHeight()); + } selectionContainerView.layout(x, y, x + selectionContainerView.getMeasuredWidth(), y + selectionContainerView.getMeasuredHeight()); } @@ -1753,6 +1923,23 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh if (stickerView.isMirrored()) { mediaEntity.subType |= 2; } + } else if (entity instanceof PhotoView) { + PhotoView photoView = (PhotoView) entity; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_PHOTO; + Size size = photoView.getBaseSize(); + mediaEntity.width = size.width; + mediaEntity.height = size.height; + mediaEntity.text = photoView.getPath(currentAccount); + if (photoView.isMirrored()) { + mediaEntity.subType |= 2; + } + if (photoView.hasSegmentedImage() && photoView.isSegmented()) { + File segmentedFile = photoView.saveSegmentedImage(currentAccount); + if (segmentedFile != null) { + mediaEntity.subType |= 16; + mediaEntity.segmentedPath = segmentedFile.getPath(); + } + } } else { continue; } @@ -2573,6 +2760,30 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh }); parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + if (entityView instanceof PhotoView && ((PhotoView) entityView).hasSegmentedImage()) { + PhotoView photoView = (PhotoView) entityView; + TextView cutView = new TextView(getContext()); + cutView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + cutView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + cutView.setGravity(Gravity.CENTER_VERTICAL); + cutView.setEllipsize(TextUtils.TruncateAt.END); + cutView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); + cutView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + cutView.setTag(5); + cutView.setText(LocaleController.getString(photoView.isSegmented() ? R.string.SegmentationUndoCutOut : R.string.SegmentationCutOut)); + cutView.setOnClickListener(v -> { + photoView.toggleSegmented(true); + if (photoView.isSegmented()) { + onSwitchSegmentedAnimation(photoView); + } + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(cutView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + photoView.highlightSegmented(); + } + popupLayout.addView(parent); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) parent.getLayoutParams(); @@ -2883,6 +3094,9 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh } private void registerRemovalUndo(final EntityView entityView) { + if (entityView == null) { + return; + } undoStore.registerUndo(entityView.getUUID(), () -> removeEntity(entityView)); } @@ -3447,4 +3661,64 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh } } } + + public ThanosEffect getThanosEffect() { + if (!ThanosEffect.supports()) { + return null; + } + if (thanosEffect == null) { + addView(thanosEffect = new ThanosEffect(getContext(), () -> { + ThanosEffect thisThanosEffect = thanosEffect; + if (thisThanosEffect != null) { + thanosEffect = null; + removeView(thisThanosEffect); + } + })); + } + return thanosEffect; + } + + public void onSwitchSegmentedAnimation(PhotoView photoView) { + if (photoView == null) { + return; + } + ThanosEffect thanosEffect = getThanosEffect(); + if (thanosEffect == null) { + photoView.onSwitchSegmentedAnimationStarted(false); + return; + } + Bitmap bitmap = photoView.getSegmentedOutBitmap(); + if (bitmap == null) { + photoView.onSwitchSegmentedAnimationStarted(false); + return; + } + Matrix matrix = new Matrix(); + float w = photoView.getWidth(), h = photoView.getHeight(); + float tx = 0, ty = 0; + if (photoView.getRotation() != 0) { + final float bw = bitmap.getWidth(); + final float bh = bitmap.getHeight(); + final float r = (float) Math.sqrt((bw / 2f) * (bw / 2f) + (bh / 2f) * (bh / 2f)); + final float d = 2 * r; + Bitmap newBitmap = Bitmap.createBitmap((int) d, (int) d, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(newBitmap); + canvas.save(); + canvas.rotate(photoView.getRotation(), r, r); + canvas.drawBitmap(bitmap, (d - bw) / 2, (d - bh) / 2, null); + bitmap.recycle(); + bitmap = newBitmap; + + final float pd = 2 * (float) Math.sqrt((w / 2f) * (w / 2f) + (h / 2f) * (h / 2f)); + tx = -(pd - w) / 2; + ty = -(pd - h) / 2; + w = pd; + h = pd; + } + matrix.postScale(w, h); + matrix.postScale(photoView.getScaleX(), photoView.getScaleY(), w / 2f, h / 2f); + matrix.postTranslate(photoView.getX() + tx, photoView.getY() + ty); + thanosEffect.animate(matrix, bitmap, () -> { + photoView.onSwitchSegmentedAnimationStarted(true); + }, () -> {}); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java index e58a66dfd..347aa67bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java @@ -145,7 +145,7 @@ public class LocationView extends EntityView { } @Override - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new Rect(); 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 new file mode 100644 index 000000000..e357f7460 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/MessageEntityView.java @@ -0,0 +1,1361 @@ +package org.telegram.ui.Components.Paint.Views; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.util.Log; +import android.util.SparseIntArray; +import android.view.MotionEvent; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.GridLayoutManagerFixed; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.SharedConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.BotHelpCell; +import org.telegram.ui.Cells.ChatActionCell; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.BlurringShader; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.MessageBackgroundDrawable; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Rect; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.Size; +import org.telegram.ui.Stories.recorder.PreviewView; +import org.telegram.ui.Stories.recorder.StoryEntry; + +import java.io.File; +import java.util.ArrayList; + +public class MessageEntityView extends EntityView { + +// private final ChatActionCell dateCell; + public final FrameLayout container; + public final RecyclerListView listView; + public final ArrayList messageObjects = new ArrayList<>(); + private MessageObject.GroupedMessages groupedMessages; + private final BlurringShader.BlurManager blurManager; + private boolean clipVideoMessageForBitmap; + private boolean usesBackgroundPaint; + private PreviewView.TextureViewHolder videoTextureHolder; + private TextureView textureView; + private boolean textureViewActive; + private int videoWidth = 1, videoHeight = 1; + + public boolean drawForBitmap() { + return false; + } + + public MessageEntityView(Context context, Point position, ArrayList messageObjects, BlurringShader.BlurManager blurManager, boolean isRepostVideoPreview, PreviewView.TextureViewHolder videoTextureHolder) { + this(context, position, 0.0f, 1.0f, messageObjects, blurManager, isRepostVideoPreview, videoTextureHolder); + } + + public MessageEntityView(Context context, Point position, float angle, float scale, ArrayList thisMessageObjects, BlurringShader.BlurManager blurManager, boolean isRepostVideoPreview, PreviewView.TextureViewHolder videoTextureHolder) { + super(context, position); + this.blurManager = blurManager; + setRotation(angle); + setScale(scale); + int date = 0; + for (int i = 0; i < thisMessageObjects.size(); ++i) { + MessageObject msg = thisMessageObjects.get(i); + date = msg.messageOwner.date; + TLRPC.Message messageOwner = copyMessage(msg.messageOwner); + Boolean b = StoryEntry.useForwardForRepost(msg); + if (b != null && b && messageOwner.fwd_from != null && messageOwner.fwd_from.from_id != null) { + messageOwner.from_id = messageOwner.fwd_from.from_id; + messageOwner.peer_id = messageOwner.fwd_from.from_id; + messageOwner.flags &=~ 4; + 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); + messageObjects.add(newMsg); + } +// dateCell = new ChatActionCell(context, false, resourcesProvider) { +// public final BlurringShader.StoryBlurDrawer blurDrawer = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_ACTION_BACKGROUND); +// private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); { +// textPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); +// textPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); +// textPaint.setColor(0xffffffff); +// } +// +// @Override +// protected Paint getThemedPaint(String paintKey) { +// if (Theme.key_paint_chatActionText.equals(paintKey) || Theme.key_paint_chatActionText2.equals(paintKey)) { +// return textPaint; +// } +// if (Theme.key_paint_chatActionBackground.equals(paintKey)) { +// usesBackgroundPaint = true; +// Paint paint = blurDrawer.adapt(isDark).getPaint(1f); +// if (paint != null) { +// return paint; +// } +// } +// return super.getThemedPaint(paintKey); +// } +// }; +// dateCell.setTranslationX(dp(26)); +// dateCell.setCustomDate(date, false, false); +// addView(dateCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + groupedMessages = null; + if (messageObjects.size() > 1) { + groupedMessages = new MessageObject.GroupedMessages(); + groupedMessages.messages.addAll(messageObjects); + groupedMessages.groupId = messageObjects.get(0).getGroupId(); + groupedMessages.calculate(); + } + container = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + listView.measure( + widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + ); + if (textureView != null) { + textureView.measure( + MeasureSpec.makeMeasureSpec(listView.getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(listView.getMeasuredHeight(), MeasureSpec.EXACTLY) + ); + } + int left = listView.getMeasuredWidth(); + int right = 0; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + int childleft = child.getLeft(), childright = child.getRight(); + if (child instanceof ChatMessageCell) { + childleft = child.getLeft() + ((ChatMessageCell) child).getBoundsLeft(); + childright = child.getLeft() + ((ChatMessageCell) child).getBoundsRight(); + } + left = Math.min(childleft, left); + right = Math.max(childright, right); + } + setMeasuredDimension(right - left, listView.getMeasuredHeight()); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int cleft = listView.getMeasuredWidth(); + int cright = 0; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + int childleft = child.getLeft(), childright = child.getRight(); + if (child instanceof ChatMessageCell) { + childleft = child.getLeft() + ((ChatMessageCell) child).getBoundsLeft(); + childright = child.getLeft() + ((ChatMessageCell) child).getBoundsRight(); + } + cleft = Math.min(childleft, cleft); + cright = Math.max(childright, cright); + } + listView.layout(-cleft, 0, listView.getMeasuredWidth() - cleft, listView.getMeasuredHeight()); + if (textureView != null) { + textureView.layout(0, 0, getMeasuredWidth(), listView.getMeasuredHeight()); + } + } + + private final Matrix videoMatrix = new Matrix(); + private final float[] radii = new float[8]; + private final Path clipPath = new Path(); + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == textureView) { + ChatMessageCell cell = getCell(); + if (cell == null) return false; + ImageReceiver photoImage = cell.getPhotoImage(); + if (photoImage == null) return false; + videoMatrix.reset(); + float scale = Math.max(photoImage.getImageWidth() / videoWidth, photoImage.getImageHeight() / videoHeight); + videoMatrix.postScale((float) videoWidth / textureView.getWidth() * scale, (float) videoHeight / textureView.getHeight() * scale); + videoMatrix.postTranslate(listView.getX() + cell.getX() + photoImage.getCenterX() - videoWidth * scale / 2f, listView.getY() + cell.getY() + photoImage.getCenterY() - videoHeight * scale / 2f); + textureView.setTransform(videoMatrix); + canvas.save(); + clipPath.rewind(); + AndroidUtilities.rectTmp.set(listView.getX() + cell.getX() + photoImage.getImageX(), listView.getY() + cell.getY() + photoImage.getImageY(), listView.getX() + cell.getX() + photoImage.getImageX2(), listView.getY() + cell.getY() + photoImage.getImageY2()); + for (int a = 0; a < photoImage.getRoundRadius().length; a++) { + radii[a * 2] = photoImage.getRoundRadius()[a]; + radii[a * 2 + 1] = photoImage.getRoundRadius()[a]; + } + clipPath.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + canvas.clipPath(clipPath); + boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } + return super.drawChild(canvas, child, drawingTime); + } + }; + addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView = new RecyclerListView(context, resourcesProvider) { + + private final ArrayList drawTimeAfter = new ArrayList<>(); + private final ArrayList drawNamesAfter = new ArrayList<>(); + private final ArrayList drawCaptionAfter = new ArrayList<>(); + private final ArrayList drawingGroups = new ArrayList<>(10); + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + selectorRect.setEmpty(); + drawChatBackgroundElements(canvas); + super.dispatchDraw(canvas); + drawChatForegroundElements(canvas); + canvas.restore(); + } + + private void drawChatForegroundElements(Canvas canvas) { + int size = drawTimeAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell cell = drawTimeAfter.get(a); + canvas.save(); + canvas.translate(cell.getLeft() + cell.getNonAnimationTranslationX(false), cell.getY()); + cell.drawTime(canvas, cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f, true); + canvas.restore(); + } + drawTimeAfter.clear(); + } + size = drawNamesAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell cell = drawNamesAfter.get(a); + float canvasOffsetX = cell.getLeft() + cell.getNonAnimationTranslationX(false); + float canvasOffsetY = cell.getY(); + float alpha = cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f; + + canvas.save(); + canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); + cell.drawNamesLayout(canvas, alpha); + cell.setInvalidatesParent(false); + canvas.restore(); + } + drawNamesAfter.clear(); + } + size = drawCaptionAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell cell = drawCaptionAfter.get(a); + boolean selectionOnly = false; + if (cell.getCurrentPosition() != null) { + selectionOnly = (cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_LEFT) == 0; + } + float alpha = cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f; + float canvasOffsetX = cell.getLeft() + cell.getNonAnimationTranslationX(false); + float canvasOffsetY = cell.getY(); + canvas.save(); + MessageObject.GroupedMessages groupedMessages = cell.getCurrentMessagesGroup(); + if (groupedMessages != null && groupedMessages.transitionParams.backgroundChangeBounds) { + float x = cell.getNonAnimationTranslationX(true); + float l = (groupedMessages.transitionParams.left + x + groupedMessages.transitionParams.offsetLeft); + float t = (groupedMessages.transitionParams.top + groupedMessages.transitionParams.offsetTop); + float r = (groupedMessages.transitionParams.right + x + groupedMessages.transitionParams.offsetRight); + float b = (groupedMessages.transitionParams.bottom + groupedMessages.transitionParams.offsetBottom); + + if (!groupedMessages.transitionParams.backgroundChangeBounds) { + t += cell.getTranslationY(); + b += cell.getTranslationY(); + } + canvas.clipRect( + l + AndroidUtilities.dp(8), t + AndroidUtilities.dp(8), + r - AndroidUtilities.dp(8), b - AndroidUtilities.dp(8) + ); + } + if (cell.getTransitionParams().wasDraw) { + canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); + cell.drawCaptionLayout(canvas, selectionOnly, alpha); + cell.setInvalidatesParent(false); + canvas.restore(); + } + } + drawCaptionAfter.clear(); + } + } + + private void drawChatBackgroundElements(Canvas canvas) { + int count = getChildCount(); + MessageObject.GroupedMessages lastDrawnGroup = null; + + for (int a = 0; a < count; a++) { + View child = getChildAt(a); + if (child.getVisibility() == View.INVISIBLE) { + continue; + } + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + if (group == null || group != lastDrawnGroup) { + lastDrawnGroup = group; + MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); + MessageBackgroundDrawable backgroundDrawable = cell.getBackgroundDrawable(); + if ((backgroundDrawable.isAnimationInProgress() || cell.isDrawingSelectionBackground()) && (position == null || (position.flags & MessageObject.POSITION_FLAG_RIGHT) != 0)) { + int y = (int) cell.getY(); + int height; + canvas.save(); + if (position == null) { + height = cell.getMeasuredHeight(); + } else { + height = y + cell.getMeasuredHeight(); + long time = 0; + float touchX = 0; + float touchY = 0; + for (int i = 0; i < count; i++) { + View inner = getChildAt(i); + if (inner instanceof ChatMessageCell) { + ChatMessageCell innerCell = (ChatMessageCell) inner; + MessageObject.GroupedMessages innerGroup = innerCell.getCurrentMessagesGroup(); + if (innerGroup == group) { + MessageBackgroundDrawable drawable = innerCell.getBackgroundDrawable(); + y = Math.min(y, (int) innerCell.getY()); + height = Math.max(height, (int) innerCell.getY() + innerCell.getMeasuredHeight()); + long touchTime = drawable.getLastTouchTime(); + if (touchTime > time) { + touchX = drawable.getTouchX() + innerCell.getX(); + touchY = drawable.getTouchY() + innerCell.getY(); + time = touchTime; + } + } + } + } + backgroundDrawable.setTouchCoordsOverride(touchX, touchY - y); + height -= y; + } + canvas.clipRect(0, y, getMeasuredWidth(), y + height); + backgroundDrawable.setCustomPaint(null); + backgroundDrawable.setColor(getThemedColor(Theme.key_chat_selectedBackground)); + backgroundDrawable.setBounds(0, y, getMeasuredWidth(), y + height); + backgroundDrawable.draw(canvas); + canvas.restore(); + } + } + } else if (child instanceof ChatActionCell) { + ChatActionCell cell = (ChatActionCell) child; + if (cell.hasGradientService()) { + canvas.save(); + canvas.translate(cell.getX(), cell.getY()); + canvas.scale(cell.getScaleX(), cell.getScaleY(), cell.getMeasuredWidth() / 2f, cell.getMeasuredHeight() / 2f); + cell.drawBackground(canvas, true); + canvas.restore(); + } + } + } + for (int k = 0; k < 3; k++) { + drawingGroups.clear(); + if (k == 2 && !isFastScrollAnimationRunning()) { + continue; + } + for (int i = 0; i < count; i++) { + View child = getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + if (child.getY() > getHeight() || child.getY() + child.getHeight() < 0 || cell.getVisibility() == View.INVISIBLE || cell.getVisibility() == View.GONE) { + continue; + } + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + if (group == null || (k == 0 && group.messages.size() == 1) || (k == 1 && !group.transitionParams.drawBackgroundForDeletedItems)) { + continue; + } + if ((k == 0 && cell.getMessageObject().deleted) || (k == 1 && !cell.getMessageObject().deleted)) { + continue; + } + if ((k == 2 && !cell.willRemovedAfterAnimation()) || (k != 2 && cell.willRemovedAfterAnimation())) { + continue; + } + + if (!drawingGroups.contains(group)) { + group.transitionParams.left = 0; + group.transitionParams.top = 0; + group.transitionParams.right = 0; + group.transitionParams.bottom = 0; + + group.transitionParams.pinnedBotton = false; + group.transitionParams.pinnedTop = false; + group.transitionParams.cell = cell; + drawingGroups.add(group); + } + + group.transitionParams.pinnedTop = cell.isPinnedTop(); + group.transitionParams.pinnedBotton = cell.isPinnedBottom(); + + int left = (cell.getLeft() + cell.getBackgroundDrawableLeft()); + int right = (cell.getLeft() + cell.getBackgroundDrawableRight()); + int top = (cell.getTop() + cell.getBackgroundDrawableTop()); + int bottom = (cell.getTop() + cell.getBackgroundDrawableBottom()); + + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_TOP) == 0) { + top -= AndroidUtilities.dp(10); + } + + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + bottom += AndroidUtilities.dp(10); + } + + if (cell.willRemovedAfterAnimation()) { + group.transitionParams.cell = cell; + } + + if (group.transitionParams.top == 0 || top < group.transitionParams.top) { + group.transitionParams.top = top; + } + if (group.transitionParams.bottom == 0 || bottom > group.transitionParams.bottom) { + group.transitionParams.bottom = bottom; + } + if (group.transitionParams.left == 0 || left < group.transitionParams.left) { + group.transitionParams.left = left; + } + if (group.transitionParams.right == 0 || right > group.transitionParams.right) { + group.transitionParams.right = right; + } + } + } + + for (int i = 0; i < drawingGroups.size(); i++) { + MessageObject.GroupedMessages group = drawingGroups.get(i); + float x = group.transitionParams.cell.getNonAnimationTranslationX(true); + float l = (group.transitionParams.left + x + group.transitionParams.offsetLeft); + float t = (group.transitionParams.top + group.transitionParams.offsetTop); + float r = (group.transitionParams.right + x + group.transitionParams.offsetRight); + float b = (group.transitionParams.bottom + group.transitionParams.offsetBottom); + + if (!group.transitionParams.backgroundChangeBounds) { + t += group.transitionParams.cell.getTranslationY(); + b += group.transitionParams.cell.getTranslationY(); + } + + boolean useScale = group.transitionParams.cell.getScaleX() != 1f || group.transitionParams.cell.getScaleY() != 1f; + if (useScale) { + canvas.save(); + canvas.scale(group.transitionParams.cell.getScaleX(), group.transitionParams.cell.getScaleY(), l + (r - l) / 2, t + (b - t) / 2); + } + boolean selected = false; + group.transitionParams.cell.drawBackground(canvas, (int) l, (int) t, (int) r, (int) b, group.transitionParams.pinnedTop, group.transitionParams.pinnedBotton, selected, 0); + group.transitionParams.cell = null; + group.transitionParams.drawCaptionLayout = group.hasCaption; + if (useScale) { + canvas.restore(); + for (int ii = 0; ii < count; ii++) { + View child = getChildAt(ii); + if (child instanceof ChatMessageCell && ((ChatMessageCell) child).getCurrentMessagesGroup() == group) { + ChatMessageCell cell = ((ChatMessageCell) child); + int left = cell.getLeft(); + int top = cell.getTop(); + child.setPivotX(l - left + (r - l) / 2); + child.setPivotY(t - top + (b - t) / 2); + } + } + } + } + } + } + + @Override + public boolean drawChild(Canvas canvas, View child, long drawingTime) { + ChatMessageCell cell = null; + ChatActionCell actionCell = null; + + if (child instanceof ChatMessageCell) { + cell = (ChatMessageCell) child; + } else if (child instanceof ChatActionCell) { + actionCell = (ChatActionCell) child; + } + + boolean result = super.drawChild(canvas, child, drawingTime); + if (cell != null && cell.hasOutboundsContent()) { + canvas.save(); + canvas.translate(cell.getX(), cell.getY()); + cell.drawOutboundsContent(canvas); + canvas.restore(); + } else if (actionCell != null) { + canvas.save(); + canvas.translate(actionCell.getX(), actionCell.getY()); + actionCell.drawOutboundsContent(canvas); + canvas.restore(); + } + + if (child.getTranslationY() != 0) { + canvas.save(); + canvas.translate(0, child.getTranslationY()); + } + + if (cell != null) { + cell.drawCheckBox(canvas); + } + + if (child.getTranslationY() != 0) { + canvas.restore(); + } + + if (child.getTranslationY() != 0) { + canvas.save(); + canvas.translate(0, child.getTranslationY()); + } + + if (cell != null) { + MessageObject message = cell.getMessageObject(); + MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); + if (position != null || cell.getTransitionParams().animateBackgroundBoundsInner) { + if (position == null || (position.last || position.minX == 0 && position.minY == 0)) { + if (position == null || position.last) { + drawTimeAfter.add(cell); + } + if ((position == null || (position.minX == 0 && position.minY == 0)) && cell.hasNameLayout()) { + drawNamesAfter.add(cell); + } + } + if (position != null || cell.getTransitionParams().transformGroupToSingleMessage || cell.getTransitionParams().animateBackgroundBoundsInner) { + if (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + drawCaptionAfter.add(cell); + } + } + } + ImageReceiver imageReceiver = cell.getAvatarImage(); + if (imageReceiver != null) { + boolean replaceAnimation = isFastScrollAnimationRunning() || (groupedMessages != null && groupedMessages.transitionParams.backgroundChangeBounds); + int top = replaceAnimation ? child.getTop() : (int) child.getY(); + if (cell.drawPinnedBottom()) { + int p; + ViewHolder holder = listView.getChildViewHolder(child); + p = holder.getAdapterPosition(); + + if (p >= 0) { + int nextPosition; + if (groupedMessages != null && position != null) { + int idx = groupedMessages.posArray.indexOf(position); + int size = groupedMessages.posArray.size(); + if ((position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + nextPosition = p - size + idx; + } else { + nextPosition = p - 1; + for (int a = idx + 1; a < size; a++) { + if (groupedMessages.posArray.get(a).minY > position.maxY) { + break; + } else { + nextPosition--; + } + } + } + } else { + nextPosition = p - 1; + } + holder = findViewHolderForAdapterPosition(nextPosition); + if (holder != null) { + if (child.getTranslationY() != 0) { + canvas.restore(); + } + imageReceiver.setVisible(false, false); + return result; + } + } + } + float tx = cell.getSlidingOffsetX() + cell.getCheckBoxTranslation(); + int y = (int) ((replaceAnimation ? child.getTop() : child.getY()) + cell.getLayoutHeight() + cell.getTransitionParams().deltaBottom); + int maxY = getMeasuredHeight() - getPaddingBottom(); + boolean canUpdateTx = cell.isCheckBoxVisible() && tx == 0; + if (cell.isPlayingRound() || cell.getTransitionParams().animatePlayingRound) { + if (cell.getTransitionParams().animatePlayingRound) { + float progressLocal = cell.getTransitionParams().animateChangeProgress; + if (!cell.isPlayingRound()) { + progressLocal = 1f - progressLocal; + } + int fromY = y; + int toY = Math.min(y, maxY); + y = (int) (fromY * progressLocal + toY * (1f - progressLocal)); + } + } else { + if (y > maxY) { + y = maxY; + } + } + + if (!replaceAnimation && child.getTranslationY() != 0) { + canvas.restore(); + } + if (cell.drawPinnedTop()) { + int p; + ViewHolder holder = getChildViewHolder(child); + p = holder.getAdapterPosition(); + if (p >= 0) { + int tries = 0; + while (true) { + if (tries >= 20) { + break; + } + tries++; + + int prevPosition; + if (groupedMessages != null && position != null) { + int idx = groupedMessages.posArray.indexOf(position); + if (idx < 0) { + break; + } + int size = groupedMessages.posArray.size(); + if ((position.flags & MessageObject.POSITION_FLAG_TOP) != 0) { + prevPosition = p + idx + 1; + } else { + prevPosition = p + 1; + for (int a = idx - 1; a >= 0; a--) { + if (groupedMessages.posArray.get(a).maxY < position.minY) { + break; + } else { + prevPosition++; + } + } + } + } else { + prevPosition = p + 1; + } + holder = findViewHolderForAdapterPosition(prevPosition); + if (holder != null) { + top = holder.itemView.getTop(); + if (holder.itemView instanceof ChatMessageCell) { + cell = (ChatMessageCell) holder.itemView; + float newTx = cell.getSlidingOffsetX() + cell.getCheckBoxTranslation(); + if (canUpdateTx && newTx > 0) { + tx = newTx; + } + if (!cell.drawPinnedTop()) { + break; + } else { + p = prevPosition; + } + } else { + break; + } + } else { + break; + } + } + } + } + if (y - AndroidUtilities.dp(42) < top) { + y = top + AndroidUtilities.dp(42); + } + if (!cell.drawPinnedBottom()) { + int cellBottom = replaceAnimation ? cell.getBottom() : (int) (cell.getY() + cell.getMeasuredHeight() + cell.getTransitionParams().deltaBottom); + if (y > cellBottom) { + y = cellBottom; + } + } + canvas.save(); + if (tx != 0) { + canvas.translate(tx, 0); + } + if (cell.getCurrentMessagesGroup() != null) { + if (cell.getCurrentMessagesGroup().transitionParams.backgroundChangeBounds) { + y -= cell.getTranslationY(); + } + } + imageReceiver.setImageY(y - AndroidUtilities.dp(40)); + if (cell.shouldDrawAlphaLayer()) { + imageReceiver.setAlpha(cell.getAlpha()); + canvas.scale( + cell.getScaleX(), cell.getScaleY(), + cell.getX() + cell.getPivotX(), cell.getY() + (cell.getHeight() >> 1) + ); + } else { + imageReceiver.setAlpha(1f); + } + imageReceiver.setVisible(true, false); + imageReceiver.draw(canvas); + canvas.restore(); + + if (!replaceAnimation && child.getTranslationY() != 0) { + canvas.save(); + } + } + } + + if (child.getTranslationY() != 0) { + canvas.restore(); + } + return result; + } + }; + listView.setAdapter(new RecyclerListView.SelectionAdapter() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + ChatMessageCell cell = new ChatMessageCell(context, false, null, resourcesProvider) { + public BlurringShader.StoryBlurDrawer blurDrawer = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_ACTION_BACKGROUND); + + @Override + protected void onDraw(Canvas canvas) { + if (videoTextureHolder != null && videoTextureHolder.active && videoTextureHolder.textureViewActive || clipVideoMessageForBitmap) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + } else { + canvas.save(); + } + super.onDraw(canvas); + canvas.restore(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return false; + } + + @Override + public Paint getThemedPaint(String paintKey) { + if (Theme.key_paint_chatActionBackground.equals(paintKey)) { + usesBackgroundPaint = true; + Paint paint = blurDrawer.getPaint(1f); + if (paint != null) { + return paint; + } + } + return super.getThemedPaint(paintKey); + } + + private final float[] radii = new float[8]; + private final Path clipPath = new Path(); + private final Paint clearPaint = new Paint(); + { clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } + private final android.graphics.Rect src = new android.graphics.Rect(); + private final android.graphics.RectF dst = new android.graphics.RectF(); + + @Override + protected boolean drawPhotoImage(Canvas canvas) { + ImageReceiver photoImage = getPhotoImage(); + if (isRepostVideoPreview && photoImage != null && (videoTextureHolder != null && videoTextureHolder.active && videoTextureHolder.textureViewActive && textureViewActive || clipVideoMessageForBitmap || textureView != null && drawForBitmap())) { + for (int a = 0; a < photoImage.getRoundRadius().length; a++) { + radii[a * 2] = photoImage.getRoundRadius()[a]; + radii[a * 2 + 1] = photoImage.getRoundRadius()[a]; + } + AndroidUtilities.rectTmp.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); + clipPath.rewind(); + clipPath.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + if (textureView != null && drawForBitmap()) { + Bitmap bitmap = textureView.getBitmap(); + if (bitmap != null) { + canvas.save(); + canvas.clipPath(clipPath); + canvas.translate(-getX(), -getY()); + float scale = Math.max(photoImage.getImageWidth() / videoWidth, photoImage.getImageHeight() / videoHeight); + canvas.translate(photoImage.getCenterX() - videoWidth * scale / 2f, photoImage.getCenterY() - videoHeight * scale / 2f); + canvas.scale((float) videoWidth / textureView.getWidth() * scale, (float) videoHeight / textureView.getHeight() * scale); + src.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); + dst.set(0, 0, textureView.getWidth(), textureView.getHeight()); + canvas.drawBitmap(bitmap, src, dst, null); + canvas.restore(); + } else { + return super.drawPhotoImage(canvas); + } + } else { + canvas.drawPath(clipPath, clearPaint); + } + return true; + } + return super.drawPhotoImage(canvas); + } + }; + cell.isChat = true; + return new RecyclerListView.Holder(cell); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + position = messageObjects.size() - 1 - position; + MessageObject message = messageObjects.get(position); + boolean pinnedTop = false; + if (groupedMessages != null) { + MessageObject.GroupedMessagePosition p = groupedMessages.positions.get(message); + if (p != null) { + pinnedTop = p.minY != 0; + } + } + ((ChatMessageCell) holder.itemView).setMessageObject(message, groupedMessages, groupedMessages != null, pinnedTop); + } + + @Override + public int getItemCount() { + return messageObjects.size(); + } + }); + GridLayoutManagerFixed layoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, true) { + + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + + @Override + public boolean shouldLayoutChildFromOpositeSide(View child) { + if (child instanceof ChatMessageCell) { + return !((ChatMessageCell) child).getMessageObject().isOutOwner(); + } + return false; + } + + @Override + protected boolean hasSiblingChild(int position) { + position = messageObjects.size() - 1 - position; + if (groupedMessages != null && position >= 0 && position < messageObjects.size()) { + MessageObject message = messageObjects.get(position); + MessageObject.GroupedMessagePosition pos = groupedMessages.positions.get(message); + if (pos == null || pos.minX == pos.maxX || pos.minY != pos.maxY || pos.minY == 0) { + return false; + } + int count = groupedMessages.posArray.size(); + for (int a = 0; a < count; a++) { + MessageObject.GroupedMessagePosition p = groupedMessages.posArray.get(a); + if (p == pos) { + continue; + } + if (p.minY <= pos.minY && p.maxY >= pos.minY) { + return true; + } + } + } + return false; + } + }; + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + position = messageObjects.size() - 1 - position; + if (groupedMessages != null && position >= 0 && position < groupedMessages.messages.size()) { + MessageObject message = groupedMessages.messages.get(position); + MessageObject.GroupedMessagePosition groupedPosition = groupedMessages.positions.get(message); + if (groupedPosition != null) { + return groupedPosition.spanSize; + } + } + return 1000; + } + }); + listView.setLayoutManager(layoutManager); + listView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.bottom = 0; + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + if (group != null) { + MessageObject.GroupedMessagePosition position = cell.getCurrentPosition(); + if (position != null && position.siblingHeights != null) { + float maxHeight = Math.max(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f; + int h = cell.getExtraInsetHeight(); + for (int a = 0; a < position.siblingHeights.length; a++) { + h += (int) Math.ceil(maxHeight * position.siblingHeights[a]); + } + h += (position.maxY - position.minY) * Math.round(7 * AndroidUtilities.density); + int count = group.posArray.size(); + for (int a = 0; a < count; a++) { + MessageObject.GroupedMessagePosition pos = group.posArray.get(a); + if (pos.minY != position.minY || pos.minX == position.minX && pos.maxX == position.maxX && pos.minY == position.minY && pos.maxY == position.maxY) { + continue; + } + if (pos.minY == position.minY) { + h -= (int) Math.ceil(maxHeight * pos.ph) - AndroidUtilities.dp(4); + break; + } + } + outRect.bottom = -h; + } + } + } + } + }); + container.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + if (videoTextureHolder != null && videoTextureHolder.active) { + videoTextureHolder.takeTextureView(textureView -> { + this.textureView = textureView; + if (textureView != null) { + container.addView(textureView, 0); + } + }, (w, h) -> { + videoWidth = w; + videoHeight = h; + AndroidUtilities.runOnUIThread(() -> { + textureViewActive = true; + invalidateAll(); + }, 60); + }); + } + updatePosition(); + } + + private ChatMessageCell getCell() { + if (listView == null) return null; + for (int i = 0; i < listView.getChildCount(); ++i) { + if (listView.getChildAt(i) instanceof ChatMessageCell) { + return (ChatMessageCell) listView.getChildAt(i); + } + } + return null; + } + + public void getBubbleBounds(RectF rect) { + float left = Integer.MAX_VALUE; + float right = Integer.MIN_VALUE; + float top = Integer.MAX_VALUE; + float bottom = Integer.MIN_VALUE; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + float cleft, ctop, cright, cbottom; + if (cell.getMessageObject() != null && cell.getMessageObject().isRoundVideo() && cell.getPhotoImage() != null) { + cleft = container.getX() + cell.getX() + cell.getPhotoImage().getImageX(); + cright = container.getX() + cell.getX() + cell.getPhotoImage().getImageX2(); + ctop = container.getY() + cell.getY() + cell.getPhotoImage().getImageY(); + cbottom = container.getY() + cell.getY() + cell.getPhotoImage().getImageY2(); + } else { + cleft = container.getX() + child.getX() + cell.getBackgroundDrawableLeft() + dp(1); + if (groupedMessages == null) { // pinned bottom + cleft += dp(8); + } + cright = container.getX() + child.getX() + cell.getBackgroundDrawableRight() - dp(1); + ctop = container.getY() + child.getY() + cell.getBackgroundDrawableTop() + dp(1.33f); + cbottom = container.getY() + child.getY() + cell.getBackgroundDrawableBottom() - dp(.66f); + } + left = Math.min(left, cleft); + left = Math.min(left, cright); + right = Math.max(right, cleft); + right = Math.max(right, cright); + top = Math.min(top, ctop); + top = Math.min(top, cbottom); + bottom = Math.max(bottom, ctop); + bottom = Math.max(bottom, cbottom); + } + } + rect.set(left, top, right, bottom); + } + + public void invalidateAll() { +// dateCell.invalidate(); + listView.invalidate(); + for (int i = 0; i < listView.getChildCount(); ++i) { + listView.getChildAt(i).invalidate(); + } + } + + public void prepareToDraw(boolean drawingToBitmap) { + clipVideoMessageForBitmap = drawingToBitmap; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ((ChatMessageCell) child).drawingToBitmap = drawingToBitmap; + } + } + } + + protected void updatePosition() { + float halfWidth = getMeasuredWidth() / 2.0f; + float halfHeight = getMeasuredHeight() / 2.0f; + setX(getPositionX() - halfWidth); + setY(getPositionY() - halfHeight); + updateSelectionView(); + if (usesBackgroundPaint) { + invalidateAll(); + } + } + + public boolean firstMeasure = true; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { +// dateCell.measure(container.getMeasuredWidth() > 0 ? MeasureSpec.makeMeasureSpec(container.getMeasuredWidth(), MeasureSpec.EXACTLY) : widthMeasureSpec, heightMeasureSpec); +// container.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - dateCell.getMeasuredHeight(), MeasureSpec.getMode(heightMeasureSpec))); +// dateCell.measure(container.getMeasuredWidth() > 0 ? MeasureSpec.makeMeasureSpec(container.getMeasuredWidth(), MeasureSpec.EXACTLY) : widthMeasureSpec, heightMeasureSpec); + container.measure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(container.getMeasuredWidth(), container.getMeasuredHeight()); + updatePosition(); + if (firstMeasure) { + int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - dp(22 * 2); + int maxHeight = MeasureSpec.getSize(heightMeasureSpec) - dp(96 * 2); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + + float scale = Math.min((float) maxWidth / width, (float) maxHeight / height); + if (scale < 1) { + setScale(scale); + } + Point p = getPosition(); + p.x -= dp(19) * Math.min(1, scale); + setPosition(p); + + firstMeasure = false; + } + } + + @Override + public Rect getSelectionBounds() { + ViewGroup parentView = (ViewGroup) getParent(); + if (parentView == null) { + return new Rect(); + } + float scale = parentView.getScaleX(); + return new Rect( + getPositionX() * scale - getMeasuredWidth() * getScale() / 2.0f * scale - dp(1.0f + 19.5f + 15), + getPositionY() * scale - getMeasuredHeight() * getScale() / 2.0f * scale - dp(1.0f + 19.5f + 15), + (getMeasuredWidth() * getScale()) * scale + dp((1.0f + 19.5f + 15) * 2), + (getMeasuredHeight() * getScale()) * scale + dp((1.0f + 19.5f + 15) * 2) + ); + } + + @Override + protected float getBounceScale() { + return 0.02f; + } + + @Override + protected SelectionView createSelectionView() { + return new MessageEntityViewSelectionView(getContext()); + } + + public class MessageEntityViewSelectionView extends SelectionView { + + private final Paint clearPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public MessageEntityViewSelectionView(Context context) { + super(context); + clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + @Override + protected int pointInsideHandle(float x, float y) { + float thickness = dp(1.0f); + float radius = dp(19.5f); + + float inset = radius + thickness; + float width = getMeasuredWidth() - inset * 2; + float height = getMeasuredHeight() - inset * 2; + + float middle = inset + height / 2.0f; + + if (x > inset - radius && y > middle - radius && x < inset + radius && y < middle + radius) { + return SELECTION_LEFT_HANDLE; + } else if (x > inset + width - radius && y > middle - radius && x < inset + width + radius && y < middle + radius) { + return SELECTION_RIGHT_HANDLE; + } + + if (x > inset && x < width && y > inset && y < height) { + return SELECTION_WHOLE_HANDLE; + } + + return 0; + } + + private Path path = new Path(); + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + + float thickness = dp(2.0f); + float radius = AndroidUtilities.dpf2(5.66f); + + float inset = radius + thickness + dp(15); + + float width = getMeasuredWidth() - inset * 2; + float height = getMeasuredHeight() - inset * 2; + + AndroidUtilities.rectTmp.set(inset, inset, inset + width, inset + height); + + float R = dp(12); + float rx = Math.min(R, width / 2f), ry = Math.min(R, height / 2f); + + path.rewind(); + AndroidUtilities.rectTmp.set(inset, inset, inset + rx * 2, inset + ry * 2); + path.arcTo(AndroidUtilities.rectTmp, 180, 90); + AndroidUtilities.rectTmp.set(inset + width - rx * 2, inset, inset + width, inset + ry * 2); + path.arcTo(AndroidUtilities.rectTmp, 270, 90); + canvas.drawPath(path, paint); + + path.rewind(); + AndroidUtilities.rectTmp.set(inset, inset + height - ry * 2, inset + rx * 2, inset + height); + path.arcTo(AndroidUtilities.rectTmp, 180, -90); + AndroidUtilities.rectTmp.set(inset + width - rx * 2, inset + height - ry * 2, inset + width, inset + height); + path.arcTo(AndroidUtilities.rectTmp, 90, -90); + canvas.drawPath(path, paint); + + canvas.drawCircle(inset, inset + height / 2.0f, radius, dotStrokePaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius - dp(1) + 1, dotPaint); + + canvas.drawCircle(inset + width, inset + height / 2.0f, radius, dotStrokePaint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius - dp(1) + 1, dotPaint); + + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + canvas.drawLine(inset, inset + ry, inset, inset + height - ry, paint); + canvas.drawLine(inset + width, inset + ry, inset + width, inset + height - ry, paint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius + dp(1) - 1, clearPaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius + dp(1) - 1, clearPaint); + + canvas.restoreToCount(count); + } + } + + private boolean isDark = Theme.isCurrentThemeDark(); + private final SparseIntArray currentColors = new SparseIntArray(); + public final Theme.ResourcesProvider resourcesProvider = new Theme.ResourcesProvider() { + public final TextPaint chat_actionTextPaint = new TextPaint(); + public final TextPaint chat_actionTextPaint2 = new TextPaint(); + public final TextPaint chat_botButtonPaint = new TextPaint(); + + public final Paint chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + { + chat_actionTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_actionTextPaint2.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_botButtonPaint.setTextSize(AndroidUtilities.dp(15)); + chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); + } + + @Override + public int getColor(int key) { + return currentColors.get(key, Theme.getColor(key)); + } + + @Override + public Paint getPaint(String paintKey) { + switch (paintKey) { + case Theme.key_paint_chatActionBackgroundSelected: return chat_actionBackgroundSelectedPaint; + case Theme.key_paint_chatActionBackgroundDarken: return chat_actionBackgroundGradientDarkenPaint; + case Theme.key_paint_chatActionText: return chat_actionTextPaint; + case Theme.key_paint_chatActionText2: return chat_actionTextPaint2; + case Theme.key_paint_chatBotButton: return chat_botButtonPaint; + } + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (drawableKey.equals(Theme.key_drawable_msgIn)) { + if (msgInDrawable == null) { + msgInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, false, resourcesProvider); + } + return msgInDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgInSelected)) { + if (msgInDrawableSelected == null) { + msgInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, true, resourcesProvider); + } + return msgInDrawableSelected; + } + if (drawableKey.equals(Theme.key_drawable_msgOut)) { + if (msgOutDrawable == null) { + msgOutDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, true, false, resourcesProvider); + } + return msgOutDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgOutSelected)) { + if (msgOutDrawableSelected == null) { + msgOutDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, true, true, resourcesProvider); + } + return msgOutDrawableSelected; + } + + if (drawableKey.equals(Theme.key_drawable_msgInMedia)) { + if (msgMediaInDrawable == null) { + msgMediaInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_MEDIA, false, false, resourcesProvider); + } + msgMediaInDrawable.invalidateSelf(); + return msgMediaInDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgInMediaSelected)) { + if (msgMediaInDrawableSelected == null) { + msgMediaInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_MEDIA, false, true, resourcesProvider); + } + return msgMediaInDrawableSelected; + } + if (drawableKey.equals(Theme.key_drawable_msgOutMedia)) { + if (msgMediaOutDrawable == null) { + msgMediaOutDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_MEDIA, true, false, resourcesProvider); + } + return msgMediaOutDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgOutMediaSelected)) { + if (msgMediaOutDrawableSelected == null) { + msgMediaOutDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_MEDIA, true, true, resourcesProvider); + } + return msgMediaOutDrawableSelected; + } + + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public boolean isDark() { + return isDark; + } + }; + private Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; + private Theme.MessageDrawable msgOutDrawable, msgOutDrawableSelected; + private Theme.MessageDrawable msgMediaInDrawable, msgMediaInDrawableSelected; + private Theme.MessageDrawable msgMediaOutDrawable, msgMediaOutDrawableSelected; + + public void setupTheme(StoryEntry entry) { + if (entry == null) { + currentColors.clear(); + return; + } + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("themeconfig", Activity.MODE_PRIVATE); + String dayThemeName = preferences.getString("lastDayTheme", "Blue"); + if (Theme.getTheme(dayThemeName) == null || Theme.getTheme(dayThemeName).isDark()) { + dayThemeName = "Blue"; + } + String nightThemeName = preferences.getString("lastDarkTheme", "Dark Blue"); + if (Theme.getTheme(nightThemeName) == null || !Theme.getTheme(nightThemeName).isDark()) { + nightThemeName = "Dark Blue"; + } + Theme.ThemeInfo themeInfo = Theme.getActiveTheme(); + if (dayThemeName.equals(nightThemeName)) { + if (themeInfo.isDark() || dayThemeName.equals("Dark Blue") || dayThemeName.equals("Night")) { + dayThemeName = "Blue"; + } else { + nightThemeName = "Dark Blue"; + } + } + if (this.isDark = entry.isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } + final String[] wallpaperLink = new String[1]; + final SparseIntArray themeColors; + if (themeInfo.assetName != null) { + themeColors = Theme.getThemeFileValues(null, themeInfo.assetName, wallpaperLink); + } else { + themeColors = Theme.getThemeFileValues(new File(themeInfo.pathToFile), null, wallpaperLink); + } + currentColors.clear(); + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); + } + } + if (themeColors != null) { + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } + Theme.ThemeAccent accent = themeInfo.getAccent(false); + if (accent != null) { + accent.fillAccentColors(themeColors, currentColors); + } + } + + invalidateAll(); + } + + public TLRPC.TL_message copyMessage(TLRPC.Message msg) { + TLRPC.TL_message newmsg = new TLRPC.TL_message(); + newmsg.id = msg.id; + newmsg.from_id = msg.from_id; + newmsg.peer_id = msg.peer_id; + newmsg.date = msg.date; + newmsg.expire_date = msg.expire_date; + newmsg.action = msg.action; + newmsg.message = msg.message; + newmsg.media = msg.media; + newmsg.flags = msg.flags; + newmsg.mentioned = msg.mentioned; + newmsg.media_unread = msg.media_unread; + newmsg.out = msg.out; + newmsg.unread = msg.unread; + newmsg.entities = msg.entities; + newmsg.via_bot_name = msg.via_bot_name; + newmsg.reply_markup = msg.reply_markup; + newmsg.views = msg.views; + newmsg.forwards = msg.forwards; + newmsg.replies = msg.replies; + newmsg.edit_date = msg.edit_date; + newmsg.silent = msg.silent; + newmsg.post = msg.post; + newmsg.from_scheduled = msg.from_scheduled; + newmsg.legacy = msg.legacy; + newmsg.edit_hide = msg.edit_hide; + newmsg.pinned = msg.pinned; + newmsg.fwd_from = msg.fwd_from; + newmsg.via_bot_id = msg.via_bot_id; + newmsg.reply_to = msg.reply_to; + newmsg.post_author = msg.post_author; + newmsg.grouped_id = msg.grouped_id; + newmsg.reactions = msg.reactions; + newmsg.restriction_reason = msg.restriction_reason; + newmsg.ttl_period = msg.ttl_period; + newmsg.noforwards = msg.noforwards; + newmsg.invert_media = msg.invert_media; + newmsg.send_state = msg.send_state; + newmsg.fwd_msg_id = msg.fwd_msg_id; + newmsg.attachPath = msg.attachPath; + newmsg.params = msg.params; + newmsg.random_id = msg.random_id; + newmsg.local_id = msg.local_id; + newmsg.dialog_id = msg.dialog_id; + newmsg.ttl = msg.ttl; + newmsg.destroyTime = msg.destroyTime; + newmsg.destroyTimeMillis = msg.destroyTimeMillis; + newmsg.layer = msg.layer; + newmsg.seq_in = msg.seq_in; + newmsg.seq_out = msg.seq_out; + newmsg.with_my_score = msg.with_my_score; + newmsg.replyMessage = msg.replyMessage; + newmsg.reqId = msg.reqId; + newmsg.realId = msg.realId; + newmsg.stickerVerified = msg.stickerVerified; + newmsg.isThreadMessage = msg.isThreadMessage; + newmsg.voiceTranscription = msg.voiceTranscription; + newmsg.voiceTranscriptionOpen = msg.voiceTranscriptionOpen; + newmsg.voiceTranscriptionRated = msg.voiceTranscriptionRated; + newmsg.voiceTranscriptionFinal = msg.voiceTranscriptionFinal; + newmsg.voiceTranscriptionForce = msg.voiceTranscriptionForce; + newmsg.voiceTranscriptionId = msg.voiceTranscriptionId; + newmsg.premiumEffectWasPlayed = msg.premiumEffectWasPlayed; + newmsg.originalLanguage = msg.originalLanguage; + newmsg.translatedToLanguage = msg.translatedToLanguage; + newmsg.translatedText = msg.translatedText; + newmsg.replyStory = msg.replyStory; + return newmsg; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java index f096b18d4..220a68534 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java @@ -1,16 +1,36 @@ package org.telegram.ui.Components.Paint.Views; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; import android.view.ViewGroup; import android.widget.FrameLayout; +import com.google.mlkit.common.MlKitException; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.segmentation.subject.SubjectSegmentation; +import com.google.mlkit.vision.segmentation.subject.SubjectSegmenter; +import com.google.mlkit.vision.segmentation.subject.SubjectSegmenterOptions; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; @@ -26,6 +46,11 @@ import org.telegram.ui.Components.Point; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.Rect; import org.telegram.ui.Components.Size; +import org.telegram.ui.Stories.recorder.StoryEntry; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; public class PhotoView extends EntityView { @@ -47,9 +72,42 @@ public class PhotoView extends EntityView { private boolean mirrored = false; private final AnimatedFloat mirrorT; private Size baseSize; + private boolean overridenSegmented = false; - private FrameLayoutDrawer containerView; - public final ImageReceiver centerImage = new ImageReceiver(); + private int orientation, invert; + + private boolean segmented = false; + private AnimatedFloat segmentedT; + + private final FrameLayoutDrawer containerView; + public final ImageReceiver centerImage = new ImageReceiver() { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (type == TYPE_IMAGE && drawable instanceof BitmapDrawable) { + segmentImage(((BitmapDrawable) drawable).getBitmap()); + } + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + + private File segmentedFile; + public void preloadSegmented(String path) { + if (TextUtils.isEmpty(path)) return; + segmentingLoading = true; + final int side = Math.round(Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f / AndroidUtilities.density); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, opts); + opts.inSampleSize = StoryEntry.calculateInSampleSize(opts, side, side); + opts.inJustDecodeBounds = false; + opts.inDither = true; + segmentedImage = BitmapFactory.decodeFile(path, opts); + if (segmentedImage != null) { + segmentedFile = new File(path); + segmentingLoaded = true; + } + segmentingLoading = false; + } public PhotoView(Context context, Point position, float angle, float scale, Size baseSize, String path, int orientation, int invert) { super(context, position); @@ -63,14 +121,16 @@ public class PhotoView extends EntityView { addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); mirrorT = new AnimatedFloat(containerView, 0, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + segmentedT = new AnimatedFloat(containerView, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + this.orientation = orientation; + this.invert = invert; centerImage.setAspectFit(true); centerImage.setInvalidateAll(true); centerImage.setParentView(containerView); - centerImage.setRoundRadius(AndroidUtilities.dp(12)); + centerImage.setRoundRadius(dp(12)); centerImage.setOrientation(orientation, invert, true); - final int side = Math.round(Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f / AndroidUtilities.density); - centerImage.setImage(ImageLocation.getForPath(path), side + "_" + side, null, null, null, 1); + centerImage.setImage(ImageLocation.getForPath(path), getImageFilter(), null, null, null, 1); updatePosition(); } @@ -86,21 +146,135 @@ public class PhotoView extends EntityView { addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); mirrorT = new AnimatedFloat(containerView, 0, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + segmentedT = new AnimatedFloat(containerView, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); centerImage.setAspectFit(true); centerImage.setInvalidateAll(true); centerImage.setParentView(containerView); - centerImage.setRoundRadius(AndroidUtilities.dp(12)); - final int side = Math.round(Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f / AndroidUtilities.density); + centerImage.setRoundRadius(dp(12)); + if (object instanceof TLRPC.Photo) { TLRPC.Photo photo = (TLRPC.Photo) object; TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 1000); TLRPC.PhotoSize thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 90); - centerImage.setImage(ImageLocation.getForPhoto(photoSize, photo), side + "_" + side, ImageLocation.getForPhoto(thumbPhotoSize, photo), side + "_" + side, (String) null, null, 1); + centerImage.setImage(ImageLocation.getForPhoto(photoSize, photo), getImageFilter(), ImageLocation.getForPhoto(thumbPhotoSize, photo), getImageFilter(), (String) null, null, 1); } updatePosition(); } + private String getImageFilter() { + final int side = Math.round(Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f / AndroidUtilities.density); + return side + "_" + side; + } + + private boolean segmentingLoading, segmentingLoaded; + public Bitmap segmentedImage; + public void segmentImage(Bitmap source) { + if (segmentingLoaded || segmentingLoading || source == null) return; + if (Build.VERSION.SDK_INT < 24) return; + SubjectSegmenter segmenter = SubjectSegmentation.getClient(new SubjectSegmenterOptions.Builder().enableForegroundBitmap().build()); + segmentingLoading = true; + InputImage inputImage = InputImage.fromBitmap(source, orientation); + segmenter.process(inputImage) + .addOnSuccessListener(result -> { + segmentingLoaded = true; + segmentingLoading = false; + segmentedImage = result.getForegroundBitmap(); + highlightSegmented(); + }) + .addOnFailureListener(error -> { + segmentingLoading = false; + FileLog.e(error); + if (isWaitingMlKitError(error) && isAttachedToWindow()) { + AndroidUtilities.runOnUIThread(() -> segmentImage(source), 2000); + } else { + segmentingLoaded = true; + } + }); + } + + public boolean hasSegmentedImage() { + return segmentedImage != null; + } + + public static boolean isWaitingMlKitError(Exception e) { + if (Build.VERSION.SDK_INT < 24) return false; + return e instanceof MlKitException && e.getMessage() != null && e.getMessage().contains("segmentation optional module to be downloaded"); + } + + public File saveSegmentedImage(int currentAccount) { + if (segmentedImage == null) { + return null; + } + if (segmentedFile == null) { + segmentedFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + try { + segmentedImage.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(segmentedFile)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + return segmentedFile; + } + + public void deleteSegmentedFile() { + if (segmentedFile != null) { + try { + segmentedFile.delete(); + } catch (Exception e) {} + segmentedFile = null; + } + } + + public void onSwitchSegmentedAnimationStarted(boolean thanos) { + overridenSegmented = true; + if (containerView != null) { + containerView.invalidate(); + } + } + + public Bitmap getSegmentedOutBitmap() { + if (!(centerImage.getImageDrawable() instanceof BitmapDrawable)) + return null; + + Bitmap source = ((BitmapDrawable) centerImage.getImageDrawable()).getBitmap(); + Bitmap mask = segmentedImage; + + if (source == null || mask == null) + return null; + + int w = source.getWidth(), h = source.getHeight(); + if (orientation == 90 || orientation == 270 || orientation == -90 || orientation == -270) { + w = source.getHeight(); + h = source.getWidth(); + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + roundRectPath.rewind(); + AndroidUtilities.rectTmp.set(0, 0, w, h); + float mirrorT = this.mirrorT.get(); + canvas.scale(1 - mirrorT * 2, 1f, w / 2f, 0); + canvas.skew(0, 4 * mirrorT * (1f - mirrorT) * .25f); + roundRectPath.addRoundRect(AndroidUtilities.rectTmp, dp(12) * getScaleX(), dp(12) * getScaleY(), Path.Direction.CW); + canvas.clipPath(roundRectPath); + canvas.translate(w / 2f, h / 2f); + canvas.rotate(orientation); + canvas.translate(-source.getWidth() / 2f, -source.getHeight() / 2f); + + AndroidUtilities.rectTmp.set(0, 0, source.getWidth(), source.getHeight()); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, 0xFF, Canvas.ALL_SAVE_FLAG); + canvas.drawBitmap(source, 0, 0, null); + Paint clearPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + canvas.save(); + canvas.drawBitmap(mask, 0, 0, clearPaint); + canvas.restore(); + canvas.restore(); + + return bitmap; + } + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -126,13 +300,32 @@ public class PhotoView extends EntityView { if (!animated) { mirrorT.set(mirrored, true); } - containerView.invalidate(); + if (containerView != null) { + containerView.invalidate(); + } } public boolean isMirrored() { return mirrored; } + public boolean isSegmented() { + return segmented; + } + + public void toggleSegmented(boolean animated) { + segmented = !segmented; + if (animated && segmented) { + overridenSegmented = false; + } + if (!animated) { + segmentedT.set(segmented, true); + } + if (containerView != null) { + containerView.invalidate(); + } + } + protected void updatePosition() { float halfWidth = baseSize.width / 2.0f; float halfHeight = baseSize.height / 2.0f; @@ -141,6 +334,17 @@ public class PhotoView extends EntityView { updateSelectionView(); } + private final android.graphics.Rect src = new android.graphics.Rect(); + private final android.graphics.RectF dest = new android.graphics.RectF(); + + private final Paint segmentPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + + private long highlightStart = -1; + private LinearGradient highlightGradient; + private Matrix highlightGradientMatrix; + private Paint highlightPaint; + private boolean needHighlight; + protected void stickerDraw(Canvas canvas) { if (containerView == null) { return; @@ -150,11 +354,98 @@ public class PhotoView extends EntityView { float mirrorT = this.mirrorT.set(mirrored); canvas.scale(1 - mirrorT * 2, 1f, baseSize.width / 2f, 0); canvas.skew(0, 4 * mirrorT * (1f - mirrorT) * .25f); - centerImage.setImageCoords(0, 0, (int) baseSize.width, (int) baseSize.height); - centerImage.draw(canvas); + + final float segmentedT = this.segmentedT.set(segmented); + if (!segmented) { + centerImage.setAlpha(1f - segmentedT); + centerImage.setImageCoords(0, 0, (int) baseSize.width, (int) baseSize.height); + centerImage.draw(canvas); + if (segmentedT > 0) { + drawSegmented(canvas); + } + + if (segmentedImage != null) { + canvas.saveLayerAlpha(0, 0, baseSize.width, baseSize.height, 0xFF, Canvas.ALL_SAVE_FLAG); + drawSegmented(canvas); + canvas.save(); + final long now = System.currentTimeMillis(); + if (highlightStart <= 0) { + highlightStart = now; + } + final float gradientWidth = .80f * baseSize.width; + final float highlightT = (now - highlightStart) / 1000f; + final float translate = highlightT * (2 * gradientWidth + baseSize.width) - gradientWidth; + if (highlightPaint == null) { + highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + highlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + highlightGradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{0x00feee8c, 0x66feee8c, 0x66feee8c, 0x00feee8c}, new float[]{0, .4f, .6f, 1f}, Shader.TileMode.CLAMP); + highlightGradientMatrix = new Matrix(); + highlightGradient.setLocalMatrix(highlightGradientMatrix); + highlightPaint.setShader(highlightGradient); + } + highlightGradientMatrix.reset(); + highlightGradientMatrix.postTranslate(translate, 0); + highlightGradient.setLocalMatrix(highlightGradientMatrix); + canvas.drawRect(0, 0, (int) baseSize.width, (int) baseSize.height, highlightPaint); + canvas.restore(); + canvas.restore(); + + if ((highlightT > 0 || needHighlight) && highlightT < 1f) { + needHighlight = false; + containerView.invalidate(); + } + } + } else { + highlightStart = -1; + needHighlight = false; + if (!overridenSegmented) { + centerImage.setImageCoords(0, 0, (int) baseSize.width, (int) baseSize.height); + centerImage.setAlpha(1f); + centerImage.draw(canvas); + } + drawSegmented(canvas); + } + canvas.restore(); } + private Path roundRectPath; + private void drawSegmented(Canvas canvas) { + if (segmentedImage == null) return; + src.set(0, 0, segmentedImage.getWidth(), segmentedImage.getHeight()); + int bitmapWidth = segmentedImage.getWidth(), bitmapHeight = segmentedImage.getHeight(); + if (orientation == 90 || orientation == 270 || orientation == -90 || orientation == -270) { + bitmapWidth = segmentedImage.getHeight(); + bitmapHeight = segmentedImage.getWidth(); + } + final float scale = Math.max(bitmapWidth / baseSize.width, bitmapHeight / baseSize.height); + final float bitmapW = segmentedImage.getWidth() / scale; + final float bitmapH = segmentedImage.getHeight() / scale; + dest.set((baseSize.width - bitmapW) / 2, (baseSize.height - bitmapH) / 2, (baseSize.width + bitmapW) / 2, (baseSize.height + bitmapH) / 2); + canvas.save(); + if (orientation != 0) { + canvas.rotate(orientation, dest.centerX(), dest.centerY()); + } + if (roundRectPath == null) { + roundRectPath = new Path(); + } + roundRectPath.rewind(); + roundRectPath.addRoundRect(dest, dp(12), dp(12), Path.Direction.CW); + canvas.clipPath(roundRectPath); + canvas.drawBitmap(segmentedImage, src, dest, segmentPaint); + canvas.restore(); + } + + public void highlightSegmented() { + needHighlight = true; + if (highlightStart <= 0 || System.currentTimeMillis() - highlightStart >= 1000) { + highlightStart = System.currentTimeMillis(); + } + if (containerView != null) { + containerView.invalidate(); + } + } + public long getDuration() { RLottieDrawable rLottieDrawable = centerImage.getLottieAnimation(); if (rLottieDrawable != null) { @@ -174,14 +465,14 @@ public class PhotoView extends EntityView { } @Override - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new Rect(); } float scale = parentView.getScaleX(); - float width = getMeasuredWidth() * getScale() + AndroidUtilities.dp(64) / scale; - float height = getMeasuredHeight() * getScale() + AndroidUtilities.dp(64) / scale; + float width = getMeasuredWidth() * getScale() + dp(64) / scale; + float height = getMeasuredHeight() * getScale() + dp(64) / scale; float left = (getPositionX() - width / 2.0f) * scale; float right = left + width * scale; return new Rect(left, (getPositionY() - height / 2.0f) * scale, right - left, height * scale); @@ -217,8 +508,8 @@ public class PhotoView extends EntityView { @Override protected int pointInsideHandle(float x, float y) { - float thickness = AndroidUtilities.dp(1.0f); - float radius = AndroidUtilities.dp(19.5f); + float thickness = dp(1.0f); + float radius = dp(19.5f); float inset = radius + thickness; float width = getMeasuredWidth() - inset * 2; @@ -254,17 +545,17 @@ public class PhotoView extends EntityView { canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); } - float thickness = AndroidUtilities.dp(2.0f); + float thickness = dp(2.0f); float radius = AndroidUtilities.dpf2(5.66f); - float inset = radius + thickness + AndroidUtilities.dp(15); + float inset = radius + thickness + dp(15); float width = getMeasuredWidth() - inset * 2; float height = getMeasuredHeight() - inset * 2; AndroidUtilities.rectTmp.set(inset, inset, inset + width, inset + height); - float R = AndroidUtilities.dp(12); + float R = dp(12); float rx = Math.min(R, width / 2f), ry = Math.min(R, height / 2f); path.rewind(); @@ -282,17 +573,17 @@ public class PhotoView extends EntityView { canvas.drawPath(path, paint); canvas.drawCircle(inset, inset + height / 2.0f, radius, dotStrokePaint); - canvas.drawCircle(inset, inset + height / 2.0f, radius - AndroidUtilities.dp(1) + 1, dotPaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius - dp(1) + 1, dotPaint); canvas.drawCircle(inset + width, inset + height / 2.0f, radius, dotStrokePaint); - canvas.drawCircle(inset + width, inset + height / 2.0f, radius - AndroidUtilities.dp(1) + 1, dotPaint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius - dp(1) + 1, dotPaint); canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); canvas.drawLine(inset, inset + ry, inset, inset + height - ry, paint); canvas.drawLine(inset + width, inset + ry, inset + width, inset + height - ry, paint); - canvas.drawCircle(inset + width, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); - canvas.drawCircle(inset, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius + dp(1) - 1, clearPaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius + dp(1) - 1, clearPaint); canvas.restoreToCount(count); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java index 6982f1ddc..1c50712ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ReactionWidgetEntityView.java @@ -129,7 +129,7 @@ public class ReactionWidgetEntityView extends EntityView { } @Override - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new Rect(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java index 1d9488f3c..41ec51869 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java @@ -192,7 +192,7 @@ public class RoundView extends EntityView { } @Override - protected org.telegram.ui.Components.Rect getSelectionBounds() { + public org.telegram.ui.Components.Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new org.telegram.ui.Components.Rect(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java index 97119d049..ce8084277 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java @@ -174,7 +174,7 @@ public class StickerView extends EntityView { } @Override - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new Rect(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java index 25a7decd0..41386272b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java @@ -382,7 +382,7 @@ public class TextPaintView extends EntityView { } @Override - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { ViewGroup parentView = (ViewGroup) getParent(); if (parentView == null) { return new Rect(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index 2a8bf63c7..0132948eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -363,7 +363,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica sendButtonColorAnimator.setDuration(150).start(); } - if (photoViewer.getParentAlert() != null && !photoViewer.getParentAlert().captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumLocked && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codePointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { + if (photoViewer.getParentAlert() != null && !photoViewer.getParentAlert().captionLimitBulletinShown && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount > MessagesController.getInstance(currentAccount).captionLengthLimitDefault && codePointCount < MessagesController.getInstance(currentAccount).captionLengthLimitPremium) { photoViewer.getParentAlert().captionLimitBulletinShown = true; if (heightShouldBeChanged) { AndroidUtilities.runOnUIThread(()->photoViewer.showCaptionLimitBulletin(parent), 300); @@ -390,7 +390,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayout implements Notifica captionLimitView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} - if (!MessagesController.getInstance(currentAccount).premiumLocked && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codePointCount) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > codePointCount) { photoViewer.showCaptionLimitBulletin(parent); } return; 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 56edb6411..573dbce89 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 @@ -10,6 +10,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -57,6 +58,7 @@ 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.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.AdminedChannelCell; import org.telegram.ui.Cells.GroupCreateUserCell; @@ -84,6 +86,7 @@ import org.telegram.ui.Components.Reactions.ChatCustomReactionsEditActivity; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; +import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; @@ -120,6 +123,12 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public static final int TYPE_BOOSTS_FOR_USERS = 19; public static final int TYPE_BOOSTS_FOR_COLOR = 20; public static final int TYPE_BOOSTS_FOR_REACTIONS = 21; + public static final int TYPE_BOOSTS_FOR_WALLPAPER = 22; + public static final int TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER = 23; + public static final int TYPE_BOOSTS_FOR_PROFILE_COLOR = 24; + public static final int TYPE_BOOSTS_FOR_EMOJI_STATUS = 25; + public static final int TYPE_BOOSTS_FOR_REPLY_ICON = 26; + public static final int TYPE_BOOSTS_FOR_PROFILE_ICON = 27; private boolean canSendLink; private int linkRow = -1; @@ -170,6 +179,81 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp int loadingRow = -1; int emptyViewDividerRow = -1; int bottomRow = -1; + int boostFeaturesStartRow = -1; + ArrayList boostFeatures; + + private static class BoostFeature { + + public final int iconResId; + public final int textKey; + public final String countValue; + public final String textKeyPlural; + public final int countPlural; + + private BoostFeature( + int iconResId, + int textKey, + String countValue, + String textKeyPlural, + int countPlural + ) { + this.iconResId = iconResId; + this.textKey = textKey; + this.countValue = countValue; + this.textKeyPlural = textKeyPlural; + this.countPlural = countPlural; + } + + public static BoostFeature of(int iconResId, int textKey) { + return new BoostFeature(iconResId, textKey, null, null, -1); + } + + public static BoostFeature of(int iconResId, int textKey, String count) { + return new BoostFeature(iconResId, textKey, count, null, -1); + } + + public static BoostFeature of(int iconResId, String textKeyPlural, int count) { + return new BoostFeature(iconResId, -1, null, textKeyPlural, count); + } + + public boolean equals(BoostFeature that) { + if (that == null) { + return false; + } + return ( + this.iconResId == that.iconResId && + this.textKey == that.textKey && + TextUtils.equals(this.countValue, that.countValue) && + TextUtils.equals(this.textKeyPlural, that.textKeyPlural) && + this.countPlural == that.countPlural + ); + } + + public static boolean arraysEqual(ArrayList a, ArrayList b) { + if (a == null && b == null) return true; + if (a != null && b == null || a == null && b != null) return false; + if (a.size() != b.size()) return false; + for (int i = 0; i < a.size(); ++i) { + if (!a.get(i).equals(b.get(i))) { + return false; + } + } + return true; + } + + public static class BoostFeatureLevel extends BoostFeature { + public final int lvl; + public final boolean isFirst; + public BoostFeatureLevel(int lvl) { + this(lvl, false); + } + public BoostFeatureLevel(int lvl, boolean isFirst) { + super(-1, -1, null, null, -1); + this.lvl = lvl; + this.isFirst = isFirst; + } + } + } public boolean parentIsChannel; private int currentValue = -1; @@ -213,8 +297,21 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp fireworksOverlay = new FireworksOverlay(getContext()); container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { + if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_REACTIONS || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON + ) { ((ViewGroup) premiumButtonView.getParent()).removeView(premiumButtonView); + if (divider != null) { + ((ViewGroup) divider.getParent()).removeView(divider); + } recyclerListView.setPadding(0, 0, 0, 0); actionBtn = new TextView(context); actionBtn.setGravity(Gravity.CENTER); @@ -247,7 +344,17 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } }; - if (!hasFixedSize) { + if (!hasFixedSize && !( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_REACTIONS || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON + )) { divider = new View(context) { @Override protected void onDraw(Canvas canvas) { @@ -302,7 +409,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (type == TYPE_BOOSTS_FOR_USERS) { if (canApplyBoost.empty) { if (UserConfig.getInstance(currentAccount).isPremium() && BoostRepository.isMultiBoostsAvailable()) { - BoostDialogs.showMoreBoostsNeeded(dialogId); + BoostDialogs.showMoreBoostsNeeded(dialogId, this); } else { AlertDialog.Builder builder = new AlertDialog.Builder(context, resourcesProvider); builder.setTitle(LocaleController.getString("PremiumNeeded", R.string.PremiumNeeded)); @@ -401,12 +508,22 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } return; } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { + if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_REACTIONS || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON + ) { AndroidUtilities.addToClipboard(getBoostLink()); dismiss(); return; } - if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked || isVeryLargeFile) { + if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() || isVeryLargeFile) { dismiss(); return; } @@ -434,7 +551,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } else { if (canApplyBoost.alreadyActive && BoostRepository.isMultiBoostsAvailable() && !canApplyBoost.isMaxLvl) { - BoostDialogs.showMoreBoostsNeeded(dialogId); + BoostDialogs.showMoreBoostsNeeded(dialogId, this); } else { dismiss(); } @@ -584,12 +701,22 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } else { premiumButtonView.buttonTextView.setText(LocaleController.getString("BoostChannel", R.string.BoostChannel)); } - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { + } else if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_REACTIONS || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON + ) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d "); spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_copy_filled), 0, 1, 0); spannableStringBuilder.append(LocaleController.getString("CopyLink", R.string.CopyLink)); premiumButtonView.buttonTextView.setText(spannableStringBuilder); - } else if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked || isVeryLargeFile) { + } else if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() || isVeryLargeFile) { premiumButtonView.buttonTextView.setText(LocaleController.getString("OK", R.string.OK)); premiumButtonView.hideIcon(); } else { @@ -697,21 +824,40 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } private static boolean hasFixedSize(int type) { - if (type == TYPE_PIN_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || - type == TYPE_LARGE_FILE || type == TYPE_ACCOUNTS || type == TYPE_FOLDER_INVITES || - type == TYPE_SHARED_FOLDERS || type == TYPE_STORIES_COUNT || type == TYPE_STORIES_WEEK || - type == TYPE_STORIES_MONTH || type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { - return true; - } - return false; + return ( + type == TYPE_PIN_DIALOGS || + type == TYPE_FOLDERS || + type == TYPE_CHATS_IN_FOLDER || + type == TYPE_LARGE_FILE || + type == TYPE_ACCOUNTS || + type == TYPE_FOLDER_INVITES || + type == TYPE_SHARED_FOLDERS || + type == TYPE_STORIES_COUNT || + type == TYPE_STORIES_WEEK || + type == TYPE_STORIES_MONTH + ); } @Override public CharSequence getTitle() { - if (type == TYPE_ADD_MEMBERS_RESTRICTED) { - return LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink); + switch (type) { + case TYPE_BOOSTS_FOR_USERS: + return LocaleController.getString(R.string.BoostChannel); + case TYPE_BOOSTS_FOR_POSTING: + case TYPE_BOOSTS_FOR_COLOR: + case TYPE_BOOSTS_FOR_WALLPAPER: + case TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER: + case TYPE_BOOSTS_FOR_REACTIONS: + case TYPE_BOOSTS_FOR_EMOJI_STATUS: + case TYPE_BOOSTS_FOR_REPLY_ICON: + case TYPE_BOOSTS_FOR_PROFILE_ICON: + case TYPE_BOOSTS_FOR_PROFILE_COLOR: + return LocaleController.getString(R.string.UnlockBoostChannelFeatures); + case TYPE_ADD_MEMBERS_RESTRICTED: + return LocaleController.getString(R.string.ChannelInviteViaLink); + default: + return LocaleController.getString(R.string.LimitReached); } - return LocaleController.getString("LimitReached", R.string.LimitReached); } @Override @@ -719,6 +865,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp super.onAttachedToWindow(); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.boostByChannelCreated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.boostedChannelByUser); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didStartedMultiGiftsSelector); } @Override @@ -726,6 +873,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp super.onDetachedFromWindow(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.boostByChannelCreated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.boostedChannelByUser); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didStartedMultiGiftsSelector); } @Override @@ -804,10 +952,23 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp String str = LocaleController.formatPluralString("BoostingReassignedFromPlural", size, LocaleController.formatPluralString("BoostingFromOtherChannel", channels)); BulletinFactory bulletinFactory = BulletinFactory.of(container, resourcesProvider); - bulletinFactory.createSimpleBulletinWithIconSize(R.raw.forward, str, 30).setDuration(4000).show(true); + bulletinFactory.createSimpleBulletinWithIconSize(R.raw.ic_boosts_replace, str, 30).setDuration(4000).show(true); + } else if (id == NotificationCenter.didStartedMultiGiftsSelector) { + dismiss(); } } + private static final int VIEW_TYPE_HEADER = 0; + private static final int VIEW_TYPE_CHANNEL = 1; + private static final int VIEW_TYPE_SHADOW = 2; + private static final int VIEW_TYPE_HEADER_CELL = 3; + private static final int VIEW_TYPE_USER = 4; + private static final int VIEW_TYPE_PROGRESS = 5; + private static final int VIEW_TYPE_SPACE16DP = 6; + private static final int VIEW_TYPE_BOOST_LINK = 7; + private static final int VIEW_TYPE_BOOST_FOOTER = 8; + private static final int VIEW_TYPE_BOOST_FEATURE = 9; + @Override public RecyclerListView.SelectionAdapter createAdapter() { return new RecyclerListView.SelectionAdapter() { @@ -816,7 +977,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (type == TYPE_ADD_MEMBERS_RESTRICTED && !canSendLink) { return false; } - return holder.getItemViewType() == 1 || holder.getItemViewType() == 4; + return holder.getItemViewType() == VIEW_TYPE_CHANNEL || holder.getItemViewType() == VIEW_TYPE_USER; } @NonNull @@ -825,8 +986,9 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp View view; Context context = parent.getContext(); switch (viewType) { - case 8: + case VIEW_TYPE_BOOST_FOOTER: LinearLayout wrapperLayout = new LinearLayout(context); + wrapperLayout.setPadding(backgroundPaddingLeft + dp(6), 0, backgroundPaddingLeft + dp(6), 0); wrapperLayout.setOrientation(LinearLayout.VERTICAL); LoginOrView orDividerView = new LoginOrView(context); @@ -871,10 +1033,14 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp view = wrapperLayout; break; - case 7: + case VIEW_TYPE_BOOST_FEATURE: + view = new BoostFeatureCell(context, resourcesProvider); + break; + case VIEW_TYPE_BOOST_LINK: FrameLayout frameLayout = new FrameLayout(getContext()); + frameLayout.setPadding(backgroundPaddingLeft + dp(6), 0, backgroundPaddingLeft + dp(6), 0); TextView linkView = new TextView(context); - linkView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(13), AndroidUtilities.dp(50), AndroidUtilities.dp(13)); + linkView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(13), AndroidUtilities.dp(statisticClickRunnable == null ? 18 : 50), AndroidUtilities.dp(13)); linkView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); linkView.setEllipsize(TextUtils.TruncateAt.MIDDLE); linkView.setSingleLine(true); @@ -901,10 +1067,10 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp view = frameLayout; break; default: - case 0: + case VIEW_TYPE_HEADER: view = headerView = new HeaderView(context); break; - case 1: + case VIEW_TYPE_CHANNEL: view = new AdminedChannelCell(context, new View.OnClickListener() { @Override public void onClick(View v) { @@ -915,17 +1081,17 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } }, true, 9); break; - case 2: + case VIEW_TYPE_SHADOW: view = new ShadowSectionCell(context, 12, Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); break; - case 3: + case VIEW_TYPE_HEADER_CELL: view = new HeaderCell(context); view.setPadding(0, 0, 0, AndroidUtilities.dp(8)); break; - case 4: + case VIEW_TYPE_USER: view = new GroupCreateUserCell(context, 1, 8, false); break; - case 5: + case VIEW_TYPE_PROGRESS: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(context, null); flickerLoadingView.setViewType(type == TYPE_PUBLIC_LINKS ? FlickerLoadingView.LIMIT_REACHED_LINKS : FlickerLoadingView.LIMIT_REACHED_GROUPS); flickerLoadingView.setIsSingleCell(true); @@ -933,7 +1099,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp flickerLoadingView.setItemsCount(10); view = flickerLoadingView; break; - case 6: + case VIEW_TYPE_SPACE16DP: view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -948,68 +1114,79 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 4) { - GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; - if (type == TYPE_TO0_MANY_COMMUNITIES) { - TLRPC.Chat chat = inactiveChats.get(position - chatStartRow); - String signature = inactiveChatsSignatures.get(position - chatStartRow); - cell.setObject(chat, chat.title, signature, position != chatEndRow - 1f); - cell.setChecked(selectedChats.contains(chat), false); - } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { - TLRPC.User user = restrictedUsers.get(position - chatStartRow); - String signature = LocaleController.formatUserStatus(currentAccount, user, null, null); - cell.setObject(user, ContactsController.formatName(user.first_name, user.last_name), signature, position != chatEndRow - 1f); - cell.setChecked(selectedChats.contains(user), false); - } - } else if (holder.getItemViewType() == 1) { - TLRPC.Chat chat = chats.get(position - chatStartRow); - AdminedChannelCell adminedChannelCell = (AdminedChannelCell) holder.itemView; - TLRPC.Chat oldChat = adminedChannelCell.getCurrentChannel(); - adminedChannelCell.setChannel(chat, false); - adminedChannelCell.setChecked(selectedChats.contains(chat), oldChat == chat); - } else if (holder.getItemViewType() == 3) { - HeaderCell headerCell = (HeaderCell) holder.itemView; - if (type == TYPE_ADD_MEMBERS_RESTRICTED) { - if (canSendLink) { - headerCell.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink)); - } else { - if (restrictedUsers.size() == 1) { - headerCell.setText(LocaleController.getString("ChannelInviteViaLinkRestricted2", R.string.ChannelInviteViaLinkRestricted2)); - } else { - headerCell.setText(LocaleController.getString("ChannelInviteViaLinkRestricted3", R.string.ChannelInviteViaLinkRestricted3)); - } + switch (holder.getItemViewType()) { + case VIEW_TYPE_USER: + GroupCreateUserCell cell = (GroupCreateUserCell) holder.itemView; + if (type == TYPE_TO0_MANY_COMMUNITIES) { + TLRPC.Chat chat = inactiveChats.get(position - chatStartRow); + String signature = inactiveChatsSignatures.get(position - chatStartRow); + cell.setObject(chat, chat.title, signature, position != chatEndRow - 1f); + cell.setChecked(selectedChats.contains(chat), false); + } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { + TLRPC.User user = restrictedUsers.get(position - chatStartRow); + String signature = LocaleController.formatUserStatus(currentAccount, user, null, null); + cell.setObject(user, ContactsController.formatName(user.first_name, user.last_name), signature, position != chatEndRow - 1f); + cell.setChecked(selectedChats.contains(user), false); } - } else if (type == TYPE_PUBLIC_LINKS) { - headerCell.setText(LocaleController.getString("YourPublicCommunities", R.string.YourPublicCommunities)); - } else { - headerCell.setText(LocaleController.getString("LastActiveCommunities", R.string.LastActiveCommunities)); - } - } else if (holder.getItemViewType() == 8) { - + break; + case VIEW_TYPE_CHANNEL: + TLRPC.Chat chat = chats.get(position - chatStartRow); + AdminedChannelCell adminedChannelCell = (AdminedChannelCell) holder.itemView; + TLRPC.Chat oldChat = adminedChannelCell.getCurrentChannel(); + adminedChannelCell.setChannel(chat, false); + adminedChannelCell.setChecked(selectedChats.contains(chat), oldChat == chat); + break; + case VIEW_TYPE_HEADER_CELL: + HeaderCell headerCell = (HeaderCell) holder.itemView; + if (type == TYPE_ADD_MEMBERS_RESTRICTED) { + if (canSendLink) { + headerCell.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink)); + } else { + if (restrictedUsers.size() == 1) { + headerCell.setText(LocaleController.getString("ChannelInviteViaLinkRestricted2", R.string.ChannelInviteViaLinkRestricted2)); + } else { + headerCell.setText(LocaleController.getString("ChannelInviteViaLinkRestricted3", R.string.ChannelInviteViaLinkRestricted3)); + } + } + } else if (type == TYPE_PUBLIC_LINKS) { + headerCell.setText(LocaleController.getString("YourPublicCommunities", R.string.YourPublicCommunities)); + } else { + headerCell.setText(LocaleController.getString("LastActiveCommunities", R.string.LastActiveCommunities)); + } + break; + case VIEW_TYPE_BOOST_FEATURE: + final int index = position - boostFeaturesStartRow; + if (boostFeatures != null && index >= 0 && index < boostFeatures.size()) { + ((BoostFeatureCell) holder.itemView).set(boostFeatures.get(index)); + } + break; } } @Override public int getItemViewType(int position) { if (headerRow == position) { - return 0; + return VIEW_TYPE_HEADER; } else if (dividerRow == position) { - return 2; + return VIEW_TYPE_SHADOW; } else if (chatsTitleRow == position) { - return 3; + return VIEW_TYPE_HEADER_CELL; } else if (loadingRow == position) { - return 5; + return VIEW_TYPE_PROGRESS; } else if (emptyViewDividerRow == position) { - return 6; + return VIEW_TYPE_SPACE16DP; } else if (linkRow == position) { - return 7; + return VIEW_TYPE_BOOST_LINK; } else if (bottomRow == position) { - return 8; + return VIEW_TYPE_BOOST_FOOTER; + } + if (boostFeatures != null && position >= boostFeaturesStartRow && position <= boostFeaturesStartRow + boostFeatures.size()) { + return VIEW_TYPE_BOOST_FEATURE; } if (type == TYPE_TO0_MANY_COMMUNITIES || type == TYPE_ADD_MEMBERS_RESTRICTED) { - return 4; + return VIEW_TYPE_USER; } else { - return 1; + return VIEW_TYPE_CHANNEL; } } @@ -1052,6 +1229,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public void setBoostsStats(TL_stories.TL_premium_boostsStatus boostsStatus, boolean isCurrentChat) { this.boostsStatus = boostsStatus; this.isCurrentChat = isCurrentChat; + updateRows(); } public void setCanApplyBoost(ChannelBoostsController.CanApplyBoost canApplyBoost) { @@ -1075,12 +1253,12 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public HeaderView(Context context) { super(context); setOrientation(LinearLayout.VERTICAL); - setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); + setPadding(backgroundPaddingLeft + dp(6), 0, backgroundPaddingLeft + dp(6), 0); limitParams = getLimitParams(type, currentAccount); int icon = limitParams.icon; String descriptionStr; - boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumLocked; + boolean premiumLocked = MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); if (type == TYPE_BOOSTS_FOR_USERS) { descriptionStr = getBoostsDescriptionString(); } else if (type == TYPE_BOOSTS_FOR_POSTING) { @@ -1098,8 +1276,38 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } else if (type == TYPE_BOOSTS_FOR_COLOR) { descriptionStr = LocaleController.formatString( - "ChannelNeedBoostsForColorDescription", R.string.ChannelNeedBoostsForColorDescription, - MessagesController.getInstance(currentAccount).channelColorLevelMin + R.string.ChannelNeedBoostsForColorDescription, + channelColorLevelMin() + ); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_COLOR) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForProfileColorDescription, + channelColorLevelMin() + ); + } else if (type == TYPE_BOOSTS_FOR_EMOJI_STATUS) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForEmojiStatusDescription, + MessagesController.getInstance(currentAccount).channelEmojiStatusLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_REPLY_ICON) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForReplyIconDescription, + MessagesController.getInstance(currentAccount).channelBgIconLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_ICON) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForProfileIconDescription, + MessagesController.getInstance(currentAccount).channelProfileIconLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_WALLPAPER) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForWallpaperDescription, + MessagesController.getInstance(currentAccount).channelWallpaperLevelMin + ); + } else if (type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER) { + descriptionStr = LocaleController.formatString( + R.string.ChannelNeedBoostsForCustomWallpaperDescription, + MessagesController.getInstance(currentAccount).channelCustomWallpaperLevelMin ); } else if (type == TYPE_BOOSTS_FOR_REACTIONS) { descriptionStr = LocaleController.formatPluralString("ReactionReachLvlForReaction", requiredLvl, requiredLvl); @@ -1184,7 +1392,19 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp percent = defaultLimit / (float) premiumLimit; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { + final boolean boostsType = ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_USERS || + type == TYPE_BOOSTS_FOR_REACTIONS || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON + ); + if (boostsType) { currentValue = 0; } @@ -1197,7 +1417,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp super.invalidate(); } }; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { + if (boostsType) { if (boostsStatus != null) { limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.boostedNow); } @@ -1240,6 +1460,16 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp title.setText(LocaleController.getString(R.string.ReactionCustomReactions)); } else if (type == TYPE_BOOSTS_FOR_COLOR) { title.setText(LocaleController.getString(R.string.BoostingEnableColor)); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_COLOR) { + title.setText(LocaleController.getString(R.string.BoostingEnableProfileColor)); + } else if (type == TYPE_BOOSTS_FOR_REPLY_ICON) { + title.setText(LocaleController.getString(R.string.BoostingEnableLinkIcon)); + } else if (type == TYPE_BOOSTS_FOR_PROFILE_ICON) { + title.setText(LocaleController.getString(R.string.BoostingEnableProfileIcon)); + } else if (type == TYPE_BOOSTS_FOR_EMOJI_STATUS) { + title.setText(LocaleController.getString(R.string.BoostingEnableEmojiStatus)); + } else if (type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER) { + title.setText(LocaleController.getString(R.string.BoostingEnableWallpaper)); } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { if (canSendLink) { title.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink)); @@ -1264,7 +1494,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp titleLinearLayout.setWeightSum(1f); titleLinearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 1, 0)); titleLinearLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 2, 0, 0)); - addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, premiumLocked ? 8 : 22, 12, 9)); + addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, premiumLocked ? 8 : 22, 12, 9)); } else { addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, premiumLocked ? 8 : 22, 0, 0)); @@ -1364,17 +1594,21 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } + protected int channelColorLevelMin() { + return 0; + } + private String getBoostsTitleString() { if (boostsStatus.next_level_boosts == 0) { return LocaleController.formatString("BoostsMaxLevelReached", R.string.BoostsMaxLevelReached); } else if (boostsStatus.level > 0 && !canApplyBoost.alreadyActive) { - return LocaleController.getString("HelpUpgradeChannel", R.string.HelpUpgradeChannel); + return LocaleController.getString(R.string.BoostChannel); } else if (isCurrentChat) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (canApplyBoost.alreadyActive) { return LocaleController.formatString("YouBoostedChannel2", R.string.YouBoostedChannel2, chat.title); } else { - return LocaleController.formatString("BoostingEnableStoriesForChannel2", R.string.BoostingEnableStoriesForChannel2, chat.title); + return LocaleController.getString(R.string.BoostChannel); } } else { if (canApplyBoost.alreadyActive) { @@ -1386,6 +1620,8 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } private String getBoostsDescriptionString() { + TLRPC.Chat channel = MessagesController.getInstance(currentAccount).getChat(-dialogId); + String channelTitle = channel == null ? LocaleController.getString(R.string.AccDescrChannel) : channel.title; boolean isZeroBoostsForNextLevel = boostsStatus.boosts == boostsStatus.current_level_boosts; if (isZeroBoostsForNextLevel && canApplyBoost.alreadyActive) { if (boostsStatus.level == 1) { @@ -1399,7 +1635,8 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp if (canApplyBoost.alreadyActive) { if (boostsStatus.level == 0) { return LocaleController.formatString( - "ChannelNeedBoostsAlreadyBoostedDescriptionLevel1", R.string.ChannelNeedBoostsAlreadyBoostedDescriptionLevel1, + R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } else { @@ -1408,17 +1645,19 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp boostsStatus.level, LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1)); } else { - return LocaleController.formatString("ChannelNeedBoostsDescriptionLevelNext", R.string.ChannelNeedBoostsDescriptionLevelNext, - LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts), - LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1) + return LocaleController.formatString( + R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } } } else { if (boostsStatus.level == 0) { return LocaleController.formatString( - "ChannelNeedBoostsDescriptionLevel1", R.string.ChannelNeedBoostsDescriptionLevel1, - LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) + R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } else { if (boostsStatus.next_level_boosts == 0) { @@ -1426,9 +1665,10 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp boostsStatus.level, LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1)); } else { - return LocaleController.formatString("ChannelNeedBoostsDescriptionLevelNext", R.string.ChannelNeedBoostsDescriptionLevelNext, - LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts), - LocaleController.formatPluralString("BoostStories", boostsStatus.level + 1) + return LocaleController.formatString( + R.string.ChannelNeedBoostsDescriptionForNewFeatures, + channelTitle, + LocaleController.formatPluralString("MoreBoosts", boostsStatus.next_level_boosts - boostsStatus.boosts, boostsStatus.next_level_boosts - boostsStatus.boosts) ); } } @@ -1529,7 +1769,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_PROFILE_COLOR || type == TYPE_BOOSTS_FOR_REPLY_ICON || type == TYPE_BOOSTS_FOR_PROFILE_ICON || type == TYPE_BOOSTS_FOR_EMOJI_STATUS || type == TYPE_BOOSTS_FOR_WALLPAPER || type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || type == TYPE_BOOSTS_FOR_USERS || type == TYPE_BOOSTS_FOR_REACTIONS) { limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitDefault; limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitPremium; limitParams.icon = R.drawable.filled_limit_boost; @@ -1583,8 +1823,32 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp loadingRow = -1; linkRow = -1; emptyViewDividerRow = -1; + boostFeaturesStartRow = -1; + headerRow = rowCount++; - if (!hasFixedSize(type)) { + if ( + type == TYPE_BOOSTS_FOR_USERS || + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_PROFILE_COLOR || + type == TYPE_BOOSTS_FOR_REPLY_ICON || + type == TYPE_BOOSTS_FOR_PROFILE_ICON || + type == TYPE_BOOSTS_FOR_WALLPAPER || + type == TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER || + type == TYPE_BOOSTS_FOR_EMOJI_STATUS || + type == TYPE_BOOSTS_FOR_REACTIONS + ) { + if (type != TYPE_BOOSTS_FOR_USERS) { + topPadding = .24f; + linkRow = rowCount++; + if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable) { + bottomRow = rowCount++; + } + } + setupBoostFeatures(); + boostFeaturesStartRow = rowCount++; + rowCount += boostFeatures.size() - 1; + } else if (!hasFixedSize(type)) { dividerRow = rowCount++; chatsTitleRow = rowCount++; if (loading) { @@ -1604,12 +1868,6 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp } } } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_REACTIONS) { - linkRow = rowCount++; - if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable) { - bottomRow = rowCount++; - } - } notifyDataSetChanged(); } @@ -1739,4 +1997,201 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp int premiumLimit = 0; } + private void setupBoostFeatures() { + boostFeatures = new ArrayList<>(); + + ArrayList lastFeatureList = null; + int startLevel = 1; + if (boostsStatus != null) { + startLevel = boostsStatus.level + 1; + } + + int maxlvl = 10; + final MessagesController m = MessagesController.getInstance(currentAccount); + if (m != null) { + maxlvl = Math.max(maxlvl, m.peerColors != null ? m.peerColors.maxLevel() : 0); + maxlvl = Math.max(maxlvl, m.profilePeerColors != null ? m.profilePeerColors.maxLevel() : 0); + maxlvl = Math.max(maxlvl, m.channelBgIconLevelMin); + maxlvl = Math.max(maxlvl, m.channelProfileIconLevelMin); + maxlvl = Math.max(maxlvl, m.channelEmojiStatusLevelMin); + maxlvl = Math.max(maxlvl, m.channelWallpaperLevelMin); + maxlvl = Math.max(maxlvl, m.channelCustomWallpaperLevelMin); + } + + for (int lvl = startLevel; lvl <= maxlvl; ++lvl) { + ArrayList featureList = boostFeaturesForLevel(lvl); + if (lastFeatureList == null || !BoostFeature.arraysEqual(lastFeatureList, featureList)) { + boostFeatures.add(new BoostFeature.BoostFeatureLevel(lvl, boostFeatures.isEmpty())); + boostFeatures.addAll(featureList); + lastFeatureList = featureList; + } + } + } + + private ArrayList boostFeaturesForLevel(int level) { + ArrayList list = new ArrayList<>(); + final MessagesController m = MessagesController.getInstance(currentAccount); + if (m == null) return list; + list.add(BoostFeature.of(R.drawable.menu_feature_stories, "BoostFeatureStoriesPerDay", level)); + list.add(BoostFeature.of(R.drawable.menu_feature_reactions, "BoostFeatureCustomReaction", level)); + final int nameColorsAvailable = m.peerColors != null ? m.peerColors.colorsAvailable(level) : 0; + final int profileColorsAvailable = m.profilePeerColors != null ? m.profilePeerColors.colorsAvailable(level) : 0; + if (nameColorsAvailable > 0) { + list.add(BoostFeature.of(R.drawable.menu_feature_color_name, "BoostFeatureNameColor", 7)); + } + if (nameColorsAvailable > 0) { + list.add(BoostFeature.of(R.drawable.menu_feature_links, "BoostFeatureReplyColor", nameColorsAvailable)); + } + if (level >= m.channelBgIconLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_links2, R.string.BoostFeatureReplyIcon)); + } + if (level >= m.channelEmojiStatusLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_status, R.string.BoostFeatureEmojiStatuses, "1000+")); + } + if (profileColorsAvailable > 0) { + list.add(BoostFeature.of(R.drawable.menu_feature_color_profile, "BoostFeatureProfileColor", profileColorsAvailable)); + } + if (level >= m.channelProfileIconLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_cover, R.string.BoostFeatureProfileIcon)); + } + if (level >= m.channelWallpaperLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_wallpaper, "BoostFeatureBackground", 8)); + } + if (level >= m.channelCustomWallpaperLevelMin) { + list.add(BoostFeature.of(R.drawable.menu_feature_custombg, R.string.BoostFeatureCustomBackground)); + } + return list; + } + + private class BoostFeatureCell extends FrameLayout { + private final Theme.ResourcesProvider resourcesProvider; + + private final ImageView imageView; + private final SimpleTextView textView; + + private final FrameLayout levelLayout; + private final SimpleTextView levelTextView; + + public BoostFeature feature; + public BoostFeature.BoostFeatureLevel level; + + public BoostFeatureCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_premiumGradient1, resourcesProvider), PorterDuff.Mode.SRC_IN)); + addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 24, 0, 24, 0)); + + textView = new SimpleTextView(context); + textView.setWidthWrapContent(true); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + textView.setTextSize(14); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 30 : 60, 0, LocaleController.isRTL ? 60 : 30, 0)); + + levelTextView = new SimpleTextView(context); + levelTextView.setTextColor(Color.WHITE); + levelTextView.setWidthWrapContent(true); + levelTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + levelTextView.setTextSize(14); + levelLayout = new FrameLayout(context) { + private final PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + dividerPaint.setStyle(Paint.Style.STROKE); + dividerPaint.setStrokeWidth(1); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + canvas.drawLine(dp(18), getHeight() / 2f, levelTextView.getLeft() - dp(20), getHeight() / 2f, dividerPaint); + canvas.drawLine(levelTextView.getRight() + dp(20), getHeight() / 2f, getWidth() - dp(18), getHeight() / 2f, dividerPaint); + + AndroidUtilities.rectTmp.set( + levelTextView.getLeft() - dp(15), + (levelTextView.getTop() + levelTextView.getBottom() - dp(30)) / 2f, + levelTextView.getRight() + dp(15), + (levelTextView.getTop() + levelTextView.getBottom() + dp(30)) / 2f + ); + canvas.save(); + canvas.translate(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top); + AndroidUtilities.rectTmp.set(0, 0, AndroidUtilities.rectTmp.width(), AndroidUtilities.rectTmp.height()); + gradientTools.gradientMatrix(AndroidUtilities.rectTmp); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(15), dp(15), gradientTools.paint); + canvas.restore(); + + super.dispatchDraw(canvas); + } + }; + levelLayout.setWillNotDraw(false); + levelLayout.addView(levelTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + addView(levelLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + public void set(BoostFeature boostFeature) { + if (boostFeature instanceof BoostFeature.BoostFeatureLevel) { + level = (BoostFeature.BoostFeatureLevel) boostFeature; + feature = null; + + imageView.setVisibility(View.GONE); + textView.setVisibility(View.GONE); + levelLayout.setVisibility(View.VISIBLE); + levelTextView.setText(LocaleController.formatPluralString(level.isFirst ? "BoostLevelUnlocks" : "BoostLevel", level.lvl)); + } else if (boostFeature != null) { + level = null; + feature = boostFeature; + imageView.setVisibility(View.VISIBLE); + imageView.setImageResource(feature.iconResId); + textView.setVisibility(View.VISIBLE); + if (feature.textKeyPlural != null) { + String key1 = feature.textKeyPlural + "_" + LocaleController.getStringParamForNumber(feature.countPlural); + String text = LocaleController.getString(key1); + if (text == null || text.startsWith("LOC_ERR")) { + text = LocaleController.getString(feature.textKeyPlural + "_other"); + } + if (text == null) { + text = ""; + } + int index; + SpannableStringBuilder ssb = new SpannableStringBuilder(text); + if ((index = text.indexOf("%d")) >= 0) { + ssb = new SpannableStringBuilder(text); + SpannableString boldNumber = new SpannableString(feature.countPlural + ""); + boldNumber.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, boldNumber.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.replace(index, index + 2, boldNumber); + } + textView.setText(ssb); + } else { + String text = LocaleController.getString(feature.textKey); + if (text == null) { + text = ""; + } + if (feature.countValue != null) { + int index; + SpannableStringBuilder ssb = new SpannableStringBuilder(text); + if ((index = text.indexOf("%s")) >= 0) { + ssb = new SpannableStringBuilder(text); + SpannableString boldNumber = new SpannableString(feature.countValue); + boldNumber.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, boldNumber.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.replace(index, index + 2, boldNumber); + } + textView.setText(ssb); + } else { + textView.setText(text); + } + } + levelLayout.setVisibility(View.GONE); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(level != null ? 49 : 36), MeasureSpec.EXACTLY)); + } + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java index 280572241..be24d2481 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java @@ -9,6 +9,8 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -133,7 +135,7 @@ public class PremiumGradient { } public Paint getMainGradientPaint() { - if (MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked) { + if (MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked()) { if (lockedPremiumPaint == null) { lockedPremiumPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @@ -182,6 +184,14 @@ public class PremiumGradient { this.colorKey5 = colorKey5; } + public void gradientMatrix(Rect rect) { + gradientMatrix(rect.left, rect.top, rect.right, rect.bottom, 0, 0); + } + + public void gradientMatrix(RectF rect) { + gradientMatrix((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom, 0, 0); + } + public void gradientMatrix(int x, int y, int x1, int y1, float xOffset, float yOffset) { chekColors(); if (exactly) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java index f1150a566..a876bbe5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components.Premium; +import static org.telegram.messenger.LocaleController.getString; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -34,12 +36,14 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; @@ -57,6 +61,7 @@ import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingSpan; import org.telegram.ui.Components.Premium.GLIcon.GLIconRenderer; import org.telegram.ui.Components.Premium.GLIcon.GLIconTextureView; +import org.telegram.ui.Components.Premium.boosts.cells.TextInfoCell; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.PremiumFeatureCell; import org.telegram.ui.PremiumPreviewFragment; @@ -65,22 +70,25 @@ import java.util.ArrayList; public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView implements NotificationCenter.NotificationCenterDelegate { - ArrayList premiumFeatures = new ArrayList<>(); + protected ArrayList premiumFeatures = new ArrayList<>(); int currentAccount; - TLRPC.User user; - GiftPremiumBottomSheet.GiftTier giftTier; + protected TLRPC.User user; + protected GiftPremiumBottomSheet.GiftTier giftTier; boolean isOutboundGift; PremiumFeatureCell dummyCell; int totalGradientHeight; - int rowCount; - int paddingRow; - int featuresStartRow; - int featuresEndRow; - int sectionRow; - int helpUsRow; - int buttonRow; + protected int rowCount; + protected int paddingRow; + protected int additionStartRow; + protected int additionEndRow; + protected int featuresStartRow; + protected int featuresEndRow; + protected int sectionRow; + protected int helpUsRow; + protected int buttonRow; + protected int termsRow; FireworksOverlay fireworksOverlay; PremiumGradient.PremiumGradientTools gradientTools; @@ -106,6 +114,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i ValueAnimator enterAnimator; boolean animateConfetti; + boolean animateConfettiWithStars; FrameLayout buttonContainer; FrameLayout bulletinContainer; @@ -137,26 +146,16 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i gradientTools.cx = 0; gradientTools.cy = 0; - paddingRow = rowCount++; - featuresStartRow = rowCount; - rowCount += premiumFeatures.size(); - featuresEndRow = rowCount; - sectionRow = rowCount++; - if (!UserConfig.getInstance(currentAccount).isPremium() && gift == null) { - buttonRow = rowCount++; - } + updateRows(); + recyclerListView.setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); recyclerListView.setOnItemClickListener((view, position) -> { if (view instanceof PremiumFeatureCell) { PremiumFeatureCell cell = (PremiumFeatureCell) view; PremiumPreviewFragment.sentShowFeaturePreview(currentAccount, cell.data.type); -// if (cell.data.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { -// DoubledLimitsBottomSheet bottomSheet = new DoubledLimitsBottomSheet(fragment, currentAccount); -// showDialog(bottomSheet); -// } else { - showDialog(new PremiumFeatureBottomSheet(fragment, cell.data.type, false)); - // } + showDialog(new PremiumFeatureBottomSheet(fragment, cell.data.type, false)); } + onAdditionItemClicked(view); }); MediaDataController.getInstance(currentAccount).preloadPremiumPreviewStickers(); @@ -169,6 +168,21 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i containerView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 140, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); } + protected void onAdditionItemClicked(View view) { + + } + + protected void updateRows() { + paddingRow = rowCount++; + featuresStartRow = rowCount; + rowCount += premiumFeatures.size(); + featuresEndRow = rowCount; + sectionRow = rowCount++; + if (!UserConfig.getInstance(currentAccount).isPremium() && giftTier == null) { + buttonRow = rowCount++; + } + } + public PremiumPreviewBottomSheet setOutboundGift(boolean outboundGift) { isOutboundGift = outboundGift; return this; @@ -179,6 +193,11 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i return this; } + public PremiumPreviewBottomSheet setAnimateConfettiWithStars(boolean animateConfettiWithStars) { + this.animateConfettiWithStars = animateConfettiWithStars; + return this; + } + private void showDialog(Dialog dialog) { if (iconTextureView != null) { iconTextureView.setDialogVisible(true); @@ -212,13 +231,17 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i buttonDivider.getLayoutParams().height = 1; AndroidUtilities.updateViewVisibilityAnimated(buttonDivider, true, 1f, false); - if (!UserConfig.getInstance(currentAccount).isPremium()) { + if (!UserConfig.getInstance(currentAccount).isPremium() && needDefaultPremiumBtn()) { buttonContainer.addView(premiumButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.CENTER_VERTICAL, 16, 0, 16, 0)); buttonContainer.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); containerView.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 68, Gravity.BOTTOM)); } } + protected boolean needDefaultPremiumBtn() { + return true; + } + @Override protected void onPreMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onPreMeasure(widthMeasureSpec, heightMeasureSpec); @@ -227,7 +250,8 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i } private FrameLayout titleViewContainer; - private LinkSpanDrawable.LinksTextView titleView[]; + protected LinkSpanDrawable.LinksTextView titleView[]; + private void titleLoaded(CharSequence newText, boolean animated) { if (titleView == null) { return; @@ -260,7 +284,8 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i } } - private TextView subtitleView; + protected TextView subtitleView; + public void setTitle(boolean animated) { if (titleView == null || subtitleView == null) { return; @@ -398,6 +423,14 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i return new Adapter(); } + protected void attachIconContainer(LinearLayout container) { + container.addView(overrideTitleIcon, LayoutHelper.createLinear(140, 140, Gravity.CENTER_HORIZONTAL, Gravity.CENTER, 10, 10, 10, 10)); + } + + protected void afterCellCreated(int viewType, View view) { + + } + private class Adapter extends RecyclerListView.SelectionAdapter { @NonNull @@ -405,6 +438,11 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; Context context = parent.getContext(); + view = onCreateAdditionCell(viewType, context); + if (view != null) { + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } switch (viewType) { case 0: LinearLayout linearLayout = new LinearLayout(context) { @@ -444,7 +482,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i if (overrideTitleIcon.getParent() != null) { ((ViewGroup) overrideTitleIcon.getParent()).removeView(overrideTitleIcon); } - linearLayout.addView(overrideTitleIcon, LayoutHelper.createLinear(140, 140, Gravity.CENTER_HORIZONTAL, Gravity.CENTER, 10, 10, 10, 10)); + attachIconContainer(linearLayout); } if (titleViewContainer == null) { @@ -499,7 +537,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i linearLayout.addView(titleViewContainer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.CENTER_HORIZONTAL, 40, 0, 40, 0)); if (subtitleView == null) { - subtitleView = new TextView(context); + subtitleView = new LinkSpanDrawable.LinksTextView(getContext(), resourcesProvider); subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); subtitleView.setGravity(Gravity.CENTER_HORIZONTAL); subtitleView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); @@ -516,9 +554,18 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - drawable.rect2.set(0, 0, getMeasuredWidth(), getMeasuredHeight() - AndroidUtilities.dp(52)); } + + @Override + protected void configure() { + super.configure(); + drawable.useGradient = true; + drawable.useBlur = false; + drawable.forceMaxAlpha = true; + drawable.checkBounds = true; + drawable.init(); + } }; FrameLayout frameLayout = new FrameLayout(context) { @Override @@ -537,11 +584,6 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i frameLayout.addView(starParticlesView); frameLayout.addView(linearLayout); - starParticlesView.drawable.useGradient = true; - starParticlesView.drawable.useBlur = false; - starParticlesView.drawable.forceMaxAlpha = true; - starParticlesView.drawable.checkBounds = true; - starParticlesView.drawable.init(); if (iconTextureView != null) { iconTextureView.setStarParticlesView(starParticlesView); } @@ -574,8 +616,25 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i case 4: view = new AboutPremiumView(context); break; + case 5: + TextInfoCell cell = new TextInfoCell(context, resourcesProvider); + cell.setBackground(true); + String terms1 = getString("GiftPremiumPrivacyPolicyAndTerms", R.string.GiftPremiumPrivacyPolicyAndTerms); + SpannableStringBuilder stringBuilder1 = AndroidUtilities.replaceSingleTag( + terms1, + Theme.key_chat_messageLinkIn, 0, + () -> Browser.openUrl(fragment.getParentActivity(), LocaleController.getString("TermsOfServiceUrl", R.string.TermsOfServiceUrl))); + String terms2 = getString("GiftPremiumPrivacyPolicy", R.string.GiftPremiumPrivacyPolicy); + SpannableStringBuilder stringBuilder2 = AndroidUtilities.replaceSingleTag( + terms2, + Theme.key_chat_messageLinkIn, 0, + () -> Browser.openUrl(fragment.getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl))); + cell.setText(AndroidUtilities.replaceCharSequence("%1$s", stringBuilder1, stringBuilder2)); + view = cell; + break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + afterCellCreated(viewType, view); return new RecyclerListView.Holder(view); } @@ -583,6 +642,8 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (position >= featuresStartRow && position < featuresEndRow) { ((PremiumFeatureCell) holder.itemView).setData(premiumFeatures.get(position - featuresStartRow), position != featuresEndRow - 1); + } else if (position >= additionStartRow && position < additionEndRow) { + onBindAdditionCell(holder.itemView, position); } } @@ -595,6 +656,8 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i public int getItemViewType(int position) { if (position == paddingRow) { return 0; + } else if (position >= additionStartRow && position < additionEndRow) { + return getAdditionItemViewType(position); } else if (position >= featuresStartRow && position < featuresEndRow) { return 1; } else if (position == sectionRow) { @@ -603,16 +666,34 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i return 3; } else if (position == helpUsRow) { return 4; + } else if (position == termsRow) { + return 5; } return super.getItemViewType(position); } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == 1; + return holder.getItemViewType() == 1 || isAdditionViewClickable(holder.getItemViewType()); } } + protected boolean isAdditionViewClickable(int viewType) { + return false; + } + + protected int getAdditionItemViewType(int position) { + return 0; + } + + protected View onCreateAdditionCell(int viewType, Context context) { + return null; + } + + protected void onBindAdditionCell(View view, int pos) { + + } + private void measureGradient(int w, int h) { int yOffset = 0; for (int i = 0; i < premiumFeatures.size(); i++) { @@ -634,7 +715,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i try { container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} - fireworksOverlay.start(); + fireworksOverlay.start(animateConfettiWithStars); }, 200); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java index 95dfa49ff..05c536b51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java @@ -49,6 +49,10 @@ public class StarParticlesView extends View { } drawable = new Drawable(particlesCount); + configure(); + } + + protected void configure() { drawable.type = 100; drawable.roundEffect = true; drawable.useRotate = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java index 0e348a4ac..fb9d287f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java @@ -83,14 +83,19 @@ public class BoostCounterView extends View { animateCount(); } lastCount = count; + int oldLength = countText.getText().length(); countText.setText("x" + count, animated); + int newLength = countText.getText().length(); invalidate(); + if (oldLength != newLength) { + requestLayout(); + } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure( - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(26), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec((int) (dp(8 + 3 + 4) + countText.getWidth()), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(26), MeasureSpec.EXACTLY) ); } @@ -100,7 +105,7 @@ public class BoostCounterView extends View { super.onDraw(canvas); canvas.save(); canvas.translate(AndroidUtilities.dp(3), AndroidUtilities.dp(3)); - AndroidUtilities.rectTmp2.set(0, 0, AndroidUtilities.dp(20), AndroidUtilities.dp(20)); + AndroidUtilities.rectTmp2.set(0, 0, dp(8) + (int) countText.getCurrentWidth(), AndroidUtilities.dp(20)); AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp2); if (countScale != 1) { @@ -109,7 +114,7 @@ public class BoostCounterView extends View { } canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(10), dp(10), bgPaint); - AndroidUtilities.rectTmp2.set(0, 0, AndroidUtilities.dp(20), AndroidUtilities.dp(19)); + AndroidUtilities.rectTmp2.set(0, 0, (int) AndroidUtilities.rectTmp.width(), AndroidUtilities.dp(19)); countText.setBounds(AndroidUtilities.rectTmp2); countText.draw(canvas); if (countScale != 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java index 8ba91f29e..176fbef65 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java @@ -19,6 +19,7 @@ import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; +import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -29,9 +30,11 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; @@ -45,6 +48,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.EffectsTextView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.LaunchActivity; @@ -69,6 +73,32 @@ public class BoostDialogs { } } + public static void processApplyGiftCodeError(TLRPC.TL_error error, FrameLayout containerLayout, Theme.ResourcesProvider resourcesProvider, Runnable share) { + if (error == null || error.text == null) { + return; + } + if (error.text.contains("PREMIUM_SUB_ACTIVE_UNTIL_")) { + String strDate = error.text.replace("PREMIUM_SUB_ACTIVE_UNTIL_", ""); + int date = Integer.parseInt(strDate); + String formattedDate = LocaleController.getInstance().formatterBoostExpired.format(new Date(date * 1000L)); + String subTitleText = getString("GiftPremiumActivateErrorText", R.string.GiftPremiumActivateErrorText); + SpannableStringBuilder subTitleWithLink = AndroidUtilities.replaceSingleTag( + subTitleText, + Theme.key_undo_cancelColor, 0, + share); + BulletinFactory.of(containerLayout, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, + LocaleController.getString("GiftPremiumActivateErrorTitle", R.string.GiftPremiumActivateErrorTitle), + AndroidUtilities.replaceCharSequence("%1$s", subTitleWithLink, replaceTags("**" + formattedDate + "**")) + ).show(); + try { + containerLayout.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + } + } else { + BoostDialogs.showToastError(containerLayout.getContext(), error); + } + } + private static void showBulletin(final BulletinFactory bulletinFactory, Theme.ResourcesProvider resourcesProvider, final TLRPC.Chat chat, final boolean isGiveaway) { AndroidUtilities.runOnUIThread(() -> bulletinFactory.createSimpleBulletin(R.raw.star_premium_2, isGiveaway ? getString("BoostingGiveawayCreated", R.string.BoostingGiveawayCreated) @@ -491,6 +521,11 @@ public class BoostDialogs { stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksText", quantity, from, quantity, months))); stringBuilder.append("\n\n"); + if (giveaway.prize_description != null && !giveaway.prize_description.isEmpty()) { + stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksIncludeText", quantity, from, giveaway.prize_description))); + stringBuilder.append("\n\n"); + } + if (giveaway.only_new_subscribers) { if (isSeveralChats) { String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral2", giveaway.channels.size() - 1, fromTime, fromDate); @@ -536,10 +571,13 @@ public class BoostDialogs { builder.setPositiveButton(getString("OK", R.string.OK), (dialogInterface, i) -> { }); - builder.show(); + applyDialogStyle(builder.show(), false); } public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giveawayInfoResults giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) { + if (giveaway.until_date == 0) { + giveaway.until_date = giveawayInfo.finish_date; + } int quantity = giveaway.quantity; String months = formatPluralString("BoldMonths", giveaway.months); String endDate = LocaleController.getInstance().formatterGiveawayMonthDay.format(new Date(giveaway.until_date * 1000L)); @@ -554,6 +592,11 @@ public class BoostDialogs { stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksTextEnd", quantity, from, quantity, months))); stringBuilder.append("\n\n"); + if (giveaway.prize_description != null && !giveaway.prize_description.isEmpty()) { + stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksIncludeText", quantity, from, giveaway.prize_description))); + stringBuilder.append("\n\n"); + } + if (giveaway.only_new_subscribers) { if (isSeveralChats) { String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral2", giveaway.channels.size() - 1, fromTime, fromDate); @@ -574,28 +617,28 @@ public class BoostDialogs { if (giveawayInfo.activated_count > 0) { stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayUsedLinksPlural", giveawayInfo.activated_count))); } - stringBuilder.append("\n\n"); if (giveawayInfo.refunded) { String str = getString("BoostingGiveawayCanceledByPayment", R.string.BoostingGiveawayCanceledByPayment); TextView bottomTextView = new TextView(context); - bottomTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); - bottomTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + bottomTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); bottomTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); bottomTextView.setGravity(Gravity.CENTER); bottomTextView.setText(str); bottomTextView.setTextColor(Theme.getColor(Theme.key_text_RedRegular, resourcesProvider)); bottomTextView.setBackground(Theme.createRoundRectDrawable(dp(10), dp(10), Theme.multAlpha(Theme.getColor(Theme.key_text_RedRegular, resourcesProvider), 0.1f))); - bottomTextView.setPadding(dp(8), dp(12), dp(8), dp(12)); + bottomTextView.setPadding(dp(12), dp(12), dp(12), dp(12)); builder.addBottomView(bottomTextView); builder.setMessage(stringBuilder); builder.setPositiveButton(getString("Close", R.string.Close), (dialogInterface, i) -> { }); + applyDialogStyle(builder.show(), true); } else { + builder.setMessage(stringBuilder); + String str; if (giveawayInfo.winner) { - stringBuilder.append(getString("BoostingGiveawayYouWon", R.string.BoostingGiveawayYouWon)); - builder.setMessage(stringBuilder); + str = getString("BoostingGiveawayYouWon", R.string.BoostingGiveawayYouWon); builder.setPositiveButton(getString("BoostingGiveawayViewPrize", R.string.BoostingGiveawayViewPrize), (dialogInterface, i) -> { BaseFragment fragment = LaunchActivity.getLastFragment(); if (fragment == null) { @@ -607,15 +650,30 @@ public class BoostDialogs { }); } else { - stringBuilder.append(getString("BoostingGiveawayYouNotWon", R.string.BoostingGiveawayYouNotWon)); - builder.setMessage(stringBuilder); + str = getString("BoostingGiveawayYouNotWon", R.string.BoostingGiveawayYouNotWon); builder.setPositiveButton(getString("Close", R.string.Close), (dialogInterface, i) -> { }); } + EffectsTextView topTextView = new EffectsTextView(context); + NotificationCenter.listenEmojiLoading(topTextView); + topTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + topTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + topTextView.setGravity(Gravity.CENTER); + topTextView.setText(str); + topTextView.setBackground(Theme.createRoundRectDrawable(dp(8), dp(8), Theme.getColor(Theme.key_profile_actionPressedBackground, resourcesProvider))); + topTextView.setPadding(dp(8), dp(8), dp(8), dp(9)); + builder.aboveMessageView(topTextView); + applyDialogStyle(builder.show(), false); } + } - builder.show(); + public static void applyDialogStyle(AlertDialog dialog, boolean defaultMarginTop) { + dialog.setTextSize(20, 14); + dialog.setMessageLineSpacing(2.5f); + if (!defaultMarginTop) { + ((ViewGroup.MarginLayoutParams) dialog.getButtonsLayout().getLayoutParams()).topMargin = AndroidUtilities.dp(-14); + } } public static void showPrivateChannelAlert(Context context, Theme.ResourcesProvider resourcesProvider, Runnable onCanceled, Runnable onAccepted) { @@ -642,7 +700,20 @@ public class BoostDialogs { final AtomicBoolean isCanceled = new AtomicBoolean(false); progress.init(); progress.onCancel(() -> isCanceled.set(true)); - final TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; + + final TLRPC.TL_messageMediaGiveaway giveaway; + if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + TLRPC.TL_messageMediaGiveawayResults giveawayResults = (TLRPC.TL_messageMediaGiveawayResults) messageObject.messageOwner.media; + giveaway = new TLRPC.TL_messageMediaGiveaway(); + giveaway.prize_description = giveawayResults.prize_description; + giveaway.months = giveawayResults.months; + giveaway.quantity = giveawayResults.winners_count + giveawayResults.unclaimed_count; + giveaway.only_new_subscribers = giveawayResults.only_new_subscribers; + giveaway.until_date = giveawayResults.until_date; + } else { + giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; + } + final String fromName = getGiveawayCreatorName(messageObject); final long msgDate = messageObject.messageOwner.date * 1000L; BoostRepository.getGiveawayInfo(messageObject, result -> { @@ -682,11 +753,22 @@ public class BoostDialogs { } public static void showBulletinAbout(MessageObject messageObject) { - if (messageObject == null) { + if (messageObject == null || messageObject.messageOwner == null) { return; } BoostRepository.getGiveawayInfo(messageObject, result -> { - final TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; + final TLRPC.TL_messageMediaGiveaway giveaway; + if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGiveawayResults) { + TLRPC.TL_messageMediaGiveawayResults giveawayResults = (TLRPC.TL_messageMediaGiveawayResults) messageObject.messageOwner.media; + giveaway = new TLRPC.TL_messageMediaGiveaway(); + giveaway.prize_description = giveawayResults.prize_description; + giveaway.months = giveawayResults.months; + giveaway.quantity = giveawayResults.winners_count + giveawayResults.unclaimed_count; + giveaway.only_new_subscribers = giveawayResults.only_new_subscribers; + giveaway.until_date = giveawayResults.until_date; + } else { + giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; + } final long msgDate = messageObject.messageOwner.date * 1000L; BaseFragment fragment = LaunchActivity.getLastFragment(); if (fragment == null) { @@ -729,7 +811,7 @@ public class BoostDialogs { }); } - public static void showMoreBoostsNeeded(long dialogId) { + public static void showMoreBoostsNeeded(long dialogId, BottomSheet bottomSheet) { TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-dialogId); BaseFragment baseFragment = LaunchActivity.getLastFragment(); if (baseFragment == null) { @@ -737,8 +819,12 @@ public class BoostDialogs { } AlertDialog.Builder builder = new AlertDialog.Builder(baseFragment.getContext(), baseFragment.getResourceProvider()); builder.setTitle(LocaleController.getString("BoostingMoreBoostsNeeded", R.string.BoostingMoreBoostsNeeded)); - builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("BoostingGetMoreBoostByGifting", R.string.BoostingGetMoreBoostByGifting, chat.title))); - builder.setPositiveButton(getString("OK", R.string.OK), (dialogInterface, i) -> { + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGetMoreBoostByGiftingCount", BoostRepository.boostsPerSentGift(), chat.title))); + builder.setNegativeButton(getString("GiftPremium", R.string.GiftPremium), (dialogInterface, i) -> { + bottomSheet.dismiss(); + UserSelectorBottomSheet.open(); + }); + builder.setPositiveButton(getString("Close", R.string.Close), (dialogInterface, i) -> { }); builder.show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java index 54e68c61b..59a64747f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java @@ -126,14 +126,18 @@ public class BoostRepository { TLRPC.TL_inputInvoicePremiumGiftCode invoice = new TLRPC.TL_inputInvoicePremiumGiftCode(); TLRPC.TL_inputStorePaymentPremiumGiftCode payload = new TLRPC.TL_inputStorePaymentPremiumGiftCode(); - payload.flags = 1; payload.users = new ArrayList<>(); for (TLObject user : users) { if (user instanceof TLRPC.User) { payload.users.add(controller.getInputUser((TLRPC.User) user)); } } - payload.boost_peer = controller.getInputPeer(-chat.id); + + if (chat != null) { + payload.flags = 1; + payload.boost_peer = controller.getInputPeer(-chat.id); + } + payload.currency = option.currency; payload.amount = option.amount; @@ -182,14 +186,16 @@ public class BoostRepository { ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); TLRPC.TL_inputStorePaymentPremiumGiftCode payload = new TLRPC.TL_inputStorePaymentPremiumGiftCode(); - payload.flags = 1; payload.users = new ArrayList<>(); for (TLObject user : users) { if (user instanceof TLRPC.User) { payload.users.add(controller.getInputUser((TLRPC.User) user)); } } - payload.boost_peer = controller.getInputPeer(-chat.id); + if (chat != null) { + payload.flags = 1; + payload.boost_peer = controller.getInputPeer(-chat.id); + } QueryProductDetailsParams.Product product = QueryProductDetailsParams.Product.newBuilder() .setProductType(BillingClient.ProductType.INAPP) @@ -227,15 +233,22 @@ public class BoostRepository { }); } - public static void launchPreparedGiveaway(TL_stories.TL_prepaidGiveaway prepaidGiveaway, List chats, List selectedCountries, TLRPC.Chat chat, int date, boolean onlyNewSubscribers, Utilities.Callback onSuccess, Utilities.Callback onError) { + public static void launchPreparedGiveaway(TL_stories.TL_prepaidGiveaway prepaidGiveaway, List chats, List selectedCountries, + TLRPC.Chat chat, int date, boolean onlyNewSubscribers, boolean winnersVisible, boolean withAdditionPrize, String prizeDesc, + Utilities.Callback onSuccess, Utilities.Callback onError) { MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); TLRPC.TL_inputStorePaymentPremiumGiveaway purpose = new TLRPC.TL_inputStorePaymentPremiumGiveaway(); purpose.only_new_subscribers = onlyNewSubscribers; + purpose.winners_are_visible = winnersVisible; + purpose.prize_description = prizeDesc; purpose.until_date = date; purpose.flags |= 2; purpose.flags |= 4; + if (withAdditionPrize) { + purpose.flags |= 16; + } purpose.random_id = System.currentTimeMillis(); purpose.additional_peers = new ArrayList<>(); purpose.boost_peer = controller.getInputPeer(-chat.id); @@ -267,15 +280,21 @@ public class BoostRepository { }); } - public static void payGiveAway(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, Utilities.Callback onSuccess, Utilities.Callback onError) { + public static void payGiveAway(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, + TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, + boolean winnersVisible, boolean withAdditionPrize, String prizeDesc, + Utilities.Callback onSuccess, Utilities.Callback onError) { if (!isGoogleBillingAvailable()) { - payGiveAwayByInvoice(chats, selectedCountries, option, chat, date, onlyNewSubscribers, baseFragment, onSuccess, onError); + payGiveAwayByInvoice(chats, selectedCountries, option, chat, date, onlyNewSubscribers, baseFragment, winnersVisible, withAdditionPrize, prizeDesc, onSuccess, onError); } else { - payGiveAwayByGoogle(chats, selectedCountries, option, chat, date, onlyNewSubscribers, baseFragment, onSuccess, onError); + payGiveAwayByGoogle(chats, selectedCountries, option, chat, date, onlyNewSubscribers, baseFragment, winnersVisible, withAdditionPrize, prizeDesc, onSuccess, onError); } } - public static void payGiveAwayByInvoice(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, Utilities.Callback onSuccess, Utilities.Callback onError) { + public static void payGiveAwayByInvoice(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, + TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, + boolean winnersVisible, boolean withAdditionPrize, String prizeDesc, + Utilities.Callback onSuccess, Utilities.Callback onError) { MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); @@ -284,9 +303,14 @@ public class BoostRepository { TLRPC.TL_inputStorePaymentPremiumGiveaway payload = new TLRPC.TL_inputStorePaymentPremiumGiveaway(); payload.only_new_subscribers = onlyNewSubscribers; + payload.winners_are_visible = winnersVisible; + payload.prize_description = prizeDesc; payload.until_date = date; payload.flags |= 2; payload.flags |= 4; + if (withAdditionPrize) { + payload.flags |= 16; + } payload.random_id = System.currentTimeMillis(); payload.additional_peers = new ArrayList<>(); for (TLObject o : chats) { @@ -344,15 +368,23 @@ public class BoostRepository { })); } - public static void payGiveAwayByGoogle(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, Utilities.Callback onSuccess, Utilities.Callback onError) { + public static void payGiveAwayByGoogle(List chats, List selectedCountries, TLRPC.TL_premiumGiftCodeOption option, + TLRPC.Chat chat, int date, boolean onlyNewSubscribers, BaseFragment baseFragment, + boolean winnersVisible, boolean withAdditionPrize, String prizeDesc, + Utilities.Callback onSuccess, Utilities.Callback onError) { MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); TLRPC.TL_inputStorePaymentPremiumGiveaway payload = new TLRPC.TL_inputStorePaymentPremiumGiveaway(); payload.only_new_subscribers = onlyNewSubscribers; + payload.winners_are_visible = winnersVisible; + payload.prize_description = prizeDesc; payload.until_date = date; payload.flags |= 2; payload.flags |= 4; + if (withAdditionPrize) { + payload.flags |= 16; + } payload.random_id = System.currentTimeMillis(); payload.additional_peers = new ArrayList<>(); for (TLObject o : chats) { @@ -420,6 +452,21 @@ public class BoostRepository { return result; } + public static List filterGiftOptionsByBilling(List list) { + if (BoostRepository.isGoogleBillingAvailable()) { + List result = new ArrayList<>(); + for (TLRPC.TL_premiumGiftCodeOption item : list) { + boolean isAvailableInGoogleStore = item.store_product != null; + if (isAvailableInGoogleStore) { + result.add(item); + } + } + return result; + } else { + return list; + } + } + public static void loadCountries(Utilities.Callback>, List>> onDone) { ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); @@ -469,8 +516,10 @@ public class BoostRepository { MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); TLRPC.TL_payments_getPremiumGiftCodeOptions req = new TLRPC.TL_payments_getPremiumGiftCodeOptions(); - req.flags = 1; - req.boost_peer = controller.getInputPeer(-chat.id); + if (chat != null) { + req.flags = 1; + req.boost_peer = controller.getInputPeer(-chat.id); + } int reqId = connection.sendRequest(req, (response, error) -> { if (response != null) { @@ -508,6 +557,35 @@ public class BoostRepository { }); } + public static int searchContacts(int reqId, String query, Utilities.Callback> onDone) { + MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); + ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); + if (reqId != 0) { + connection.cancelRequest(reqId, false); + } + if (query == null || query.isEmpty()) { + AndroidUtilities.runOnUIThread(() -> onDone.run(Collections.emptyList())); + return 0; + } + TLRPC.TL_contacts_search req = new TLRPC.TL_contacts_search(); + req.q = query; + req.limit = 50; + return connection.sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_contacts_found) { + TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; + controller.putUsers(res.users, false); + List result = new ArrayList<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + if (!user.self && !UserObject.isDeleted(user) && !user.bot && !UserObject.isService(user.id)) { + result.add(user); + } + } + AndroidUtilities.runOnUIThread(() -> onDone.run(result)); + } + }); + } + public static void searchChats(long currentChatId, int guid, String query, int count, Utilities.Callback> onDone) { MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); ConnectionsManager connection = ConnectionsManager.getInstance(UserConfig.selectedAccount); @@ -591,7 +669,7 @@ public class BoostRepository { return; } onDone.run(null); - })); + }), ConnectionsManager.RequestFlagFailOnServerErrors); } public static void getGiveawayInfo(MessageObject messageObject, Utilities.Callback onDone, Utilities.Callback onError) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java index 9f89f3fa2..33d178588 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostViaGiftsBottomSheet.java @@ -5,16 +5,16 @@ import android.graphics.Canvas; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -33,6 +33,7 @@ import org.telegram.ui.Components.Premium.boosts.cells.DateEndCell; import org.telegram.ui.Components.Premium.boosts.cells.ParticipantsTypeCell; import org.telegram.ui.Components.Premium.boosts.cells.BoostTypeCell; import org.telegram.ui.Components.Premium.boosts.cells.DurationCell; +import org.telegram.ui.Components.Premium.boosts.cells.SwitcherCell; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.Premium.boosts.adapters.BoostAdapter.Item; @@ -70,6 +71,10 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im private int top; private Runnable onCloseClick; private final TL_stories.TL_prepaidGiveaway prepaidGiveaway; + private String additionalPrize = ""; + private boolean isAdditionalPrizeSelected; + private boolean isShowWinnersSelected = true; + private final Runnable hideKeyboardRunnable = () -> AndroidUtilities.hideKeyboard(recyclerListView); public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolean hasFixedSize, long dialogId, TL_stories.TL_prepaidGiveaway prepaidGiveaway) { super(fragment, needFocus, hasFixedSize); @@ -90,7 +95,36 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, AndroidUtilities.dp(BOTTOM_HEIGHT_DP)); recyclerListView.setItemAnimator(itemAnimator); + recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + AndroidUtilities.hideKeyboard(recyclerView); + } + } + }); recyclerListView.setOnItemClickListener((view, position) -> { + if (view instanceof SwitcherCell) { + SwitcherCell cell = ((SwitcherCell) view); + int type = cell.getType(); + boolean isChecked = !cell.isChecked(); + cell.setChecked(isChecked); + if (type == SwitcherCell.TYPE_WINNERS) { + isShowWinnersSelected = isChecked; + updateRows(false, false); + } else if (type == SwitcherCell.TYPE_ADDITION_PRIZE) { + cell.setDivider(isChecked); + isAdditionalPrizeSelected = isChecked; + updateRows(false, false); + adapter.notifyAdditionalPrizeItem(isChecked); + adapter.notifyAllVisibleTextDividers(); + if (!isAdditionalPrizeSelected) { + AndroidUtilities.runOnUIThread(hideKeyboardRunnable, 250); + } else { + AndroidUtilities.cancelRunOnUIThread(hideKeyboardRunnable); + } + } + } if (view instanceof BaseCell) { if (view instanceof BoostTypeCell) { int boostType = ((BoostTypeCell) view).getSelectedType(); @@ -121,6 +155,7 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im } else if (view instanceof DurationCell) { selectedMonths = ((TLRPC.TL_premiumGiftCodeOption) ((DurationCell) view).getGifCode()).months; updateRows(false, false); + adapter.notifyAllVisibleTextDividers(); } else if (view instanceof DateEndCell) { BoostDialogs.showDatePicker(fragment.getContext(), selectedEndDate, (notify, timeSec) -> { selectedEndDate = timeSec * 1000L; @@ -141,6 +176,10 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im }, deletedChat -> { selectedChats.remove(deletedChat); updateRows(true, true); + }, text -> { + additionalPrize = text; + updateRows(false, false); + updateRows(true, true); }); updateRows(false, false); actionBtn = new ActionBtnCell(getContext(), resourcesProvider); @@ -175,7 +214,7 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im int dateInt = BoostRepository.prepareServerDate(selectedEndDate); boolean onlyNewSubscribers = selectedParticipantsType == ParticipantsTypeCell.TYPE_NEW; actionBtn.updateLoading(true); - BoostRepository.launchPreparedGiveaway(prepaidGiveaway, selectedChats, selectedCountries, currentChat, dateInt, onlyNewSubscribers, + BoostRepository.launchPreparedGiveaway(prepaidGiveaway, selectedChats, selectedCountries, currentChat, dateInt, onlyNewSubscribers, isShowWinnersSelected, isAdditionalPrizeSelected, additionalPrize, result -> { dismiss(); AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(UserConfig.selectedAccount).postNotificationName(NotificationCenter.boostByChannelCreated, currentChat, true, prepaidGiveaway), 220); @@ -198,7 +237,7 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im boolean onlyNewSubscribers = selectedParticipantsType == ParticipantsTypeCell.TYPE_NEW; int dateInt = BoostRepository.prepareServerDate(selectedEndDate); actionBtn.updateLoading(true); - BoostRepository.payGiveAway(selectedChats, selectedCountries, option, currentChat, dateInt, onlyNewSubscribers, fragment, result -> { + BoostRepository.payGiveAway(selectedChats, selectedCountries, option, currentChat, dateInt, onlyNewSubscribers, fragment, isShowWinnersSelected, isAdditionalPrizeSelected, additionalPrize, result -> { dismiss(); AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(UserConfig.selectedAccount).postNotificationName(NotificationCenter.boostByChannelCreated, currentChat, true), 220); }, error -> { @@ -321,11 +360,6 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im items.add(Item.asParticipants(ParticipantsTypeCell.TYPE_ALL, selectedParticipantsType, true, selectedCountries)); items.add(Item.asParticipants(ParticipantsTypeCell.TYPE_NEW, selectedParticipantsType, false, selectedCountries)); items.add(Item.asDivider(LocaleController.getString("BoostingChooseLimitGiveaway", R.string.BoostingChooseLimitGiveaway), false)); - items.add(Item.asSubTitle(LocaleController.getString("BoostingDateWhenGiveawayEnds", R.string.BoostingDateWhenGiveawayEnds))); - items.add(Item.asDateEnd(selectedEndDate)); - if (!isPreparedGiveaway()) { - items.add(Item.asDivider(LocaleController.formatPluralString("BoostingChooseRandom", getSelectedSliderValue()), false)); - } } if (!isPreparedGiveaway()) { @@ -336,17 +370,56 @@ public class BoostViaGiftsBottomSheet extends BottomSheetWithRecyclerListView im items.add(Item.asDuration(option, option.months, isGiveaway() ? getSelectedSliderValue() : selectedUsers.size(), option.amount, selectedMonths, option.currency, i != options.size() - 1)); } } - String textDivider = !isPreparedGiveaway() ? LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms) - : LocaleController.formatPluralString("BoostingChooseRandom", prepaidGiveaway.quantity) + "\n\n" + LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms); - items.add(Item.asDivider(AndroidUtilities.replaceSingleTag( - textDivider, - Theme.key_chat_messageLinkIn, 0, () -> { - PremiumPreviewBottomSheet previewBottomSheet = new PremiumPreviewBottomSheet(getBaseFragment(), currentAccount, null, resourcesProvider); - previewBottomSheet.setOnDismissListener(dialog -> adapter.setPausedStars(false)); - previewBottomSheet.setOnShowListener(dialog -> adapter.setPausedStars(true)); - previewBottomSheet.show(); - }, - resourcesProvider), true)); + + if (!isPreparedGiveaway()) { + items.add(Item.asDivider(AndroidUtilities.replaceSingleTag( + LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms), + Theme.key_chat_messageLinkIn, 0, () -> { + PremiumPreviewBottomSheet previewBottomSheet = new PremiumPreviewBottomSheet(getBaseFragment(), currentAccount, null, resourcesProvider); + previewBottomSheet.setOnDismissListener(dialog -> adapter.setPausedStars(false)); + previewBottomSheet.setOnShowListener(dialog -> adapter.setPausedStars(true)); + previewBottomSheet.show(); + }, + resourcesProvider), true)); + } + + if (selectedBoostType == BoostTypeCell.TYPE_GIVEAWAY) { + items.add(Item.asSwitcher(LocaleController.getString("BoostingGiveawayAdditionalPrizes", R.string.BoostingGiveawayAdditionalPrizes), isAdditionalPrizeSelected, isAdditionalPrizeSelected, SwitcherCell.TYPE_ADDITION_PRIZE)); + + if (isAdditionalPrizeSelected) { + int quantity = isPreparedGiveaway() ? prepaidGiveaway.quantity : getSelectedSliderValue(); + items.add(Item.asEnterPrize(quantity)); + String months = LocaleController.formatPluralString("BoldMonths", selectedMonths); + if (additionalPrize.isEmpty()) { + items.add(Item.asDivider(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGiveawayAdditionPrizeCountHint", quantity, months)), false)); + } else { + items.add(Item.asDivider(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGiveawayAdditionPrizeCountNameHint", quantity, additionalPrize, months)), false)); + } + } else { + items.add(Item.asDivider(LocaleController.getString("BoostingGiveawayAdditionPrizeHint", R.string.BoostingGiveawayAdditionPrizeHint), false)); + } + + items.add(Item.asSwitcher(LocaleController.getString("BoostingGiveawayShowWinners", R.string.BoostingGiveawayShowWinners), isShowWinnersSelected, false, SwitcherCell.TYPE_WINNERS)); + items.add(Item.asDivider(LocaleController.getString("BoostingGiveawayShowWinnersHint", R.string.BoostingGiveawayShowWinnersHint), false)); + + items.add(Item.asSubTitle(LocaleController.getString("BoostingDateWhenGiveawayEnds", R.string.BoostingDateWhenGiveawayEnds))); + items.add(Item.asDateEnd(selectedEndDate)); + + if (!isPreparedGiveaway()) { + items.add(Item.asDivider(LocaleController.formatPluralString("BoostingChooseRandom", getSelectedSliderValue()), false)); + } else { + items.add(Item.asDivider(AndroidUtilities.replaceSingleTag( + LocaleController.formatPluralString("BoostingChooseRandom", prepaidGiveaway.quantity) + "\n\n" + LocaleController.getString("BoostingStoriesFeaturesAndTerms", R.string.BoostingStoriesFeaturesAndTerms), + Theme.key_chat_messageLinkIn, 0, () -> { + PremiumPreviewBottomSheet previewBottomSheet = new PremiumPreviewBottomSheet(getBaseFragment(), currentAccount, null, resourcesProvider); + previewBottomSheet.setOnDismissListener(dialog -> adapter.setPausedStars(false)); + previewBottomSheet.setOnShowListener(dialog -> adapter.setPausedStars(true)); + previewBottomSheet.show(); + }, + resourcesProvider), true)); + } + } + if (adapter == null) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java new file mode 100644 index 000000000..00a72c9f3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/DiscountSpan.java @@ -0,0 +1,84 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ReplacementSpan; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; + +public class DiscountSpan extends ReplacementSpan { + + public static CharSequence applySpan(CharSequence str, int discount) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d "); + spannableStringBuilder.append(str); + DiscountSpan span = new DiscountSpan(11, discount); + span.setColor(Theme.getColor(Theme.key_premiumGradient1)); + spannableStringBuilder.setSpan(span, 0, 1, 0); + return spannableStringBuilder; + } + + TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + StaticLayout layout; + float width, height; + int discount; + private int color; + + public DiscountSpan(float textSize, int discount) { + textPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + bgPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(dp(textSize)); + this.discount = discount; + } + + public void setColor(int color) { + this.color = color; + } + + public void makeLayout() { + if (layout == null) { + layout = new StaticLayout(LocaleController.formatString(R.string.GiftPremiumOptionDiscount, discount), textPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 1, 0, false); + width = layout.getLineWidth(0); + height = layout.getHeight(); + } + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + makeLayout(); + return (int) (dp(13) + width); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float _x, int top, int _y, int bottom, @NonNull Paint paint) { + makeLayout(); + int color = this.color; + if (color == 0) { + color = paint.getColor(); + } + bgPaint.setColor(color); + textPaint.setColor(AndroidUtilities.computePerceivedBrightness(color) > .721f ? Color.BLACK : Color.WHITE); + float x = _x + dp(6), y = _y - height + dp(2f); + AndroidUtilities.rectTmp.set(x, y, x + width, y + height); + float r = dp(4f); + AndroidUtilities.rectTmp.inset(dp(-4.5f), dp(-1.66f)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, bgPaint); + canvas.save(); + canvas.translate(x, y); + layout.draw(canvas); + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java index d9540ae32..f5ef0d54c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java @@ -44,8 +44,23 @@ public class GiftInfoBottomSheet extends BottomSheetWithRecyclerListView { if (fragment.getParentActivity() == null) { return; } - GiftInfoBottomSheet alert = new GiftInfoBottomSheet(fragment, false, true, giftCode, slug); - fragment.showDialog(alert); + + if (giftCode.from_id == null) { + TLRPC.TL_premiumGiftOption giftOption = new TLRPC.TL_premiumGiftOption(); + giftOption.months = giftCode.months; + TLRPC.User user = null; + if (fragment instanceof ChatActivity) { + user = ((ChatActivity) fragment).getCurrentUser(); + } + if (user == null || user.self) { + user = new TLRPC.TL_user(); + } + boolean isUsed = giftCode.used_date != 0; + PremiumPreviewGiftLinkBottomSheet.show(slug, giftOption, user, isUsed); + } else { + fragment.showDialog(new GiftInfoBottomSheet(fragment, false, true, giftCode, slug)); + } + if (progress != null) { progress.end(); } @@ -110,7 +125,7 @@ public class GiftInfoBottomSheet extends BottomSheetWithRecyclerListView { setApplyBottomPadding(false); fixNavigationBar(); updateTitle(); - adapter.init(fragment, giftCode, slug); + adapter.init(fragment, giftCode, slug, container); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GradientButtonWithCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GradientButtonWithCounterView.java new file mode 100644 index 000000000..cd82c3896 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GradientButtonWithCounterView.java @@ -0,0 +1,53 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.RectF; + +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Premium.PremiumGradient; +import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +@SuppressLint("ViewConstructor") +public class GradientButtonWithCounterView extends ButtonWithCounterView { + + private final RectF rect = new RectF(); + private boolean incGradient; + private float progress; + private final CellFlickerDrawable flickerDrawable; + + public GradientButtonWithCounterView(Context context, boolean filled, Theme.ResourcesProvider resourcesProvider) { + super(context, filled, resourcesProvider); + flickerDrawable = new CellFlickerDrawable(); + flickerDrawable.animationSpeedScale = 1.2f; + flickerDrawable.drawFrame = false; + flickerDrawable.repeatProgress = 4f; + } + + @Override + protected void onDraw(Canvas canvas) { + if (incGradient) { + progress += 16f / 1000f; + if (progress > 3) { + incGradient = false; + } + } else { + progress -= 16f / 1000f; + if (progress < 1) { + incGradient = true; + } + } + + rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); + canvas.drawRoundRect(rect, dp(8), dp(8), PremiumGradient.getInstance().getMainGradientPaint()); + flickerDrawable.setParentWidth(getMeasuredWidth()); + flickerDrawable.draw(canvas, rect, dp(8), null); + super.onDraw(canvas); + invalidate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftLinkBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftLinkBottomSheet.java new file mode 100644 index 000000000..262722dc4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftLinkBottomSheet.java @@ -0,0 +1,170 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.getString; + +import android.content.Context; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.SendMessagesHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; +import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; +import org.telegram.ui.Components.Premium.boosts.cells.ActionBtnCell; +import org.telegram.ui.Components.Premium.boosts.cells.LinkCell; +import org.telegram.ui.DialogsActivity; +import org.telegram.ui.LaunchActivity; + +public class PremiumPreviewGiftLinkBottomSheet extends PremiumPreviewBottomSheet { + private static final int BOTTOM_HEIGHT_DP = 68; + private static final int CELL_TYPE_LINK = 6; + private static PremiumPreviewGiftLinkBottomSheet instance; + + private ActionBtnCell actionBtn; + private final String slug; + private final boolean isUsed; + + public static void show(String slug, TLRPC.TL_premiumGiftOption giftOption, TLRPC.User user, Browser.Progress progress) { + GiftInfoBottomSheet.show(LaunchActivity.getLastFragment(), slug, progress); + } + + public static void show(String slug, TLRPC.TL_premiumGiftOption giftOption, TLRPC.User user, boolean isUsed) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null || instance != null) { + return; + } + GiftPremiumBottomSheet.GiftTier tier = new GiftPremiumBottomSheet.GiftTier(giftOption); + PremiumPreviewGiftLinkBottomSheet sheet = new PremiumPreviewGiftLinkBottomSheet(fragment, UserConfig.selectedAccount, user, tier, slug, isUsed, fragment.getResourceProvider()); + sheet.show(); + instance = sheet; + } + + public PremiumPreviewGiftLinkBottomSheet(BaseFragment fragment, int currentAccount, TLRPC.User user, GiftPremiumBottomSheet.GiftTier gift, String slug, boolean isUsed, Theme.ResourcesProvider resourcesProvider) { + super(fragment, currentAccount, user, gift, resourcesProvider); + this.slug = slug; + this.isUsed = isUsed; + init(); + } + + @Override + protected void updateRows() { + paddingRow = rowCount++; + additionStartRow = rowCount; + additionEndRow = ++rowCount; + featuresStartRow = rowCount; + rowCount += premiumFeatures.size(); + featuresEndRow = rowCount; + sectionRow = rowCount++; + } + + @Override + public void setTitle(boolean animated) { + super.setTitle(animated); + subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1f); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).bottomMargin = dp(14); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).topMargin = dp(12); + String subTitleText = getString("GiftPremiumAboutThisLink", R.string.GiftPremiumAboutThisLink); + SpannableStringBuilder subTitleWithLink = AndroidUtilities.replaceSingleTag( + subTitleText, + Theme.key_chat_messageLinkIn, 0, + this::share); + subtitleView.setText(AndroidUtilities.replaceCharSequence("%1$s", subTitleWithLink, replaceTags(getString("GiftPremiumAboutThisLinkEnd", R.string.GiftPremiumAboutThisLinkEnd)))); + } + + private void share() { + final String slugLink = "https://t.me/giftcode/" + slug; + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); + DialogsActivity dialogFragment = new DialogsActivity(args); + dialogFragment.setDelegate((fragment1, dids, message, param, topicsFragment) -> { + long did = 0; + for (int a = 0; a < dids.size(); a++) { + did = dids.get(a).dialogId; + getBaseFragment().getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(slugLink, did, null, null, null, true, null, null, null, true, 0, null, false)); + } + fragment1.finishFragment(); + BoostDialogs.showGiftLinkForwardedBulletin(did); + return true; + }); + getBaseFragment().presentFragment(dialogFragment); + dismiss(); + } + + @Override + protected View onCreateAdditionCell(int viewType, Context context) { + if (viewType == CELL_TYPE_LINK) { + LinkCell cell = new LinkCell(context, getBaseFragment(), resourcesProvider); + cell.setPadding(0, 0, 0, dp(8)); + return cell; + } + return null; + } + + @Override + protected void onBindAdditionCell(View view, int pos) { + ((LinkCell) view).setSlug(slug); + } + + @Override + protected int getAdditionItemViewType(int position) { + return CELL_TYPE_LINK; + } + + private void init() { + Bulletin.addDelegate((FrameLayout) containerView, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return dp(BOTTOM_HEIGHT_DP); + } + }); + if (!isUsed) { + recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, dp(BOTTOM_HEIGHT_DP)); + actionBtn = new ActionBtnCell(getContext(), resourcesProvider); + actionBtn.setOnClickListener(v -> { + if (actionBtn.isLoading()) { + return; + } + actionBtn.updateLoading(true); + BoostRepository.applyGiftCode(slug, result -> { + actionBtn.updateLoading(false); + dismiss(); + AndroidUtilities.runOnUIThread(() -> { + PremiumPreviewBottomSheet previewBottomSheet = new PremiumPreviewBottomSheet(getBaseFragment(), UserConfig.selectedAccount, null, null, resourcesProvider) + .setAnimateConfetti(true) + .setAnimateConfettiWithStars(true) + .setOutboundGift(true); + getBaseFragment().showDialog(previewBottomSheet); + }, 200); + }, error -> { + actionBtn.updateLoading(false); + BoostDialogs.processApplyGiftCodeError(error, (FrameLayout) containerView, resourcesProvider, this::share); + }); + }); + actionBtn.setActivateForFreeStyle(); + containerView.addView(actionBtn, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, BOTTOM_HEIGHT_DP, Gravity.BOTTOM, 0, 0, 0, 0)); + } + fixNavigationBar(); + } + + @Override + public void dismissInternal() { + super.dismissInternal(); + instance = null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftSentBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftSentBottomSheet.java new file mode 100644 index 000000000..69f34c6f9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftSentBottomSheet.java @@ -0,0 +1,158 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getPluralString; +import static org.telegram.messenger.LocaleController.getString; + +import android.graphics.Outline; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.LinearLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; +import org.telegram.ui.Components.Premium.boosts.cells.ActionBtnCell; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; +import java.util.List; + +public class PremiumPreviewGiftSentBottomSheet extends PremiumPreviewBottomSheet { + private static final int BOTTOM_HEIGHT_DP = 64; + + private final List selectedUsers = new ArrayList<>(); + + public static void show(List selectedUsers) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null) { + return; + } + PremiumPreviewGiftSentBottomSheet sheet = new PremiumPreviewGiftSentBottomSheet(fragment, UserConfig.selectedAccount, selectedUsers, fragment.getResourceProvider()); + sheet.setAnimateConfetti(true); + sheet.setAnimateConfettiWithStars(true); + sheet.show(); + } + + public PremiumPreviewGiftSentBottomSheet(BaseFragment fragment, int currentAccount, List selectedUsers, Theme.ResourcesProvider resourcesProvider) { + super(fragment, currentAccount, null, null, resourcesProvider); + this.selectedUsers.addAll(selectedUsers); + init(); + } + + @Override + protected boolean needDefaultPremiumBtn() { + return false; + } + + @Override + protected void updateRows() { + rowCount = 0; + paddingRow = rowCount++; + featuresStartRow = rowCount; + rowCount += premiumFeatures.size(); + featuresEndRow = rowCount; + termsRow = rowCount++; + } + + @Override + public void setTitle(boolean animated) { + titleView[0].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + subtitleView.setPadding(dp(30), 0, dp(30), 0); + subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1f); + titleView[0].setText(getPluralString("GiftPremiumGiftsSent", selectedUsers.size())); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).bottomMargin = dp(16); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).topMargin = dp(4f); + + String subTitle; + switch (selectedUsers.size()) { + case 1: { + String names = formatString("GiftPremiumUsersOne", R.string.GiftPremiumUsersOne, UserObject.getFirstName(selectedUsers.get(0))); + subTitle = formatString("GiftPremiumUsersPurchasedManyZero", R.string.GiftPremiumUsersPurchasedManyZero, names); + break; + } + case 2: { + String names = formatString("GiftPremiumUsersTwo", R.string.GiftPremiumUsersTwo, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1))); + subTitle = formatString("GiftPremiumUsersPurchasedManyZero", R.string.GiftPremiumUsersPurchasedManyZero, names); + break; + } + case 3: { + String names = formatString("GiftPremiumUsersThree", R.string.GiftPremiumUsersThree, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1)), UserObject.getFirstName(selectedUsers.get(2))); + subTitle = formatString("GiftPremiumUsersPurchasedManyZero", R.string.GiftPremiumUsersPurchasedManyZero, names); + break; + } + default: { + String names = formatString("GiftPremiumUsersThree", R.string.GiftPremiumUsersThree, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1)), UserObject.getFirstName(selectedUsers.get(2))); + subTitle = formatPluralString("GiftPremiumUsersPurchasedMany", selectedUsers.size() - 3, names); + break; + } + } + subtitleView.setText(replaceTags(subTitle)); + + subtitleView.append("\n"); + subtitleView.append("\n"); + + if (selectedUsers.size() == 1) { + subtitleView.append(replaceTags(formatString("GiftPremiumGiftsSentStatusForUser", R.string.GiftPremiumGiftsSentStatusForUser, UserObject.getFirstName(selectedUsers.get(0))))); + } else { + subtitleView.append(replaceTags(getString("GiftPremiumGiftsSentStatus", R.string.GiftPremiumGiftsSentStatus))); + } + } + + private void init() { + updateRows(); + useBackgroundTopPadding = false; + setApplyTopPadding(false); + backgroundPaddingTop = 0; + ActionBtnCell actionBtn = new ActionBtnCell(getContext(), resourcesProvider); + actionBtn.setOnClickListener(v -> dismiss()); + actionBtn.setCloseStyle(true); + containerView.addView(actionBtn, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, BOTTOM_HEIGHT_DP, Gravity.BOTTOM, 0, 0, 0, 0)); + + recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, dp(BOTTOM_HEIGHT_DP)); + overrideTitleIcon = PremiumPreviewGiftToUsersBottomSheet.AvatarHolderView.createAvatarsContainer(getContext(), selectedUsers); + fixNavigationBar(); + } + + protected void afterCellCreated(int viewType, View view) { + if (viewType == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + view.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + float cornerRadius = AndroidUtilities.dp(12); + outline.setRoundRect(0, 0, view.getWidth(), (int) (view.getHeight() + cornerRadius), cornerRadius); + } + }); + view.setClipToOutline(true); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); + } + ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin = -dp(6); + } + } + + @Override + protected void attachIconContainer(LinearLayout container) { + container.addView(overrideTitleIcon, LayoutHelper.createLinear( + LayoutHelper.MATCH_PARENT, + selectedUsers.size() == 1 ? 94 : 83, + 0, + selectedUsers.size() == 1 ? 28 : 34, + 0, + selectedUsers.size() == 1 ? 9 : 14) + ); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftToUsersBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftToUsersBottomSheet.java new file mode 100644 index 000000000..eb584bf3e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/PremiumPreviewGiftToUsersBottomSheet.java @@ -0,0 +1,402 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.formatString; +import static org.telegram.messenger.LocaleController.getString; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Paint; +import android.os.Build; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BillingController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumGradient; +import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; +import org.telegram.ui.Components.Premium.StarParticlesView; +import org.telegram.ui.Components.Premium.boosts.cells.DurationWithDiscountCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorBtnCell; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class PremiumPreviewGiftToUsersBottomSheet extends PremiumPreviewBottomSheet { + private static final int BOTTOM_HEIGHT_DP = 64; + private static final int CELL_TYPE_HEADER = 6, + CELL_TYPE_SHADOW = 7, + CELL_TYPE_DURATION = 8; + + private GradientButtonWithCounterView actionBtn; + private SelectorBtnCell buttonContainer; + private final List selectedUsers = new ArrayList<>(); + private final List giftCodeOptions = new ArrayList<>(); + private int selectedMonths = 3; + + public static void show(List selectedUsers, List giftCodeOptions) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null) { + return; + } + new PremiumPreviewGiftToUsersBottomSheet(fragment, UserConfig.selectedAccount, selectedUsers, giftCodeOptions, fragment.getResourceProvider()).show(); + } + + public PremiumPreviewGiftToUsersBottomSheet(BaseFragment fragment, int currentAccount, List selectedUsers, List giftCodeOptions, Theme.ResourcesProvider resourcesProvider) { + super(fragment, currentAccount, null, null, resourcesProvider); + this.selectedUsers.addAll(selectedUsers); + this.giftCodeOptions.addAll(giftCodeOptions); + Collections.sort(giftCodeOptions, Comparator.comparingLong(o -> o.amount)); + init(); + } + + @Override + protected boolean needDefaultPremiumBtn() { + return false; + } + + @Override + protected void updateRows() { + rowCount = 0; + paddingRow = rowCount++; + additionStartRow = rowCount; + rowCount += (giftCodeOptions != null ? giftCodeOptions.size() : 0) + 2; + additionEndRow = rowCount; + featuresStartRow = rowCount; + rowCount += premiumFeatures.size(); + featuresEndRow = rowCount; + termsRow = rowCount++; + } + + @Override + public void setTitle(boolean animated) { + titleView[0].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + subtitleView.setPadding(dp(30), 0, dp(30), 0); + subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1f); + titleView[0].setText(getString("GiftTelegramPremiumTitle", R.string.GiftTelegramPremiumTitle)); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).bottomMargin = dp(16); + ((ViewGroup.MarginLayoutParams) subtitleView.getLayoutParams()).topMargin = dp(4f); + + String subTitle; + switch (selectedUsers.size()) { + case 1: { + String names = formatString("GiftPremiumUsersOne", R.string.GiftPremiumUsersOne, UserObject.getFirstName(selectedUsers.get(0))); + subTitle = formatString("GiftPremiumUsersGiveAccessManyZero", R.string.GiftPremiumUsersGiveAccessManyZero, names); + break; + } + case 2: { + String names = formatString("GiftPremiumUsersTwo", R.string.GiftPremiumUsersTwo, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1))); + subTitle = formatString("GiftPremiumUsersGiveAccessManyZero", R.string.GiftPremiumUsersGiveAccessManyZero, names); + break; + } + case 3: { + String names = formatString("GiftPremiumUsersThree", R.string.GiftPremiumUsersThree, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1)), UserObject.getFirstName(selectedUsers.get(2))); + subTitle = formatString("GiftPremiumUsersGiveAccessManyZero", R.string.GiftPremiumUsersGiveAccessManyZero, names); + break; + } + default: { + String names = formatString("GiftPremiumUsersThree", R.string.GiftPremiumUsersThree, UserObject.getFirstName(selectedUsers.get(0)), UserObject.getFirstName(selectedUsers.get(1)), UserObject.getFirstName(selectedUsers.get(2))); + subTitle = formatPluralString("GiftPremiumUsersGiveAccessMany", selectedUsers.size() - 3, names); + break; + } + } + subtitleView.setText(replaceTags(subTitle)); + + subtitleView.append("\n"); + subtitleView.append("\n"); + CharSequence boostInfo = replaceTags(formatPluralString("GiftPremiumWillReceiveBoostsPlural", selectedUsers.size() * BoostRepository.boostsPerSentGift())); + SpannableStringBuilder boostInfoSpannableBuilder = new SpannableStringBuilder(boostInfo); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_boost_button); + span.setSize(dp(20)); + span.setWidth(dp(11)); + span.setTranslateX(-dp(4)); + span.setTranslateY(-dp(1)); + span.setColorKey(Theme.key_windowBackgroundWhiteBlueText4); + String lightning = "⚡"; + int lightningIndex = TextUtils.indexOf(boostInfo, lightning); + if (lightningIndex >= 0) { + boostInfoSpannableBuilder.setSpan(span, lightningIndex, lightningIndex + lightning.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + subtitleView.append(boostInfoSpannableBuilder); + } + + @Override + protected View onCreateAdditionCell(int viewType, Context context) { + switch (viewType) { + case CELL_TYPE_HEADER: { + HeaderCell cell = new HeaderCell(context,Theme.key_windowBackgroundWhiteBlueHeader, 21, 12, false, resourcesProvider); + cell.setTextSize(15); + cell.setPadding(0, 0, 0, dp(2)); + cell.setText(getString("GiftPremiumWhatsIncluded", R.string.GiftPremiumWhatsIncluded)); + return cell; + } + case CELL_TYPE_SHADOW: { + return new ShadowSectionCell(context, 12, Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); + } + case CELL_TYPE_DURATION: { + return new DurationWithDiscountCell(context, resourcesProvider); + } + default: + return null; + } + } + + @Override + protected void onAdditionItemClicked(View view) { + if (view instanceof DurationWithDiscountCell) { + DurationWithDiscountCell cell = ((DurationWithDiscountCell) view); + selectedMonths = cell.getOption().months; + cell.markChecked(recyclerListView); + updateActionButton(true); + } + } + + @Override + protected boolean isAdditionViewClickable(int viewType) { + return viewType == 8; + } + + @Override + protected void onBindAdditionCell(View view, int pos) { + if (view instanceof DurationWithDiscountCell) { + pos = pos - 1; + TLRPC.TL_premiumGiftCodeOption option = giftCodeOptions.get(pos); + ((DurationWithDiscountCell) view).setDuration(option, giftCodeOptions.get(giftCodeOptions.size() - 1), selectedUsers.size(), pos != giftCodeOptions.size() - 1, selectedMonths == option.months); + } + } + + @Override + protected int getAdditionItemViewType(int position) { + if (position <= giftCodeOptions.size()) { + return CELL_TYPE_DURATION; + } else if (position == giftCodeOptions.size() + 1) { + return CELL_TYPE_SHADOW; + } else if (position == giftCodeOptions.size() + 2) { + return CELL_TYPE_HEADER; + } + return 0; + } + + private TLRPC.TL_premiumGiftCodeOption getSelectedOption() { + for (TLRPC.TL_premiumGiftCodeOption giftCodeOption : giftCodeOptions) { + if (giftCodeOption.months == selectedMonths) { + return giftCodeOption; + } + } + return giftCodeOptions.get(0); + } + + private void updateActionButton(boolean animated) { + TLRPC.TL_premiumGiftCodeOption giftCodeOption = getSelectedOption(); + String priceStr = BillingController.getInstance().formatCurrency(giftCodeOption.amount, giftCodeOption.currency); + if (selectedUsers.size() == 1) { + actionBtn.setText(formatString("GiftSubscriptionFor", R.string.GiftSubscriptionFor, priceStr), animated); + } else { + actionBtn.setText(formatPluralString("GiftSubscriptionCountFor", selectedUsers.size(), priceStr), animated); + } + } + + private void chooseMaxSelectedMonths() { + for (TLRPC.TL_premiumGiftCodeOption giftCodeOption : giftCodeOptions) { + selectedMonths = Math.max(giftCodeOption.months, selectedMonths); + } + } + + private void init() { + chooseMaxSelectedMonths(); + updateRows(); + useBackgroundTopPadding = false; + setApplyTopPadding(false); + backgroundPaddingTop = 0; + recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, dp(BOTTOM_HEIGHT_DP)); + + buttonContainer = new SelectorBtnCell(getContext(), resourcesProvider, recyclerListView); + buttonContainer.setClickable(true); + buttonContainer.setOrientation(LinearLayout.VERTICAL); + buttonContainer.setPadding(dp(8), dp(8), dp(8), dp(8)); + buttonContainer.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + actionBtn = new GradientButtonWithCounterView(getContext(), true, resourcesProvider); + actionBtn.setOnClickListener(v -> { + if (actionBtn.isLoading()) { + return; + } + actionBtn.setLoading(true); + BoostRepository.payGiftCode(new ArrayList<>(selectedUsers), getSelectedOption(), null, getBaseFragment(), result -> { + dismiss(); + NotificationCenter.getInstance(UserConfig.selectedAccount).postNotificationName(NotificationCenter.giftsToUserSent); + AndroidUtilities.runOnUIThread(() -> PremiumPreviewGiftSentBottomSheet.show(selectedUsers), 250); + }, error -> { + actionBtn.setLoading(false); + BoostDialogs.showToastError(getContext(), error); + }); + }); + buttonContainer.addView(actionBtn, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); + containerView.addView(buttonContainer, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + + overrideTitleIcon = AvatarHolderView.createAvatarsContainer(getContext(), selectedUsers); + updateActionButton(false); + fixNavigationBar(); + } + + protected void afterCellCreated(int viewType, View view) { + if (viewType == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + view.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + float cornerRadius = AndroidUtilities.dp(12); + outline.setRoundRect(0, 0, view.getWidth(), (int) (view.getHeight() + cornerRadius), cornerRadius); + } + }); + view.setClipToOutline(true); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); + } + ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin = -dp(6); + } + } + + @Override + protected void attachIconContainer(LinearLayout container) { + container.addView(overrideTitleIcon, LayoutHelper.createLinear( + LayoutHelper.MATCH_PARENT, + selectedUsers.size() == 1 ? 94 : 83, + 0, + selectedUsers.size() == 1 ? 28 : 34, + 0, + selectedUsers.size() == 1 ? 9 : 14) + ); + } + + @SuppressLint("ViewConstructor") + static class AvatarHolderView extends FrameLayout { + + public static View createAvatarsContainer(Context context, List selectedUsers) { + FrameLayout avatarsContainer = new FrameLayout(context); + avatarsContainer.setClipChildren(false); + FrameLayout avatarsWrapper = new FrameLayout(context); + avatarsWrapper.setClipChildren(false); + + if (selectedUsers.size() == 1) { + avatarsContainer.addView(avatarsWrapper, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 94, 0, 0, 0, 0, 0)); + PremiumPreviewGiftToUsersBottomSheet.AvatarHolderView avatarHolderView = new PremiumPreviewGiftToUsersBottomSheet.AvatarHolderView(context, 47); + avatarHolderView.drawCycle = false; + avatarHolderView.setUser(selectedUsers.get(0)); + avatarsWrapper.addView(avatarHolderView, 0, LayoutHelper.createFrame(94, 94, Gravity.CENTER)); + } else { + avatarsContainer.addView(avatarsWrapper, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 83, 0, 0, 0, 0, 0)); + int visibleCount = 0; + for (int i = 0; i < selectedUsers.size(); i++) { + TLRPC.User user = selectedUsers.get(i); + PremiumPreviewGiftToUsersBottomSheet.AvatarHolderView avatarHolderView = new PremiumPreviewGiftToUsersBottomSheet.AvatarHolderView(context, 41.5f); + avatarHolderView.setUser(user); + avatarsWrapper.addView(avatarHolderView, 0, LayoutHelper.createFrame(83, 83, Gravity.CENTER)); + avatarHolderView.setTranslationX(-i * dp(29)); + if (i == 0 && selectedUsers.size() > 3) { + avatarHolderView.iconView.setAlpha(1f); + avatarHolderView.iconView.count = selectedUsers.size() - 3; + } + visibleCount++; + if (i == 2) { + break; + } + } + avatarsContainer.setTranslationX(dp(29 / 2f) * (visibleCount - 1)); + } + return avatarsContainer; + } + + private final BackupImageView imageView; + protected final AdditionalCounterView iconView; + private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public TLRPC.User user; + public boolean drawCycle = true; + AvatarDrawable fromAvatarDrawable = new AvatarDrawable(); + + public AvatarHolderView(Context context, float radiusDp) { + super(context); + imageView = new BackupImageView(getContext()); + imageView.setRoundRadius(AndroidUtilities.dp(radiusDp)); + iconView = new AdditionalCounterView(context); + iconView.setAlpha(0f); + addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 5, 5, 5, 5)); + addView(iconView, LayoutHelper.createFrame(26, 26, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 1, 3)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + bgPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray)); + } else { + bgPaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + } + } + + public void setUser(TLRPC.User user) { + this.user = user; + fromAvatarDrawable.setInfo(user); + imageView.setForUserOrChat(user, fromAvatarDrawable); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (drawCycle) { + canvas.drawCircle(getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, (getMeasuredHeight() / 2f) - dp(2f), bgPaint); + } + super.dispatchDraw(canvas); + } + } + + static class AdditionalCounterView extends View { + + TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + int count; + + public AdditionalCounterView(Context context) { + super(context); + paint.setTextAlign(Paint.Align.CENTER); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + paint.setColor(Theme.getColor(Theme.key_windowBackgroundGray)); + } else { + paint.setColor(Theme.getColor(Theme.key_dialogBackground)); + } + paint.setTextSize(dp(11.5f)); + paint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + + @Override + protected void onDraw(Canvas canvas) { + float cx = getMeasuredWidth() / 2f; + float cy = getMeasuredHeight() / 2f; + canvas.drawCircle(cx, cy, getMeasuredWidth() / 2f, paint); + PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -AndroidUtilities.dp(10), 0); + canvas.drawCircle(cx, cy, getMeasuredWidth() / 2f - AndroidUtilities.dp(1.5f), PremiumGradient.getInstance().getMainGradientPaint()); + cy = (int) (cy - ((paint.descent() + paint.ascent()) / 2f)); + canvas.drawText("+" + count, cx, cy, paint); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java index 5f8601061..87268ccb8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java @@ -1,16 +1,18 @@ package org.telegram.ui.Components.Premium.boosts; +import static org.telegram.messenger.AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.LocaleController.getString; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.CountDownTimer; import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -26,6 +28,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; @@ -34,6 +37,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; @@ -44,6 +48,7 @@ import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorBtnCell; import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorUserCell; @@ -97,32 +102,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { buttonContainer.setOrientation(LinearLayout.VERTICAL); buttonContainer.setPadding(dp(8), dp(8), dp(8), dp(8)); buttonContainer.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); - actionButton = new ButtonWithCounterView(getContext(), true, resourcesProvider) { - - private final RectF rect = new RectF(); - private boolean incGradient; - private float progress; - - @Override - protected void onDraw(Canvas canvas) { - if (incGradient) { - progress += 16f / 1000f; - if (progress > 3) { - incGradient = false; - } - } else { - progress -= 16f / 1000f; - if (progress < 1) { - incGradient = true; - } - } - rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); - canvas.drawRoundRect(rect, dp(8), dp(8), PremiumGradient.getInstance().getMainGradientPaint()); - invalidate(); - super.onDraw(canvas); - } - }; + actionButton = new GradientButtonWithCounterView(getContext(), true, resourcesProvider); actionButton.withCounterIcon(); actionButton.setCounterColor(0xFF9874fc); actionButton.setOnClickListener(view -> { @@ -295,7 +275,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { cell.setText(LocaleController.getString("BoostingRemoveBoostFrom", R.string.BoostingRemoveBoostFrom)); } else if (holder.getItemViewType() == HOLDER_TYPE_HEADER) { topCell = (TopCell) holder.itemView; - topCell.setData(currentChat); + topCell.setData(currentChat, ReassignBoostBottomSheet.this); } } @@ -356,7 +336,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 15, 0, 7)); - description = new TextView(context); + description = new LinkSpanDrawable.LinksTextView(getContext()); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); description.setGravity(Gravity.CENTER_HORIZONTAL); description.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); @@ -365,8 +345,34 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 28, 0, 28, 18)); } - public void setData(TLRPC.Chat chat) { - description.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingReassignBoostTextPlural", BoostRepository.boostsPerSentGift(), chat == null ? "" : chat.title))); + public void setData(TLRPC.Chat chat, BottomSheet bottomSheet) { + try { + String replacer = "%3$s"; + SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingReassignBoostTextPluralWithLink", BoostRepository.boostsPerSentGift(), chat == null ? "" : chat.title, replacer)); + SpannableStringBuilder link = AndroidUtilities.replaceSingleTag( + getString("BoostingReassignBoostTextLink", R.string.BoostingReassignBoostTextLink), + Theme.key_chat_messageLinkIn, REPLACING_TAG_TYPE_LINKBOLD, + () -> { + bottomSheet.dismiss(); + NotificationCenter.getInstance(UserConfig.selectedAccount).postNotificationName(NotificationCenter.didStartedMultiGiftsSelector); + AndroidUtilities.runOnUIThread(UserSelectorBottomSheet::open, 220); + }); + int indexOfReplacer = TextUtils.indexOf(text, replacer); + text.replace(indexOfReplacer, indexOfReplacer + replacer.length(), link); + description.setText(text, TextView.BufferType.EDITABLE); + description.post(() -> { + try { + int linkLine = description.getLayout().getLineForOffset(indexOfReplacer); + if (linkLine == 0) { + description.getEditableText().insert(indexOfReplacer, "\n"); + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } catch (Exception e) { + FileLog.e(e); + } } public void showBoosts(List selectedBoosts, TLRPC.Chat currentChat) { @@ -409,7 +415,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { avatar.setChat(chat); int childCount = allViews.size(); avatarsWrapper.addView(avatar, 0, LayoutHelper.createFrame(70, 70, Gravity.CENTER)); - avatar.setTranslationX(-childCount * (52 + 18)); + avatar.setTranslationX(-childCount * dp(23)); avatar.setAlpha(0f); avatar.setScaleX(0.1f); avatar.setScaleY(0.1f); @@ -435,7 +441,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { final AvatarHolderView finalRemovedAvatar = removedAvatar; finalRemovedAvatar.setTag("REMOVED"); finalRemovedAvatar.animate() - .alpha(0f).translationXBy((52 + 18)) + .alpha(0f).translationXBy(dp(23)) .scaleX(0.1f).scaleY(0.1f) .setInterpolator(interpolator) .setDuration(duration).setListener(new AnimatorListenerAdapter() { @@ -451,7 +457,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { if (view != finalRemovedAvatar) { pos++; childCount -= pos; - view.animate().translationX(-childCount * (52 + 18)) + view.animate().translationX(-childCount * dp(23)) .setInterpolator(interpolator) .setDuration(duration).start(); } @@ -474,7 +480,7 @@ public class ReassignBoostBottomSheet extends BottomSheetWithRecyclerListView { avatarsContainer.animate().setInterpolator(interpolator).translationX(0).setDuration(duration).start(); } else { int count = addedChats.size() - 1; - avatarsContainer.animate().setInterpolator(interpolator).translationX(dp(13) * count).setDuration(duration).start(); + avatarsContainer.animate().setInterpolator(interpolator).translationX(dp(23 / 2f) * count).setDuration(duration).start(); } toAvatar.animate().cancel(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java index 83d6a4e3d..103ad2ad5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java @@ -615,7 +615,7 @@ public class SelectorBottomSheet extends BottomSheetWithRecyclerListView { if (!countryItems.isEmpty()) { h += dp(32); - items.add(Item.asLetter(countriesLetter)); + items.add(Item.asLetter(countriesLetter.toUpperCase())); items.addAll(countryItems); } } 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 new file mode 100644 index 000000000..aa55dd99a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/UserSelectorBottomSheet.java @@ -0,0 +1,593 @@ +package org.telegram.ui.Components.Premium.boosts; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.net.Uri; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ReplacementSpan; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearSmoothScrollerCustom; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BottomSheetWithRecyclerListView; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.boosts.adapters.SelectorAdapter; +import org.telegram.ui.Components.Premium.boosts.adapters.SelectorAdapter.Item; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorBtnCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorHeaderCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorSearchCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorUserCell; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class UserSelectorBottomSheet extends BottomSheetWithRecyclerListView implements NotificationCenter.NotificationCenterDelegate { + private static UserSelectorBottomSheet instance; + + public static void open() { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null) { + return; + } + if (instance != null) { + return; + } + UserSelectorBottomSheet sheet = new UserSelectorBottomSheet(fragment, true); + sheet.show(); + instance = sheet; + } + + public static boolean handleIntent(Intent intent, Browser.Progress progress) { + Uri data = intent.getData(); + if (data != null) { + String scheme = data.getScheme(); + if (scheme != null) { + if ((scheme.equals("http") || scheme.equals("https"))) { + String host = data.getHost().toLowerCase(); + if (host.equals("telegram.me") || host.equals("t.me") || host.equals("telegram.dog")) { + String path = data.getPath(); + if (path != null) { + if (path.startsWith("/premium_multigift")) { + open(); + return true; + } + } + } + } else if (scheme.equals("tg")) { + String url = data.toString(); + if (url.startsWith("tg:premium_multigift") || url.startsWith("tg://premium_multigift")) { + open(); + return true; + } + } + } + } + return false; + } + + private static final int BOTTOM_HEIGHT_DP = 60; + + private final ButtonWithCounterView actionButton; + private final SelectorSearchCell searchField; + private final View sectionCell; + private final SelectorHeaderCell headerView; + private final SelectorBtnCell buttonContainer; + + private final ArrayList oldItems = new ArrayList<>(); + private final ArrayList items = new ArrayList<>(); + private final HashSet selectedIds = new HashSet<>(); + private final List contacts = new ArrayList<>(); + private final List hints = new ArrayList<>(); + private final List foundedUsers = new ArrayList<>(); + private final Map> contactsMap = new HashMap<>(); + private final List contactsLetters = new ArrayList<>(); + private final HashMap allSelectedObjects = new LinkedHashMap<>(); + private String query; + private SelectorAdapter selectorAdapter; + private int listPaddingTop = AndroidUtilities.dp(56 + 64); + private final List paymentOptions = new ArrayList<>(); + private boolean isHintSearchText = false; + private int lastRequestId; + private float recipientsBtnExtraSpace; + private ReplacementSpan recipientsBtnSpaceSpan; + + private final Runnable remoteSearchRunnable = new Runnable() { + @Override + public void run() { + final String finalQuery = query; + if (finalQuery != null) { + loadData(finalQuery); + } + } + }; + + private void loadData(String query) { + lastRequestId = BoostRepository.searchContacts(lastRequestId, query, arg -> { + foundedUsers.clear(); + foundedUsers.addAll(arg); + updateList(true, true); + }); + } + + private void checkEditTextHint() { + if (selectedIds.size() > 0) { + if (!isHintSearchText) { + isHintSearchText = true; + AndroidUtilities.runOnUIThread(() -> searchField.setHintText(LocaleController.getString("Search", R.string.Search), true), 10); + } + } else { + if (isHintSearchText) { + isHintSearchText = false; + AndroidUtilities.runOnUIThread(() -> searchField.setHintText(LocaleController.getString("GiftPremiumUsersSearchHint", R.string.GiftPremiumUsersSearchHint), true), 10); + } + } + } + + private void createRecipientsBtnSpaceSpan() { + recipientsBtnSpaceSpan = new ReplacementSpan() { + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return (int) recipientsBtnExtraSpace; + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + + } + }; + } + + public UserSelectorBottomSheet(BaseFragment fragment, boolean needFocus) { + super(fragment, needFocus, false, false, fragment.getResourceProvider()); + + headerView = new SelectorHeaderCell(getContext(), resourcesProvider) { + @Override + protected int getHeaderHeight() { + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + return dp(48); + } else { + return dp(54); + } + } + }; + headerView.setOnCloseClickListener(this::dismiss); + headerView.setText(getTitle()); + headerView.setCloseImageVisible(false); + headerView.backDrawable.setRotation(0f, false); + + createRecipientsBtnSpaceSpan(); + + searchField = new SelectorSearchCell(getContext(), resourcesProvider, null) { + private boolean isKeyboardVisible; + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + listPaddingTop = getMeasuredHeight() + dp(64); + selectorAdapter.notifyChangedLast(); + if (isKeyboardVisible != isKeyboardVisible()) { + isKeyboardVisible = isKeyboardVisible(); + if (isKeyboardVisible) { + scrollToTop(true); + } + } + } + }; + searchField.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + searchField.setOnSearchTextChange(this::onSearch); + searchField.setHintText(LocaleController.getString("GiftPremiumUsersSearchHint", R.string.GiftPremiumUsersSearchHint), false); + + sectionCell = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + canvas.drawColor(getThemedColor(Theme.key_graySection)); + } + }; + + containerView.addView(headerView, 0, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + containerView.addView(searchField, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + containerView.addView(sectionCell, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, 1, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + + buttonContainer = new SelectorBtnCell(getContext(), resourcesProvider, null); + buttonContainer.setClickable(true); + buttonContainer.setOrientation(LinearLayout.VERTICAL); + buttonContainer.setPadding(dp(10), dp(10), dp(10), dp(10)); + buttonContainer.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + actionButton = new ButtonWithCounterView(getContext(), resourcesProvider) { + @Override + protected float calculateCounterWidth(float width, float percent) { + boolean needUpdateActionBtn = recipientsBtnExtraSpace == 0; + recipientsBtnExtraSpace = width; + if (needUpdateActionBtn) { + createRecipientsBtnSpaceSpan(); + updateActionButton(false); + } + return width; + } + }; + actionButton.setOnClickListener(v -> next()); + buttonContainer.addView(actionButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); + containerView.addView(buttonContainer, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + + selectorAdapter.setData(items, recyclerListView); + recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, dp(BOTTOM_HEIGHT_DP)); + recyclerListView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + AndroidUtilities.hideKeyboard(searchField.getEditText()); + } + } + }); + recyclerListView.setOnItemClickListener((view, position, x, y) -> { + if (view instanceof SelectorUserCell) { + TLRPC.User user = ((SelectorUserCell) view).getUser(); + long id = user.id; + if (selectedIds.contains(id)) { + selectedIds.remove(id); + } else { + selectedIds.add(id); + allSelectedObjects.put(id, user); + } + if (selectedIds.size() == 11) { + selectedIds.remove(id); + showMaximumUsersToast(); + return; + } + checkEditTextHint(); + searchField.updateSpans(true, selectedIds, () -> { + checkEditTextHint(); + updateList(true, false); + }, null); + updateList(true, false); + clearSearchAfterSelect(); + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + recyclerListView.setItemAnimator(itemAnimator); + recyclerListView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); + if (position == items.size()) { + outRect.bottom = listPaddingTop; + } + } + }); + + searchField.setText(""); + searchField.spansContainer.removeAllSpans(false); + searchField.updateSpans(false, selectedIds, () -> { + checkEditTextHint(); + updateList(true, false); + }, null); + headerView.setText(getTitle()); + updateActionButton(false); + initContacts(false); + initHints(false); + updateList(false, true); + fixNavigationBar(); + BoostRepository.loadGiftOptions(null, arg -> { + paymentOptions.clear(); + paymentOptions.addAll(arg); + }); + } + + private void initContacts(boolean needUpdate) { + if (contacts.isEmpty()) { + contacts.addAll(ContactsController.getInstance(currentAccount).contacts); + contactsMap.putAll(ContactsController.getInstance(currentAccount).usersSectionsDict); + contactsLetters.addAll(ContactsController.getInstance(currentAccount).sortedUsersSectionsArray); + if (needUpdate) { + updateItems(true, true); + } + } + } + + private void initHints(boolean needUpdate) { + if (hints.isEmpty()) { + hints.addAll(MediaDataController.getInstance(currentAccount).hints); + if (needUpdate) { + updateItems(true, true); + } + } + } + + @Override + protected void onPreDraw(Canvas canvas, int top, float progressToFullView) { + float minTop = AndroidUtilities.statusBarHeight + (headerView.getMeasuredHeight() - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(40)) / 2f; + float fromY = Math.max(top, minTop) + AndroidUtilities.dp(8); + headerView.setTranslationY(fromY); + searchField.setTranslationY(headerView.getTranslationY() + headerView.getMeasuredHeight()); + sectionCell.setTranslationY(searchField.getTranslationY() + searchField.getMeasuredHeight()); + recyclerListView.setTranslationY(headerView.getMeasuredHeight() + searchField.getMeasuredHeight() + sectionCell.getMeasuredHeight() - AndroidUtilities.dp(8)); + } + + private void next() { + if (selectedIds.size() == 0 || paymentOptions.isEmpty()) { + return; + } + List selectedUsers = new ArrayList<>(); + for (TLRPC.User object : allSelectedObjects.values()) { + if (selectedIds.contains(object.id)) { + selectedUsers.add(object); + } + } + AndroidUtilities.hideKeyboard(searchField.getEditText()); + List options = BoostRepository.filterGiftOptions(paymentOptions, selectedUsers.size()); + options = BoostRepository.filterGiftOptionsByBilling(options); + PremiumPreviewGiftToUsersBottomSheet.show(selectedUsers, options); + } + + public void scrollToTop(boolean animate) { + if (animate) { + LinearSmoothScrollerCustom linearSmoothScroller = new LinearSmoothScrollerCustom(getContext(), LinearSmoothScrollerCustom.POSITION_TOP, .6f); + linearSmoothScroller.setTargetPosition(1); + linearSmoothScroller.setOffset(AndroidUtilities.dp(36)); + recyclerListView.getLayoutManager().startSmoothScroll(linearSmoothScroller); + } else { + recyclerListView.scrollToPosition(0); + } + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.giftsToUserSent); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsDidLoad); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.reloadHints); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.giftsToUserSent); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.reloadHints); + } + + @Override + public void dismissInternal() { + super.dismissInternal(); + instance = null; + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + } + + private void showMaximumUsersToast() { + String text = LocaleController.getString("BoostingSelectUpToWarningUsers", R.string.BoostingSelectUpToWarningUsers); + BulletinFactory.of(container, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, text).show(true); + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + } + } + + private void updateList(boolean animated, boolean notify) { + updateItems(animated, notify); + updateCheckboxes(animated); + updateActionButton(animated); + } + + private void updateCheckboxes(boolean animated) { + int visibleItemsFrom = -1; + int visibleItemsTo = 0; + for (int i = 0; i < recyclerListView.getChildCount(); ++i) { + View child = recyclerListView.getChildAt(i); + if (child instanceof SelectorUserCell) { + int position = recyclerListView.getChildAdapterPosition(child); + if (position <= 0) { + continue; + } + if (visibleItemsFrom == -1) { + visibleItemsFrom = position; + } + visibleItemsTo = position; + Item item = items.get(position - 1); + SelectorUserCell cell = (SelectorUserCell) child; + cell.setChecked(item.checked, animated); + if (item.chat != null) { + cell.setCheckboxAlpha(selectorAdapter.getParticipantsCount(item.chat) > 200 ? .3f : 1f, animated); + } else { + cell.setCheckboxAlpha(1f, animated); + } + } + } + if (animated) { + selectorAdapter.notifyItemRangeChanged(0, visibleItemsFrom); + selectorAdapter.notifyItemRangeChanged(visibleItemsTo, selectorAdapter.getItemCount() - visibleItemsTo); + } + } + + private void updateActionButton(boolean animated) { + actionButton.setShowZero(false); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + if (selectedIds.size() == 0) { + stringBuilder.append("d").setSpan(recipientsBtnSpaceSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.append(LocaleController.getString("GiftPremiumChooseRecipientsBtn", R.string.GiftPremiumChooseRecipientsBtn)); + } else { + stringBuilder.append(LocaleController.getString("GiftPremiumProceedBtn", R.string.GiftPremiumProceedBtn)); + } + actionButton.setCount(selectedIds.size(), true); + actionButton.setText(stringBuilder, animated, false); + actionButton.setEnabled(true); + } + + private void onSearch(String text) { + this.query = text; + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + AndroidUtilities.runOnUIThread(remoteSearchRunnable, 350); + } + + private void clearSearchAfterSelect() { + if (isSearching()) { + query = null; + searchField.setText(""); + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + updateItems(true, true); + } + } + + private void updateSectionCell(boolean animated) { + if (selectedIds == null) { + return; + } + if (selectedIds.size() > 0) { + selectorAdapter.setTopSectionClickListener(v -> { + selectedIds.clear(); + searchField.spansContainer.removeAllSpans(true); + checkEditTextHint(); + updateList(true, false); + }); + } else { + selectorAdapter.setTopSectionClickListener(null); + } + } + + private boolean isSearching() { + return !TextUtils.isEmpty(query); + } + + @SuppressLint("NotifyDataSetChanged") + public void updateItems(boolean animated, boolean notify) { + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + + int h = 0; + if (isSearching()) { + for (TLRPC.User foundedUser : foundedUsers) { + h += dp(56); + items.add(Item.asUser(foundedUser, selectedIds.contains(foundedUser.id))); + } + } else { + if (!hints.isEmpty()) { + List userItems = new ArrayList<>(); + for (TLRPC.TL_topPeer hint : hints) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(hint.peer.user_id); + if (user.self || user.bot || UserObject.isService(user.id) || UserObject.isDeleted(user)) { + continue; + } + h += dp(56); + userItems.add(Item.asUser(user, selectedIds.contains(user.id))); + } + if (!userItems.isEmpty()) { + h += dp(32); + items.add(Item.asTopSection(LocaleController.getString("GiftPremiumFrequentContacts", R.string.GiftPremiumFrequentContacts))); + items.addAll(userItems); + } + } + for (String contactLetter : contactsLetters) { + List userItems = new ArrayList<>(); + for (TLRPC.TL_contact contact : contactsMap.get(contactLetter)) { + long myUid = UserConfig.getInstance(currentAccount).getClientUserId(); + if (contact.user_id == myUid) { + continue; + } + h += dp(56); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); + userItems.add(Item.asUser(user, selectedIds.contains(user.id))); + } + + if (!userItems.isEmpty()) { + h += dp(32); + items.add(Item.asLetter(contactLetter.toUpperCase())); + items.addAll(userItems); + } + } + } + + if (items.isEmpty()) { + items.add(Item.asNoUsers()); + h += dp(150); + } + int minHeight = (int) (AndroidUtilities.displaySize.y * 0.6f); + items.add(Item.asPad(Math.max(0, minHeight - h))); + + updateSectionCell(animated); + + if (notify && selectorAdapter != null) { + if (animated) { + selectorAdapter.setItems(oldItems, items); + } else { + selectorAdapter.notifyDataSetChanged(); + } + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateItems(false, true); + } + + @Override + protected CharSequence getTitle() { + return LocaleController.getString("GiftTelegramPremiumTitle", R.string.GiftTelegramPremiumTitle); + } + + @Override + protected RecyclerListView.SelectionAdapter createAdapter() { + selectorAdapter = new SelectorAdapter(getContext(), resourcesProvider); + selectorAdapter.setGreenSelector(true); + return selectorAdapter; + } + + @Override + public void dismiss() { + AndroidUtilities.hideKeyboard(searchField.getEditText()); + super.dismiss(); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.giftsToUserSent) { + dismiss(); + } else if (id == NotificationCenter.contactsDidLoad) { + AndroidUtilities.runOnUIThread(() -> initContacts(true)); + } else if (id == NotificationCenter.reloadHints) { + AndroidUtilities.runOnUIThread(() -> initHints(true)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java index 2e4138e88..0fddfb8dc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/BoostAdapter.java @@ -23,11 +23,13 @@ import org.telegram.ui.Components.Premium.boosts.cells.BoostTypeCell; import org.telegram.ui.Components.Premium.boosts.cells.BoostTypeSingleCell; import org.telegram.ui.Components.Premium.boosts.cells.ChatCell; import org.telegram.ui.Components.Premium.boosts.cells.DateEndCell; +import org.telegram.ui.Components.Premium.boosts.cells.EnterPrizeCell; import org.telegram.ui.Components.Premium.boosts.cells.HeaderCell; import org.telegram.ui.Components.Premium.boosts.cells.ParticipantsTypeCell; import org.telegram.ui.Components.Premium.boosts.cells.DurationCell; import org.telegram.ui.Components.Premium.boosts.cells.SliderCell; import org.telegram.ui.Components.Premium.boosts.cells.SubtitleWithCounterCell; +import org.telegram.ui.Components.Premium.boosts.cells.SwitcherCell; import org.telegram.ui.Components.Premium.boosts.cells.TextInfoCell; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SlideChooseView; @@ -51,7 +53,9 @@ public class BoostAdapter extends AdapterWithDiffUtils { HOLDER_TYPE_PARTICIPANTS = 11, HOLDER_TYPE_DURATION = 12, HOLDER_TYPE_SUBTITLE_WITH_COUNTER = 13, - HOLDER_TYPE_SINGLE_BOOST_TYPE = 14; + HOLDER_TYPE_SINGLE_BOOST_TYPE = 14, + HOLDER_TYPE_SWITCHER = 15, + HOLDER_TYPE_ENTER_PRIZE = 16; private final Theme.ResourcesProvider resourcesProvider; private List items = new ArrayList<>(); @@ -59,16 +63,18 @@ public class BoostAdapter extends AdapterWithDiffUtils { private SlideChooseView.Callback sliderCallback; private ChatCell.ChatDeleteListener chatDeleteListener; private HeaderCell headerCell; + private EnterPrizeCell.AfterTextChangedListener afterTextChangedListener; public BoostAdapter(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; } - public void setItems(List items, RecyclerListView recyclerListView, SlideChooseView.Callback sliderCallback, ChatCell.ChatDeleteListener chatDeleteListener) { + public void setItems(List items, RecyclerListView recyclerListView, SlideChooseView.Callback sliderCallback, ChatCell.ChatDeleteListener chatDeleteListener, EnterPrizeCell.AfterTextChangedListener afterTextChangedListener) { this.items = items; this.recyclerListView = recyclerListView; this.sliderCallback = sliderCallback; this.chatDeleteListener = chatDeleteListener; + this.afterTextChangedListener = afterTextChangedListener; } public void updateBoostCounter(int value) { @@ -81,13 +87,30 @@ public class BoostAdapter extends AdapterWithDiffUtils { ((ChatCell) child).setCounter(value); } } - notifyItemChanged(8); - //updates all prices - notifyItemChanged(items.size() - 1); - notifyItemChanged(items.size() - 2); - notifyItemChanged(items.size() - 3); - notifyItemChanged(items.size() - 4); - notifyItemChanged(items.size() - 6); + notifyItemChanged(8); //update main channel + notifyItemRangeChanged(items.size() - 12, 12); //updates all prices + } + + public void notifyAllVisibleTextDividers() { + for (int i = 0; i < items.size(); i++) { + if (items.get(i).viewType == HOLDER_TYPE_TEXT_DIVIDER) { + notifyItemChanged(i); + } + } + } + + public void notifyAdditionalPrizeItem(boolean checked) { + for (int i = 0; i < items.size(); i++) { + Item item = items.get(i); + if (item.viewType == HOLDER_TYPE_SWITCHER && item.subType == SwitcherCell.TYPE_ADDITION_PRIZE) { + if (checked) { + notifyItemInserted(i + 1); + } else { + notifyItemRemoved(i + 1); + } + break; + } + } } public void setPausedStars(boolean paused) { @@ -158,6 +181,7 @@ public class BoostAdapter extends AdapterWithDiffUtils { || itemViewType == HOLDER_TYPE_PARTICIPANTS || itemViewType == HOLDER_TYPE_ADD_CHANNEL || itemViewType == HOLDER_TYPE_DATE_END + || itemViewType == HOLDER_TYPE_SWITCHER || itemViewType == HOLDER_TYPE_DURATION; } @@ -177,6 +201,14 @@ public class BoostAdapter extends AdapterWithDiffUtils { case HOLDER_TYPE_SINGLE_BOOST_TYPE: view = new BoostTypeSingleCell(context, resourcesProvider); break; + case HOLDER_TYPE_ENTER_PRIZE: + view = new EnterPrizeCell(context, resourcesProvider); + break; + case HOLDER_TYPE_SWITCHER: + SwitcherCell cell = new SwitcherCell(context, resourcesProvider); + cell.setHeight(50); + view = cell; + break; case HOLDER_TYPE_EMPTY: view = new View(context); break; @@ -293,6 +325,17 @@ public class BoostAdapter extends AdapterWithDiffUtils { case HOLDER_TYPE_SIMPLE_DIVIDER: { break; } + case HOLDER_TYPE_ENTER_PRIZE: { + EnterPrizeCell cell = (EnterPrizeCell) holder.itemView; + cell.setCount(item.intValue); + cell.setAfterTextChangedListener(afterTextChangedListener); + break; + } + case HOLDER_TYPE_SWITCHER: { + SwitcherCell cell = (SwitcherCell) holder.itemView; + cell.setData(item.text, item.selectable, item.boolValue, item.subType); + break; + } } } @@ -358,6 +401,20 @@ public class BoostAdapter extends AdapterWithDiffUtils { return item; } + public static Item asEnterPrize(int count) { + Item item = new Item(HOLDER_TYPE_ENTER_PRIZE, false); + item.intValue = count; + return item; + } + + public static Item asSwitcher(CharSequence text, boolean isSelected, boolean needDivider, int subType) { + Item item = new Item(HOLDER_TYPE_SWITCHER, isSelected); + item.text = text; + item.boolValue = needDivider; + item.subType = subType; + return item; + } + public static Item asSingleBoost(Object user) { Item item = new Item(HOLDER_TYPE_SINGLE_BOOST_TYPE, false); item.user = user; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java index cf28bbc47..081079743 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java @@ -9,6 +9,7 @@ import android.text.SpannableStringBuilder; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -48,16 +49,18 @@ public abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter private BaseFragment baseFragment; private TLRPC.TL_payments_checkedGiftCode giftCode; private String slug; + private FrameLayout container; public GiftInfoAdapter(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; } - public void init(BaseFragment baseFragment, TLRPC.TL_payments_checkedGiftCode giftCode, String slug) { + public void init(BaseFragment baseFragment, TLRPC.TL_payments_checkedGiftCode giftCode, String slug, FrameLayout container) { this.isUnused = giftCode.used_date == 0; this.baseFragment = baseFragment; this.giftCode = giftCode; this.slug = slug; + this.container = container; } @Override @@ -111,7 +114,7 @@ public abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter break; case HOLDER_TYPE_BUTTON: view = new ActionBtnCell(context, resourcesProvider); - view.setPadding(0,0,0, AndroidUtilities.dp(14)); + view.setPadding(0, 0, 0, AndroidUtilities.dp(14)); break; case HOLDER_TYPE_EMPTY: view = new View(context); @@ -181,25 +184,7 @@ public abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter LocaleController.getString("BoostingSendLinkToAnyone", R.string.BoostingSendLinkToAnyone) : LocaleController.getString("BoostingSendLinkToFriends", R.string.BoostingSendLinkToFriends), Theme.key_chat_messageLinkIn, 0, - () -> { - final String slugLink = "https://t.me/giftcode/" + slug; - Bundle args = new Bundle(); - args.putBoolean("onlySelect", true); - args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); - DialogsActivity dialogFragment = new DialogsActivity(args); - dialogFragment.setDelegate((fragment1, dids, message, param, topicsFragment) -> { - long did = 0; - for (int a = 0; a < dids.size(); a++) { - did = dids.get(a).dialogId; - baseFragment.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(slugLink, did, null, null, null, true, null, null, null, true, 0, null, false)); - } - fragment1.finishFragment(); - BoostDialogs.showGiftLinkForwardedBulletin(did); - return true; - }); - baseFragment.presentFragment(dialogFragment); - dismiss(); - }, + this::share, resourcesProvider ); cell.setText(text); @@ -227,7 +212,7 @@ public abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter dismiss(); }, error -> { cell.updateLoading(false); - BoostDialogs.showToastError(baseFragment.getContext(), error); + BoostDialogs.processApplyGiftCodeError(error, container, resourcesProvider, this::share); }); } else { dismiss(); @@ -245,6 +230,26 @@ public abstract class GiftInfoAdapter extends RecyclerListView.SelectionAdapter } } + private void share() { + final String slugLink = "https://t.me/giftcode/" + slug; + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); + DialogsActivity dialogFragment = new DialogsActivity(args); + dialogFragment.setDelegate((fragment1, dids, message, param, topicsFragment) -> { + long did = 0; + for (int a = 0; a < dids.size(); a++) { + did = dids.get(a).dialogId; + baseFragment.getSendMessagesHelper().sendMessage(SendMessagesHelper.SendMessageParams.of(slugLink, did, null, null, null, true, null, null, null, true, 0, null, false)); + } + fragment1.finishFragment(); + BoostDialogs.showGiftLinkForwardedBulletin(did); + return true; + }); + baseFragment.presentFragment(dialogFragment); + dismiss(); + } + @Override public int getItemCount() { return 5; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/SelectorAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/SelectorAdapter.java index 786473589..952ab38ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/SelectorAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/SelectorAdapter.java @@ -17,6 +17,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorCountryCell; @@ -35,12 +36,16 @@ public class SelectorAdapter extends AdapterWithDiffUtils { public static final int VIEW_TYPE_NO_USERS = 5; public static final int VIEW_TYPE_COUNTRY = 6; public static final int VIEW_TYPE_LETTER = 7; + public static final int VIEW_TYPE_TOP_SECTION = 8; private final Theme.ResourcesProvider resourcesProvider; private final Context context; private RecyclerListView listView; private List items; private HashMap chatsParticipantsCount = new HashMap<>(); + private View.OnClickListener topSectionClickListener; + private boolean isGreenSelector; + private GraySectionCell topSectionCell; public SelectorAdapter(Context context, Theme.ResourcesProvider resourcesProvider) { this.context = context; @@ -56,6 +61,21 @@ public class SelectorAdapter extends AdapterWithDiffUtils { this.listView = listView; } + public void setTopSectionClickListener(View.OnClickListener topSectionClickListener) { + this.topSectionClickListener = topSectionClickListener; + if (topSectionCell != null) { + if (topSectionClickListener == null) { + topSectionCell.setRightText(null); + } else { + topSectionCell.setRightText(LocaleController.getString(R.string.UsersDeselectAll), true, topSectionClickListener); + } + } + } + + public void setGreenSelector(boolean isGreenSelector) { + this.isGreenSelector = isGreenSelector; + } + @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return (holder.getItemViewType() == VIEW_TYPE_USER || holder.getItemViewType() == VIEW_TYPE_COUNTRY); @@ -68,7 +88,7 @@ public class SelectorAdapter extends AdapterWithDiffUtils { if (viewType == VIEW_TYPE_PAD) { view = new View(context); } else if (viewType == VIEW_TYPE_USER) { - view = new SelectorUserCell(context, resourcesProvider, false); + view = new SelectorUserCell(context, resourcesProvider, isGreenSelector); } else if (viewType == VIEW_TYPE_NO_USERS) { StickerEmptyView searchEmptyView = new StickerEmptyView(context, null, StickerEmptyView.STICKER_TYPE_SEARCH, resourcesProvider); searchEmptyView.title.setText(LocaleController.getString("NoResult", R.string.NoResult)); @@ -79,6 +99,8 @@ public class SelectorAdapter extends AdapterWithDiffUtils { view = new SelectorLetterCell(context, resourcesProvider); } else if (viewType == VIEW_TYPE_COUNTRY) { view = new SelectorCountryCell(context, resourcesProvider); + } else if (viewType == VIEW_TYPE_TOP_SECTION) { + view = new GraySectionCell(context, resourcesProvider); } else { view = new View(context); } @@ -128,9 +150,12 @@ public class SelectorAdapter extends AdapterWithDiffUtils { userCell.setChecked(item.checked, false); userCell.setCheckboxAlpha(1f, false); userCell.setDivider(position < items.size() - 2); + if ((position + 1 < items.size()) && items.get(position + 1).viewType == VIEW_TYPE_LETTER) { + userCell.setDivider(false); + } } else if (viewType == VIEW_TYPE_COUNTRY) { SelectorCountryCell cell = (SelectorCountryCell) holder.itemView; - boolean needDivider = (position < items.size() - 2) && (position + 1 < items.size() - 2) && (items.get(position + 1).viewType != VIEW_TYPE_LETTER); + boolean needDivider = (position < items.size() - 1) && (position + 1 < items.size() - 1) && (items.get(position + 1).viewType != VIEW_TYPE_LETTER); cell.setCountry(item.country, needDivider); cell.setChecked(item.checked, false); } else if (viewType == VIEW_TYPE_PAD) { @@ -149,6 +174,15 @@ public class SelectorAdapter extends AdapterWithDiffUtils { ((StickerEmptyView) holder.itemView).stickerView.getImageReceiver().startAnimation(); } catch (Exception ignore) { } + } else if (viewType == VIEW_TYPE_TOP_SECTION) { + GraySectionCell cell = (GraySectionCell) holder.itemView; + cell.setText(item.text); + if (topSectionClickListener == null) { + cell.setRightText(null, null); + } else { + cell.setRightText(LocaleController.getString(R.string.UsersDeselectAll), topSectionClickListener); + } + topSectionCell = cell; } } @@ -262,6 +296,12 @@ public class SelectorAdapter extends AdapterWithDiffUtils { return item; } + public static Item asTopSection(String text) { + Item item = new Item(VIEW_TYPE_TOP_SECTION, false); + item.text = text; + return item; + } + public static Item asCountry(TLRPC.TL_help_country tlHelpCountry, boolean checked) { Item item = new Item(VIEW_TYPE_COUNTRY, true); item.country = tlHelpCountry; @@ -307,6 +347,8 @@ public class SelectorAdapter extends AdapterWithDiffUtils { return false; } else if (viewType == VIEW_TYPE_LETTER && (!TextUtils.equals(text, i.text))) { return false; + } else if (viewType == VIEW_TYPE_TOP_SECTION && (!TextUtils.equals(text, i.text) || checked != i.checked)) { + return false; } return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ActionBtnCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ActionBtnCell.java index d6626d363..9d0e95912 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ActionBtnCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ActionBtnCell.java @@ -63,6 +63,13 @@ public class ActionBtnCell extends FrameLayout { backgroundView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); } + public void setActivateForFreeStyle() { + drawDivider = true; + button.setEnabled(true); + button.setText(LocaleController.formatString("GiftPremiumActivateForFree", R.string.GiftPremiumActivateForFree), false); + backgroundView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + } + @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); @@ -99,4 +106,9 @@ public class ActionBtnCell extends FrameLayout { button.setEnabled(true); button.setText(LocaleController.formatString("Close", R.string.Close), false); } + + public void setCloseStyle(boolean needDivider){ + setCloseStyle(); + drawDivider = needDivider; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java index 696e41633..5e0a8c62a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java @@ -13,7 +13,7 @@ import org.telegram.ui.Components.LayoutHelper; @SuppressLint("ViewConstructor") public class DurationCell extends BaseCell { - private final SimpleTextView totalTextView; + protected final SimpleTextView totalTextView; private Object code; public DurationCell(Context context, Theme.ResourcesProvider resourcesProvider) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java new file mode 100644 index 000000000..6cd927629 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationWithDiscountCell.java @@ -0,0 +1,83 @@ +package org.telegram.ui.Components.Premium.boosts.cells; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.Gravity; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BillingController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.boosts.DiscountSpan; + +@SuppressLint("ViewConstructor") +public class DurationWithDiscountCell extends DurationCell { + + protected final CheckBox2 checkBox; + private TLRPC.TL_premiumGiftCodeOption option; + + public DurationWithDiscountCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + checkBox = new CheckBox2(context, 21, resourcesProvider); + checkBox.setColor(Theme.key_premiumGradient1, Theme.key_checkboxDisabled, Theme.key_dialogRoundCheckBoxCheck); + checkBox.setDrawUnchecked(true); + checkBox.setDrawBackgroundAsArc(10); + addView(checkBox); + titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + radioButton.setVisibility(GONE); + updateLayouts(); + } + + @Override + protected void updateLayouts() { + super.updateLayouts(); + titleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : 102, 0, LocaleController.isRTL ? 102 : 20, 0)); + subtitleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 20 : 102, 0, LocaleController.isRTL ? 102 : 20, 0)); + if (checkBox != null) { + checkBox.setLayoutParams(LayoutHelper.createFrame(22, 22, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 15 : 20, 0, LocaleController.isRTL ? 20 : 15, 0)); + } + } + + @Override + public void setChecked(boolean checked, boolean animated) { + if (checkBox.getVisibility() == View.VISIBLE) { + checkBox.setChecked(checked, animated); + } + } + + public void setDuration(TLRPC.TL_premiumGiftCodeOption option, TLRPC.TL_premiumGiftCodeOption minOption, int usersCount, boolean needDivider, boolean selected) { + this.option = option; + long price = option.amount; + CharSequence currency = option.currency; + titleTextView.setText(LocaleController.formatPluralString("Months", option.months)); + int discount = (int) ((1.0 - (option.amount / (double) option.months) / (minOption.amount / (double) minOption.months)) * 100); + String subTitle; + if (usersCount > 1) { + subTitle = BillingController.getInstance().formatCurrency(price / usersCount, currency.toString()) + " x " + usersCount; + } else { + subTitle = LocaleController.formatString(R.string.PricePerMonth, BillingController.getInstance().formatCurrency(price / option.months, currency.toString())); + } + if (discount > 0) { + setSubtitle(DiscountSpan.applySpan(subTitle, discount)); + } else { + setSubtitle(subTitle); + } + totalTextView.setText(BillingController.getInstance().formatCurrency(usersCount > 0 ? price : 0, currency.toString())); + setDivider(needDivider); + checkBox.setChecked(selected, false); + } + + public TLRPC.TL_premiumGiftCodeOption getOption() { + return option; + } + + @Override + protected boolean needCheck() { + return true; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/EnterPrizeCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/EnterPrizeCell.java new file mode 100644 index 000000000..4c03f708b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/EnterPrizeCell.java @@ -0,0 +1,123 @@ +package org.telegram.ui.Components.Premium.boosts.cells; + +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; +import org.telegram.messenger.R; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.Spanned; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.inputmethod.EditorInfo; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.EditTextCaption; +import org.telegram.ui.Components.LayoutHelper; + +@SuppressLint("ViewConstructor") +public class EnterPrizeCell extends LinearLayout { + private static final int MAX_INPUT_LENGTH = 128; + + public interface AfterTextChangedListener { + void afterTextChanged(String text); + } + + private final Theme.ResourcesProvider resourcesProvider; + private final EditTextCaption editText; + private final TextView textView; + private AfterTextChangedListener afterTextChangedListener; + + public EnterPrizeCell(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + setOrientation(LinearLayout.HORIZONTAL); + editText = new EditTextCaption(context, resourcesProvider); + editText.setLines(1); + editText.setSingleLine(true); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(MAX_INPUT_LENGTH) { + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + CharSequence result = super.filter(source, start, end, dest, dstart, dend); + if (result != null && result.length() == 0) { + AndroidUtilities.shakeView(editText); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + } + return result; + } + }; + editText.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + editText.setFilters(inputFilters); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editText.setTextColor(Theme.getColor(Theme.key_chat_messagePanelText, resourcesProvider)); + editText.setLinkTextColor(Theme.getColor(Theme.key_chat_messageLinkOut, resourcesProvider)); + editText.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight, resourcesProvider)); + editText.setHintColor(Theme.getColor(Theme.key_chat_messagePanelHint, resourcesProvider)); + editText.setHintTextColor(Theme.getColor(Theme.key_chat_messagePanelHint, resourcesProvider)); + editText.setCursorColor(Theme.getColor(Theme.key_chat_messagePanelCursor, resourcesProvider)); + editText.setHandlesColor(Theme.getColor(Theme.key_chat_TextSelectionCursor, resourcesProvider)); + editText.setBackground(null); + editText.setHint(LocaleController.getString("BoostingGiveawayEnterYourPrize", R.string.BoostingGiveawayEnterYourPrize)); + editText.addTextChangedListener(new TextWatcher() { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (afterTextChangedListener != null) { + afterTextChangedListener.afterTextChanged(s.toString().trim()); + } + } + }); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + + if (LocaleController.isRTL) { + LinearLayout.LayoutParams lp = LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 20, 0, 36, 0); + lp.weight = 1; + addView(editText, lp); + addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 20, 0)); + } else { + addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 20, 0, 0, 0)); + addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 36, 0, 20, 0)); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50), MeasureSpec.EXACTLY) + ); + } + + public void setAfterTextChangedListener(AfterTextChangedListener afterTextChangedListener) { + this.afterTextChangedListener = afterTextChangedListener; + } + + public void setCount(int count) { + textView.setText(String.valueOf(count)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java index 59107741c..b3a38b3f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/HeaderCell.java @@ -1,19 +1,14 @@ package org.telegram.ui.Components.Premium.boosts.cells; import static org.telegram.messenger.AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD; -import static org.telegram.messenger.AndroidUtilities.dp; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Outline; import android.os.Build; -import android.os.Bundle; -import android.text.Html; import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.util.TypedValue; import android.view.Gravity; @@ -25,31 +20,22 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; -import androidx.core.text.HtmlCompat; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; -import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ChatActivity; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.Premium.GLIcon.GLIconRenderer; import org.telegram.ui.Components.Premium.GLIcon.GLIconTextureView; import org.telegram.ui.Components.Premium.StarParticlesView; -import org.telegram.ui.Components.Premium.boosts.BoostDialogs; -import org.telegram.ui.DialogsActivity; -import org.telegram.ui.LaunchActivity; @SuppressLint("ViewConstructor") public class HeaderCell extends FrameLayout { @@ -178,31 +164,16 @@ public class HeaderCell extends FrameLayout { public void setGiftLinkToUserText(long toUserId, Utilities.Callback onObjectClicked) { titleView.setText(LocaleController.formatString("BoostingGiftLink", R.string.BoostingGiftLink)); - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); - try { - String description = LocaleController.getString("BoostingLinkAllowsToUser", R.string.BoostingLinkAllowsToUser); - CharSequence descriptionStart = description.substring(0, description.indexOf("**%1$s**") + 8); - CharSequence descriptionEnd = description.substring(description.indexOf("**%1$s**") + 8); + CharSequence description = AndroidUtilities.replaceTags(LocaleController.getString("BoostingLinkAllowsToUser", R.string.BoostingLinkAllowsToUser)); + TLRPC.User toUser = MessagesController.getInstance(UserConfig.selectedAccount).getUser(toUserId); - TLRPC.User toUser = MessagesController.getInstance(UserConfig.selectedAccount).getUser(toUserId); - SpannableStringBuilder userName = new SpannableStringBuilder(); - userName.append("**"); - userName.append(Emoji.replaceEmoji(UserObject.getUserName(toUser), subtitleView.getPaint().getFontMetricsInt(), false)); - userName.append("**"); - - descriptionStart = AndroidUtilities.replaceSingleTag( - descriptionStart.toString().replace("**%1$s**", userName), - Theme.key_chat_messageLinkIn, REPLACING_TAG_TYPE_LINKBOLD, - () -> onObjectClicked.run(toUser), - resourcesProvider - ); - descriptionEnd = AndroidUtilities.replaceTags(descriptionEnd.toString()); - stringBuilder.append(descriptionStart); - stringBuilder.append(descriptionEnd); - } catch (Exception e) { - FileLog.e(e); - } - subtitleView.setText(stringBuilder); + SpannableStringBuilder link = AndroidUtilities.replaceSingleTag( + "**" + UserObject.getUserName(toUser) + "**", + Theme.key_chat_messageLinkIn, REPLACING_TAG_TYPE_LINKBOLD, + () -> onObjectClicked.run(toUser), + resourcesProvider + ); + subtitleView.setText(AndroidUtilities.replaceCharSequence("%1$s", description, link)); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SwitcherCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SwitcherCell.java new file mode 100644 index 000000000..006d65873 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SwitcherCell.java @@ -0,0 +1,41 @@ +package org.telegram.ui.Components.Premium.boosts.cells; + +import android.content.Context; + +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.TextCheckCell; + +public class SwitcherCell extends TextCheckCell { + public static int TYPE_WINNERS = 0; + public static int TYPE_ADDITION_PRIZE = 1; + private int type; + + public SwitcherCell(Context context) { + super(context); + } + + public SwitcherCell(Context context, int padding) { + super(context, padding); + } + + public SwitcherCell(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + } + + public SwitcherCell(Context context, int padding, boolean dialog) { + super(context, padding, dialog); + } + + public SwitcherCell(Context context, int padding, boolean dialog, Theme.ResourcesProvider resourcesProvider) { + super(context, padding, dialog, resourcesProvider); + } + + public int getType() { + return type; + } + + public void setData(CharSequence text, boolean checked, boolean divider, int type) { + this.type = type; + setTextAndCheck(text, checked, divider); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java index 5b208ff3a..053255b72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java @@ -282,7 +282,6 @@ public class TableCell extends FrameLayout { if (blueColor) { textView = new LinkSpanDrawable.LinksTextView(getContext(), resourcesProvider); - textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); } else { textView = new TextView(getContext()); @@ -290,7 +289,9 @@ public class TableCell extends FrameLayout { textView.setTextColor(Theme.getColor(blueColor ? Theme.key_dialogTextBlue : Theme.key_dialogTextBlack, resourcesProvider)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + if (!blueColor) { + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + } if (text != null) { textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textView.setText(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java index 652b603d3..9893bb262 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java @@ -72,39 +72,49 @@ public class GiveawayMessageCell { private ImageReceiver[] avatarImageReceivers; private AvatarDrawable[] avatarDrawables; private final ChatMessageCell parentView; - private final ImageReceiver giftReceiver; + private ImageReceiver giftReceiver; - private CharSequence[] chatTitles = new CharSequence[10]; - private TLRPC.Chat[] chats = new TLRPC.Chat[10]; - private float[] chatTitleWidths = new float[10]; - private boolean[] needNewRow = new boolean[10]; - private Rect[] clickRect = new Rect[10]; + private CharSequence[] chatTitles; + private TLRPC.Chat[] chats; + private float[] chatTitleWidths; + private boolean[] needNewRow; + private Rect[] clickRect; private boolean[] avatarVisible; private int measuredHeight = 0; private int measuredWidth = 0; + + private int additionPrizeHeight; + private float textDividerWidth; + private String textDivider; + private int titleHeight; private int topHeight; private int bottomHeight; private int countriesHeight; private String counterStr; private int diffTextWidth; + + private StaticLayout titleLayout; + private StaticLayout additionPrizeLayout; private StaticLayout topLayout; private StaticLayout bottomLayout; private StaticLayout countriesLayout; - private final TextPaint counterTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private final TextPaint chatTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private final TextPaint countriesTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - private final Paint counterBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint chatBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private TextPaint counterTextPaint; + private TextPaint chatTextPaint; + private TextPaint textPaint; + private TextPaint textDividerPaint; + private Paint lineDividerPaint; + private TextPaint countriesTextPaint; + private Paint counterBgPaint; + private Paint chatBgPaint; - private final Paint saveLayerPaint = new Paint(); - private final Paint clipRectPaint = new Paint(); - private final RectF countRect = new RectF(); - private final RectF chatRect = new RectF(); - private final Rect counterTextBounds = new Rect(); - private final Rect containerRect = new Rect(); - private final int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + private Paint saveLayerPaint; + private Paint clipRectPaint; + private RectF countRect; + private RectF chatRect; + private Rect counterTextBounds; + private Rect containerRect; + private int[] pressedState; private int selectorColor; private Drawable selectorDrawable; @@ -115,6 +125,35 @@ public class GiveawayMessageCell { public GiveawayMessageCell(ChatMessageCell parentView) { this.parentView = parentView; + } + + private void init() { + if (counterTextPaint != null) { + return; + } + counterTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + chatTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textDividerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + lineDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + countriesTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + counterBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + chatBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + saveLayerPaint = new Paint(); + clipRectPaint = new Paint(); + countRect = new RectF(); + chatRect = new RectF(); + counterTextBounds = new Rect(); + containerRect = new Rect(); + pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + + chatTitles = new CharSequence[10]; + chats = new TLRPC.Chat[10]; + chatTitleWidths = new float[10]; + needNewRow = new boolean[10]; + clickRect = new Rect[10]; + giftReceiver = new ImageReceiver(parentView); giftReceiver.setAllowLoadingOnAttachedOnly(true); @@ -127,6 +166,8 @@ public class GiveawayMessageCell { chatTextPaint.setTextSize(dp(13)); countriesTextPaint.setTextSize(dp(13)); textPaint.setTextSize(dp(14)); + textDividerPaint.setTextSize(dp(14)); + textDividerPaint.setTextAlign(Paint.Align.CENTER); } public boolean checkMotionEvent(MotionEvent event) { @@ -210,15 +251,20 @@ public class GiveawayMessageCell { public void setMessageContent(MessageObject messageObject, int parentWidth, int forwardedNameWidth) { this.messageObject = null; + titleLayout = null; + additionPrizeLayout = null; topLayout = null; bottomLayout = null; countriesLayout = null; measuredHeight = 0; measuredWidth = 0; + additionPrizeHeight = 0; + textDividerWidth = 0; if (!messageObject.isGiveaway()) { return; } this.messageObject = messageObject; + init(); createImages(); setGiftImage(messageObject); TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media; @@ -233,23 +279,23 @@ public class GiveawayMessageCell { } CharSequence giveawayPrizes = replaceTags(getString("BoostingGiveawayPrizes", R.string.BoostingGiveawayPrizes)); - SpannableStringBuilder topStringBuilder = new SpannableStringBuilder(giveawayPrizes); - topStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, giveawayPrizes.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - topStringBuilder.append("\n"); + SpannableStringBuilder titleStringBuilder = new SpannableStringBuilder(giveawayPrizes); + titleStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, giveawayPrizes.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableStringBuilder subTitleBuilder = new SpannableStringBuilder(); subTitleBuilder.append(replaceTags(formatPluralStringComma("BoostingGiveawayMsgInfoPlural1", giveaway.quantity))); subTitleBuilder.append("\n"); subTitleBuilder.append(replaceTags(formatPluralString("BoostingGiveawayMsgInfoPlural2", giveaway.quantity, LocaleController.formatPluralString("BoldMonths", giveaway.months)))); - CharSequence subTitle = subTitleBuilder; + SpannableStringBuilder topStringBuilder = new SpannableStringBuilder(); topStringBuilder.append(subTitleBuilder); topStringBuilder.append("\n\n"); - topStringBuilder.setSpan(new RelativeSizeSpan(0.5f), topStringBuilder.length() - 1, topStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + topStringBuilder.setSpan(new RelativeSizeSpan(0.4f), topStringBuilder.length() - 1, topStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); CharSequence participants = replaceTags(getString("BoostingGiveawayMsgParticipants", R.string.BoostingGiveawayMsgParticipants)); topStringBuilder.append(participants); - topStringBuilder.setSpan(new RelativeSizeSpan(1.05f), giveawayPrizes.length() + subTitle.length() + 2, giveawayPrizes.length() + subTitle.length() + 3 + participants.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + topStringBuilder.setSpan(new RelativeSizeSpan(1.05f), subTitleBuilder.length() + 2, subTitleBuilder.length() + 2 + participants.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); topStringBuilder.append("\n"); if (giveaway.only_new_subscribers) { @@ -267,10 +313,14 @@ public class GiveawayMessageCell { bottomStringBuilder.append("\n"); bottomStringBuilder.append(formatString("formatDateAtTime", R.string.formatDateAtTime, monthTxt, timeTxt)); + titleLayout = StaticLayoutEx.createStaticLayout(titleStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxWidth, 10); topLayout = StaticLayoutEx.createStaticLayout(topStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxWidth, 10); - bottomLayout = StaticLayoutEx.createStaticLayout(bottomStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxWidth, 10); + bottomLayout = StaticLayoutEx.createStaticLayout(bottomStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(3), false, TextUtils.TruncateAt.END, maxWidth, 10); int maxRowLength = 0; + for (int a = 0; a < titleLayout.getLineCount(); ++a) { + maxRowLength = (int) Math.max(maxRowLength, Math.ceil(titleLayout.getLineWidth(a))); + } for (int a = 0; a < topLayout.getLineCount(); ++a) { maxRowLength = (int) Math.max(maxRowLength, Math.ceil(topLayout.getLineWidth(a))); } @@ -282,6 +332,14 @@ public class GiveawayMessageCell { maxRowLength = dp(180); } + if (giveaway.prize_description != null && !giveaway.prize_description.isEmpty()) { + CharSequence txt = Emoji.replaceEmoji(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingGiveawayMsgPrizes", giveaway.quantity, giveaway.prize_description)), countriesTextPaint.getFontMetricsInt(), false); + additionPrizeLayout = StaticLayoutEx.createStaticLayout(txt, textPaint, maxRowLength, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxRowLength, 20); + additionPrizeHeight = additionPrizeLayout.getLineBottom(additionPrizeLayout.getLineCount() - 1) + dp(22); + textDivider = LocaleController.getString("BoostingGiveawayMsgWithDivider", R.string.BoostingGiveawayMsgWithDivider); + textDividerWidth = textDividerPaint.measureText(textDivider, 0, textDivider.length()); + } + if (giveaway.countries_iso2.size() > 0) { List countriesWithFlags = new ArrayList<>(); for (String iso2 : giveaway.countries_iso2) { @@ -308,7 +366,8 @@ public class GiveawayMessageCell { giftReceiver.setImageCoords((maxWidth / 2f) - (giftSize / 2f), AndroidUtilities.dp(42) - giftSize / 2f, giftSize, giftSize); - topHeight = topLayout.getLineBottom(topLayout.getLineCount() - 1); + titleHeight = titleLayout.getLineBottom(titleLayout.getLineCount() - 1) + dp(5); + topHeight = titleHeight + additionPrizeHeight + topLayout.getLineBottom(topLayout.getLineCount() - 1); bottomHeight = bottomLayout.getLineBottom(bottomLayout.getLineCount() - 1); countriesHeight = countriesLayout != null ? (countriesLayout.getLineBottom(countriesLayout.getLineCount() - 1) + dp(4 + 8)) : 0; @@ -341,10 +400,10 @@ public class GiveawayMessageCell { if (chat != null) { avatarVisible[i] = true; chats[i] = chat; - CharSequence text = Emoji.replaceEmoji(chat.title, chatTextPaint.getFontMetricsInt(), dp(14), false); + CharSequence text = Emoji.replaceEmoji(chat.title, chatTextPaint.getFontMetricsInt(), false); chatTitles[i] = TextUtils.ellipsize(text, chatTextPaint, maxWidth * 0.8f, TextUtils.TruncateAt.END); chatTitleWidths[i] = chatTextPaint.measureText(chatTitles[i], 0, chatTitles[i].length()); - float oneRowWidth = chatTitleWidths[i] + dp(24 + 6 + 12); + float oneRowWidth = chatTitleWidths[i] + dp(24 + 6 + 10); oneRowTotalWidth += oneRowWidth; if (i > 0) { needNewRow[i] = oneRowTotalWidth > maxWidth * 0.9f; @@ -370,6 +429,9 @@ public class GiveawayMessageCell { } private int getChatColor(TLRPC.Chat chat, Theme.ResourcesProvider resourcesProvider) { + if (messageObject.isOutOwner()) { + return Theme.getColor(Theme.key_chat_outPreviewInstantText, resourcesProvider); + } final int color; int colorId = ChatObject.getColorId(chat); if (colorId < 7) { @@ -378,7 +440,7 @@ public class GiveawayMessageCell { MessagesController.PeerColors peerColors = MessagesController.getInstance(UserConfig.selectedAccount).peerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); if (peerColor != null) { - color = peerColor.getColor1(); + color = peerColor.getColor(0, resourcesProvider); } else { color = Theme.getColor(Theme.keys_avatar_nameInMessage[0], resourcesProvider); } @@ -396,6 +458,8 @@ public class GiveawayMessageCell { } textPaint.setColor(Theme.chat_msgTextPaint.getColor()); + textDividerPaint.setColor(Theme.multAlpha(Theme.chat_msgTextPaint.getColor(), 0.45f)); + lineDividerPaint.setColor(Theme.multAlpha(Theme.chat_msgTextPaint.getColor(), 0.15f)); countriesTextPaint.setColor(Theme.chat_msgTextPaint.getColor()); if (messageObject.isOutOwner()) { @@ -444,6 +508,24 @@ public class GiveawayMessageCell { canvas.save(); canvas.translate(diffTextWidth / 2f, 0); + titleLayout.draw(canvas); + canvas.translate(0, titleHeight); + + if (additionPrizeLayout != null) { + canvas.restore(); + canvas.save(); + float textDividerCY = titleHeight + additionPrizeHeight - dp(22 - 16); + float textDividerCX = measuredWidth / 2f; + canvas.drawText(textDivider, textDividerCX, textDividerCY, textDividerPaint); + canvas.drawLine(dp(17), textDividerCY - dp(4), textDividerCX - textDividerWidth / 2f - dp(6), textDividerCY - dp(4), lineDividerPaint); + canvas.drawLine(textDividerCX + textDividerWidth / 2f + dp(6), textDividerCY - dp(4), measuredWidth - dp(16), textDividerCY - dp(4), lineDividerPaint); + canvas.translate((measuredWidth - additionPrizeLayout.getWidth()) / 2f, titleHeight); + additionPrizeLayout.draw(canvas); + canvas.restore(); + canvas.save(); + canvas.translate(diffTextWidth / 2f, additionPrizeHeight + titleHeight); + } + topLayout.draw(canvas); canvas.restore(); canvas.translate(0, topHeight + dp(6)); @@ -458,7 +540,7 @@ public class GiveawayMessageCell { float rowWidth = 0; do { - rowWidth += chatTitleWidths[k] + dp(24 + 6 + 12); + rowWidth += chatTitleWidths[k] + dp(24 + 6 + 10); k++; } while (k < avatarVisible.length && !needNewRow[k] && avatarVisible[k]); @@ -478,7 +560,7 @@ public class GiveawayMessageCell { chatBgPaint.setAlpha(25); avatarImageReceivers[k].draw(canvas); canvas.drawText(chatTitles[k], 0, chatTitles[k].length(), dp(24 + 6), dp(16), chatTextPaint); - chatRect.set(0, 0, chatTitleWidths[k] + dp(24 + 6 + 12), dp(24)); + chatRect.set(0, 0, chatTitleWidths[k] + dp(24 + 6 + 10), dp(24)); canvas.drawRoundRect(chatRect, dp(12), dp(12), chatBgPaint); clickRect[k].set(xRow, y, (int) (xRow + chatRect.width()), y + dp(24)); @@ -524,7 +606,9 @@ public class GiveawayMessageCell { } public void onDetachedFromWindow() { - giftReceiver.onDetachedFromWindow(); + if (giftReceiver != null) { + giftReceiver.onDetachedFromWindow(); + } if (avatarImageReceivers != null) { for (ImageReceiver avatarImageReceiver : avatarImageReceivers) { avatarImageReceiver.onDetachedFromWindow(); @@ -533,7 +617,9 @@ public class GiveawayMessageCell { } public void onAttachedToWindow() { - giftReceiver.onAttachedToWindow(); + if (giftReceiver != null) { + giftReceiver.onAttachedToWindow(); + } if (avatarImageReceivers != null) { for (ImageReceiver avatarImageReceiver : avatarImageReceivers) { avatarImageReceiver.onAttachedToWindow(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayResultsMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayResultsMessageCell.java new file mode 100644 index 000000000..f3a6a2be9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayResultsMessageCell.java @@ -0,0 +1,652 @@ +package org.telegram.ui.Components.Premium.boosts.cells.msg; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.getPluralString; +import static org.telegram.messenger.LocaleController.getString; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.ClickableSpan; +import android.text.style.RelativeSizeSpan; +import android.util.StateSet; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.Premium.boosts.BoostDialogs; +import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.LaunchActivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class GiveawayResultsMessageCell { + + private ImageReceiver[] avatarImageReceivers; + private AvatarDrawable[] avatarDrawables; + private final ChatMessageCell parentView; + private ImageReceiver giftReceiver; + private RLottieDrawable giftDrawable; + + private CharSequence[] userTitles; + private TLRPC.User[] users; + private float[] userTitleWidths; + private boolean[] needNewRow; + private Rect[] clickRect; + private boolean[] avatarVisible; + private int measuredHeight = 0; + private int measuredWidth = 0; + + private int titleHeight; + private int topHeight; + private int bottomHeight; + private int countriesHeight; + private String counterStr; + private int diffTextWidth; + + private StaticLayout titleLayout; + private StaticLayout topLayout; + private StaticLayout bottomLayout; + private StaticLayout countriesLayout; + + private TextPaint counterTextPaint; + private TextPaint chatTextPaint; + private TextPaint textPaint; + private TextPaint textDividerPaint; + private TextPaint countriesTextPaint; + private Paint counterBgPaint; + private Paint chatBgPaint; + + private Paint saveLayerPaint; + private Paint clipRectPaint; + private RectF countRect; + private RectF chatRect; + private Rect counterTextBounds; + private Rect containerRect; + private int[] pressedState; + + private int selectorColor; + private Drawable selectorDrawable; + private MessageObject messageObject; + private int pressedPos = -1; + private boolean isButtonPressed = false; + private boolean isContainerPressed = false; + private SpannableStringBuilder topStringBuilder; + private int subTitleMarginTop; + private int subTitleMarginLeft; + private LinkSpanDrawable.LinkCollector links; + + public GiveawayResultsMessageCell(ChatMessageCell parentView) { + this.parentView = parentView; + } + + private void init() { + if (counterTextPaint != null) { + return; + } + counterTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + chatTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textDividerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + countriesTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + counterBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + chatBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + saveLayerPaint = new Paint(); + clipRectPaint = new Paint(); + countRect = new RectF(); + chatRect = new RectF(); + counterTextBounds = new Rect(); + containerRect = new Rect(); + pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + + userTitles = new CharSequence[10]; + users = new TLRPC.User[10]; + userTitleWidths = new float[10]; + needNewRow = new boolean[10]; + clickRect = new Rect[10]; + + giftReceiver = new ImageReceiver(parentView); + giftReceiver.setAllowLoadingOnAttachedOnly(true); + + clipRectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + counterTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + counterTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + counterTextPaint.setTextSize(dp(12)); + counterTextPaint.setTextAlign(Paint.Align.CENTER); + chatTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + chatTextPaint.setTextSize(dp(13)); + countriesTextPaint.setTextSize(dp(13)); + textPaint.setTextSize(dp(14)); + textDividerPaint.setTextSize(dp(14)); + textDividerPaint.setTextAlign(Paint.Align.CENTER); + } + + public boolean checkMotionEvent(MotionEvent event) { + if (messageObject == null || !messageObject.isGiveawayResults()) { + return false; + } + + if (links == null) { + links = new LinkSpanDrawable.LinkCollector(parentView); + } + + int action = event.getAction(); + int x = (int) event.getX(); + int y = (int) event.getY(); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { + if (topStringBuilder != null && topLayout != null && (y - subTitleMarginTop) > 0) { + int line = topLayout.getLineForVertical(y - subTitleMarginTop - dp(10)); + int off = topLayout.getOffsetForHorizontal(line, x - subTitleMarginLeft); + ClickableSpan[] link = topStringBuilder.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + if (action == MotionEvent.ACTION_UP) { + links.clear(); + link[0].onClick(parentView); + } else { + LinkSpanDrawable pressedLink = new LinkSpanDrawable<>(link[0], null, x, y); + links.addLink(pressedLink); + try { + int start = topStringBuilder.getSpanStart(link[0]); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(topLayout, start, subTitleMarginLeft, subTitleMarginTop); + topLayout.getSelectionPath(start, topStringBuilder.getSpanEnd(link[0]), path); + } catch (Exception e) { + FileLog.e(e); + } + } + return true; + } else { + links.clear(); + } + parentView.invalidate(); + } + } + + if (action == MotionEvent.ACTION_DOWN) { + for (int i = 0; i < clickRect.length; i++) { + Rect rect = clickRect[i]; + if (rect.contains(x, y)) { + pressedPos = i; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selectorDrawable.setHotspot(x, y); + } + isButtonPressed = true; + setButtonPressed(true); + return true; + } + } + if (containerRect.contains(x, y)) { + isContainerPressed = true; + return true; + } + } else if (action == MotionEvent.ACTION_UP) { + if (isButtonPressed) { + if (parentView.getDelegate() != null) { + parentView.getDelegate().didPressGiveawayChatButton(parentView, pressedPos); + } + parentView.playSoundEffect(SoundEffectConstants.CLICK); + setButtonPressed(false); + isButtonPressed = false; + } + if (isContainerPressed) { + isContainerPressed = false; + BoostDialogs.showBulletinAbout(messageObject); + } + } else if (action == MotionEvent.ACTION_MOVE) { + + } else if (action == MotionEvent.ACTION_CANCEL) { + links.clear(); + if (isButtonPressed) { + setButtonPressed(false); + } + isButtonPressed = false; + isContainerPressed = false; + } + return false; + } + + public void setButtonPressed(boolean pressed) { + if (messageObject == null || !messageObject.isGiveawayResults() || selectorDrawable == null) { + return; + } + if (links != null) { + links.clear(); + } + if (pressed) { + selectorDrawable.setCallback(new Drawable.Callback() { + @Override + public void invalidateDrawable(@NonNull Drawable who) { + parentView.invalidate(); + } + + @Override + public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { + parentView.invalidate(); + } + + @Override + public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { + parentView.invalidate(); + } + }); + selectorDrawable.setState(pressedState); + parentView.invalidate(); + } else { + selectorDrawable.setState(StateSet.NOTHING); + parentView.invalidate(); + } + } + + public void setMessageContent(MessageObject messageObject, int parentWidth, int forwardedNameWidth) { + this.messageObject = null; + titleLayout = null; + topLayout = null; + bottomLayout = null; + countriesLayout = null; + measuredHeight = 0; + measuredWidth = 0; + if (!messageObject.isGiveawayResults()) { + return; + } + this.messageObject = messageObject; + init(); + createImages(); + setGiftImage(); + TLRPC.TL_messageMediaGiveawayResults giveaway = (TLRPC.TL_messageMediaGiveawayResults) messageObject.messageOwner.media; + checkArraysLimits(giveaway.winners.size()); + + int giftSize = AndroidUtilities.dp(90); + int maxWidth = AndroidUtilities.dp(230); + + CharSequence winnersSelected = replaceTags(getString("BoostingGiveawayResultsMsgWinnersSelected", R.string.BoostingGiveawayResultsMsgWinnersSelected)); + SpannableStringBuilder titleStringBuilder = new SpannableStringBuilder(winnersSelected); + titleStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, winnersSelected.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + topStringBuilder = new SpannableStringBuilder(); + String subTitleText = getPluralString("BoostingGiveawayResultsMsgWinnersTitle", giveaway.winners_count); + SpannableStringBuilder subTitleWithLink = AndroidUtilities.replaceSingleTag( + subTitleText, + Theme.key_chat_messageLinkIn, 0, + () -> AndroidUtilities.runOnUIThread(() -> { + if (messageObject.getDialogId() == -giveaway.channel_id) { + parentView.getDelegate().didPressReplyMessage(parentView, giveaway.launch_msg_id); + } else { + Bundle bundle = new Bundle(); + bundle.putLong("chat_id", giveaway.channel_id); + bundle.putInt("message_id", giveaway.launch_msg_id); + LaunchActivity.getLastFragment().presentFragment(new ChatActivity(bundle)); + } + }) + ); + topStringBuilder.append(AndroidUtilities.replaceCharSequence("%1$d", subTitleWithLink, replaceTags("**" + giveaway.winners_count + "**"))); + + topStringBuilder.append("\n\n"); + topStringBuilder.setSpan(new RelativeSizeSpan(0.4f), topStringBuilder.length() - 1, topStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + CharSequence winners = replaceTags(getPluralString("BoostingGiveawayResultsMsgWinners", giveaway.winners_count)); + topStringBuilder.append(winners); + topStringBuilder.setSpan(new RelativeSizeSpan(1.05f), subTitleWithLink.length() + 2, subTitleWithLink.length() + 2 + winners.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + SpannableStringBuilder bottomStringBuilder = new SpannableStringBuilder(); + if (giveaway.winners_count != giveaway.winners.size()) { + bottomStringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayResultsMsgAllAndMoreWinners", giveaway.winners_count - giveaway.winners.size()))); + bottomStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, bottomStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + bottomStringBuilder.append("\n"); + } + bottomStringBuilder.append(LocaleController.getString("BoostingGiveawayResultsMsgAllWinnersReceivedLinks", R.string.BoostingGiveawayResultsMsgAllWinnersReceivedLinks)); + + titleLayout = StaticLayoutEx.createStaticLayout(titleStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxWidth, 10); + topLayout = StaticLayoutEx.createStaticLayout(topStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(2), false, TextUtils.TruncateAt.END, maxWidth, 10); + bottomLayout = StaticLayoutEx.createStaticLayout(bottomStringBuilder, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, AndroidUtilities.dp(3), false, TextUtils.TruncateAt.END, maxWidth, 10); + + int oldMaxWidth = maxWidth; + maxWidth = Math.max(forwardedNameWidth, maxWidth); + diffTextWidth = maxWidth - oldMaxWidth; + + giftReceiver.setImageCoords((maxWidth / 2f) - (giftSize / 2f), AndroidUtilities.dp(70) - giftSize / 2f, giftSize, giftSize); + + titleHeight = titleLayout.getLineBottom(titleLayout.getLineCount() - 1) + dp(5); + topHeight = titleHeight + topLayout.getLineBottom(topLayout.getLineCount() - 1); + bottomHeight = bottomLayout.getLineBottom(bottomLayout.getLineCount() - 1); + countriesHeight = countriesLayout != null ? (countriesLayout.getLineBottom(countriesLayout.getLineCount() - 1) + dp(4 + 8)) : 0; + + measuredHeight += topHeight; + measuredHeight += countriesHeight; + measuredHeight += bottomHeight; + measuredHeight += dp(32 + 96); //gift + measuredWidth = maxWidth; + + counterStr = "x" + giveaway.winners_count; + counterTextPaint.getTextBounds(counterStr, 0, counterStr.length(), counterTextBounds); + + Arrays.fill(avatarVisible, false); + + float oneRowTotalWidth = 0; + measuredHeight += dp(24 + 6); + + List visibleChannels = new ArrayList<>(giveaway.winners.size()); + for (Long uid : giveaway.winners) { + TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(uid); + if (user != null) { + visibleChannels.add(uid); + } + } + + for (int i = 0; i < visibleChannels.size(); i++) { + long uid = visibleChannels.get(i); + TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(uid); + + if (user != null) { + avatarVisible[i] = true; + users[i] = user; + CharSequence text = Emoji.replaceEmoji(UserObject.getUserName(user), chatTextPaint.getFontMetricsInt(), false); + userTitles[i] = TextUtils.ellipsize(text, chatTextPaint, maxWidth * 0.8f, TextUtils.TruncateAt.END); + userTitleWidths[i] = chatTextPaint.measureText(userTitles[i], 0, userTitles[i].length()); + float oneRowWidth = userTitleWidths[i] + dp(24 + 6 + 10); + oneRowTotalWidth += oneRowWidth; + if (i > 0) { + needNewRow[i] = oneRowTotalWidth > maxWidth * 0.9f; + if (needNewRow[i]) { + oneRowTotalWidth = oneRowWidth; + measuredHeight += dp(24 + 6); + } + } else { + needNewRow[i] = false; + } + avatarDrawables[i].setInfo(user); + avatarImageReceivers[i].setForUserOrChat(user, avatarDrawables[i]); + avatarImageReceivers[i].setImageCoords(0, 0, dp(24), dp(24)); + } else { + users[i] = null; + avatarVisible[i] = false; + userTitles[i] = ""; + needNewRow[i] = false; + userTitleWidths[i] = dp(20); + avatarDrawables[i].setInfo(uid, "", ""); + } + } + } + + private int getUserColor(TLRPC.User user, Theme.ResourcesProvider resourcesProvider) { + if (messageObject.isOutOwner()) { + return Theme.getColor(Theme.key_chat_outPreviewInstantText, resourcesProvider); + } + final int color; + int colorId = UserObject.getColorId(user); + if (colorId < 7) { + color = Theme.getColor(Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); + } else { + MessagesController.PeerColors peerColors = MessagesController.getInstance(UserConfig.selectedAccount).peerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (peerColor != null) { + color = peerColor.getColor1(); + } else { + color = Theme.getColor(Theme.keys_avatar_nameInMessage[0], resourcesProvider); + } + } + return color; + } + + public void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesProvider resourcesProvider) { + if (messageObject == null || !messageObject.isGiveawayResults()) { + return; + } + + if (selectorDrawable == null) { + selectorDrawable = Theme.createRadSelectorDrawable(selectorColor = Theme.getColor(Theme.key_listSelector), 12, 12); + } + + textPaint.setColor(Theme.chat_msgTextPaint.getColor()); + textDividerPaint.setColor(Theme.getColor(Theme.key_dialogTextGray2)); + countriesTextPaint.setColor(Theme.chat_msgTextPaint.getColor()); + + if (messageObject.isOutOwner()) { + chatTextPaint.setColor(Theme.getColor(Theme.key_chat_outPreviewInstantText, resourcesProvider)); + counterBgPaint.setColor(Theme.getColor(Theme.key_chat_outPreviewInstantText, resourcesProvider)); + chatBgPaint.setColor(Theme.getColor(Theme.key_chat_outReplyLine, resourcesProvider)); + } else { + chatTextPaint.setColor(Theme.getColor(Theme.key_chat_inPreviewInstantText, resourcesProvider)); + counterBgPaint.setColor(Theme.getColor(Theme.key_chat_inPreviewInstantText, resourcesProvider)); + chatBgPaint.setColor(Theme.getColor(Theme.key_chat_inReplyLine, resourcesProvider)); + } + + int x = 0, y = 0; + canvas.save(); + x = marginLeft - dp(4); + y = marginTop; + canvas.translate(x, y); + containerRect.set(x, y, getMeasuredWidth() + x, getMeasuredHeight() + y); + + canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), saveLayerPaint, Canvas.ALL_SAVE_FLAG); + giftReceiver.draw(canvas); + + float centerX = getMeasuredWidth() / 2f; + float centerY = dp(106); + int textWidth = counterTextBounds.width() + dp(12); + int textHeight = counterTextBounds.height() + dp(10); + countRect.set( + centerX - ((textWidth + dp(2)) / 2f), + centerY - ((textHeight + dp(2)) / 2f), + centerX + ((textWidth + dp(2)) / 2f), + centerY + ((textHeight + dp(2)) / 2f) + ); + canvas.drawRoundRect(countRect, dp(11), dp(11), clipRectPaint); + countRect.set( + centerX - ((textWidth) / 2f), + centerY - ((textHeight) / 2f), + centerX + ((textWidth) / 2f), + centerY + ((textHeight) / 2f) + ); + canvas.drawRoundRect(countRect, dp(10), dp(10), counterBgPaint); + canvas.drawText(counterStr, countRect.centerX(), countRect.centerY() + dp(4), counterTextPaint); + canvas.restore(); + + canvas.translate(0, dp(32 + 96)); + y += dp(32 + 96); + subTitleMarginTop = y + titleHeight; + subTitleMarginLeft = (int) (x + diffTextWidth / 2f); + + canvas.save(); + canvas.translate(diffTextWidth / 2f, 0); + titleLayout.draw(canvas); + canvas.translate(0, titleHeight); + + topLayout.draw(canvas); + canvas.restore(); + canvas.translate(0, topHeight + dp(6)); + y += topHeight + dp(6); + + int selectedChatColor = 0; + int i = 0; + while (i < avatarVisible.length) { + if (avatarVisible[i]) { + canvas.save(); + int k = i; + float rowWidth = 0; + + do { + rowWidth += userTitleWidths[k] + dp(24 + 6 + 10); + k++; + } while (k < avatarVisible.length && !needNewRow[k] && avatarVisible[k]); + + float marginItemsLeft = centerX - (rowWidth / 2f); + canvas.translate(marginItemsLeft, 0); + int xRow = x + (int) (marginItemsLeft); + + k = i; + + do { + int chatColor = getUserColor(users[k], resourcesProvider); + if (pressedPos >= 0 && pressedPos == k) { + selectedChatColor = chatColor; + } + chatTextPaint.setColor(chatColor); + chatBgPaint.setColor(chatColor); + chatBgPaint.setAlpha(25); + avatarImageReceivers[k].draw(canvas); + canvas.drawText(userTitles[k], 0, userTitles[k].length(), dp(24 + 6), dp(16), chatTextPaint); + chatRect.set(0, 0, userTitleWidths[k] + dp(24 + 6 + 10), dp(24)); + canvas.drawRoundRect(chatRect, dp(12), dp(12), chatBgPaint); + + clickRect[k].set(xRow, y, (int) (xRow + chatRect.width()), y + dp(24)); + + canvas.translate(chatRect.width() + dp(6), 0); + xRow += chatRect.width() + dp(6); + + k++; + } while (k < avatarVisible.length && !needNewRow[k] && avatarVisible[k]); + + i = k; + + canvas.restore(); + canvas.translate(0, dp(24 + 6)); + y += dp(24 + 6); + } else { + i++; + } + } + + if (countriesLayout != null) { + canvas.save(); + canvas.translate((measuredWidth - countriesLayout.getWidth()) / 2f, dp(4)); + countriesLayout.draw(canvas); + canvas.restore(); + canvas.translate(0, countriesHeight); + } + + canvas.translate(0, dp(6)); + canvas.save(); + canvas.translate(diffTextWidth / 2f, 0); + bottomLayout.draw(canvas); + canvas.restore(); + canvas.restore(); + if (pressedPos >= 0) { + int rippleColor = Theme.multAlpha(selectedChatColor, Theme.isCurrentThemeDark() ? 0.12f : 0.10f); + if (selectorColor != rippleColor) { + Theme.setSelectorDrawableColor(selectorDrawable, selectorColor = rippleColor, true); + } + selectorDrawable.setBounds(clickRect[pressedPos]); + selectorDrawable.draw(canvas); + } + + if (links != null && links.draw(canvas)) { + parentView.invalidate(); + } + } + + public void onDetachedFromWindow() { + if (giftReceiver != null) { + giftReceiver.onDetachedFromWindow(); + } + if (avatarImageReceivers != null) { + for (ImageReceiver avatarImageReceiver : avatarImageReceivers) { + avatarImageReceiver.onDetachedFromWindow(); + } + } + } + + public void onAttachedToWindow() { + if (giftReceiver != null) { + giftReceiver.onAttachedToWindow(); + } + if (avatarImageReceivers != null) { + for (ImageReceiver avatarImageReceiver : avatarImageReceivers) { + avatarImageReceiver.onAttachedToWindow(); + } + } + } + + public int getMeasuredHeight() { + return measuredHeight; + } + + public int getMeasuredWidth() { + return measuredWidth; + } + + private void createImages() { + if (avatarImageReceivers != null) { + return; + } + + avatarImageReceivers = new ImageReceiver[10]; + avatarDrawables = new AvatarDrawable[10]; + avatarVisible = new boolean[10]; + for (int a = 0; a < avatarImageReceivers.length; a++) { + avatarImageReceivers[a] = new ImageReceiver(parentView); + avatarImageReceivers[a].setAllowLoadingOnAttachedOnly(true); + avatarImageReceivers[a].setRoundRadius(AndroidUtilities.dp(12)); + avatarDrawables[a] = new AvatarDrawable(); + avatarDrawables[a].setTextSize(AndroidUtilities.dp(18)); + clickRect[a] = new Rect(); + } + } + + private void checkArraysLimits(int channelsCount) { + if (avatarImageReceivers.length < channelsCount) { + int oldLength = avatarImageReceivers.length; + avatarImageReceivers = Arrays.copyOf(avatarImageReceivers, channelsCount); + avatarDrawables = Arrays.copyOf(avatarDrawables, channelsCount); + avatarVisible = Arrays.copyOf(avatarVisible, channelsCount); + userTitles = Arrays.copyOf(userTitles, channelsCount); + userTitleWidths = Arrays.copyOf(userTitleWidths, channelsCount); + needNewRow = Arrays.copyOf(needNewRow, channelsCount); + clickRect = Arrays.copyOf(clickRect, channelsCount); + users = Arrays.copyOf(users, channelsCount); + + for (int i = oldLength - 1; i < channelsCount; i++) { + avatarImageReceivers[i] = new ImageReceiver(parentView); + avatarImageReceivers[i].setAllowLoadingOnAttachedOnly(true); + avatarImageReceivers[i].setRoundRadius(AndroidUtilities.dp(12)); + avatarDrawables[i] = new AvatarDrawable(); + avatarDrawables[i].setTextSize(AndroidUtilities.dp(18)); + clickRect[i] = new Rect(); + } + } + } + + private void setGiftImage() { + giftReceiver.setAllowStartLottieAnimation(false); + if (giftDrawable == null) { + giftDrawable = new RLottieDrawable(R.raw.giveaway_results, "" + R.raw.giveaway_results, dp(120), dp(120)); + } + giftReceiver.setImageBitmap(giftDrawable); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorHeaderCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorHeaderCell.java index 469f7b609..01a2598c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorHeaderCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorHeaderCell.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components.Premium.boosts.cells.selector; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; @@ -81,7 +83,11 @@ public class SelectorHeaderCell extends FrameLayout { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure( MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(56), MeasureSpec.EXACTLY) + MeasureSpec.makeMeasureSpec(getHeaderHeight(), MeasureSpec.EXACTLY) ); } + + protected int getHeaderHeight() { + return dp(56); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorLetterCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorLetterCell.java index d5448547c..1785e1abb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorLetterCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorLetterCell.java @@ -33,7 +33,7 @@ public class SelectorLetterCell extends FrameLayout { } public void setLetter(String letter) { - textView.setText(letter.toUpperCase()); + textView.setText(letter); } private int getThemedColor(int key) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorSearchCell.java index dec759408..197eb665f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorSearchCell.java @@ -140,6 +140,10 @@ public class SelectorSearchCell extends ScrollView { }); } + public void setHintText(String text, boolean animated) { + editText.setHintText(text, animated); + } + private final AnimatedFloat topGradientAlpha = new AnimatedFloat(this, 0, 300, CubicBezierInterpolator.EASE_OUT_QUINT); private final LinearGradient topGradient = new LinearGradient(0, 0, 0, dp(8), new int[]{0xff000000, 0x00000000}, new float[]{0, 1}, Shader.TileMode.CLAMP); private final Paint topGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java index 0a219c4f3..011d52bf4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java @@ -26,7 +26,7 @@ import java.util.Locale; public class RadialProgress2 { - private RectF progressRect = new RectF(); + public RectF progressRect = new RectF(); private View parent; private boolean previousCheckDrawable; @@ -36,21 +36,21 @@ public class RadialProgress2 { private Paint miniProgressBackgroundPaint; private Paint overlayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint circleMiniPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private MediaActionDrawable mediaActionDrawable; + public MediaActionDrawable mediaActionDrawable; private MediaActionDrawable miniMediaActionDrawable; private float miniIconScale = 1.0f; private int circleColor; private int circlePressedColor; - private int iconColor; + public int iconColor; private int iconPressedColor; private int circleColorKey = -1; private int circleCrossfadeColorKey = -1; private float circleCrossfadeColorProgress; private float circleCheckProgress = 1.0f; private int circlePressedColorKey = -1; - private int iconColorKey = -1; + public int iconColorKey = -1; private int iconPressedColorKey = -1; private ImageReceiver overlayImageView; private int circleRadius; @@ -70,6 +70,8 @@ public class RadialProgress2 { private int maxIconSize; private float overlayImageAlpha = 1f; + public float iconScale = 1f; + public RadialProgress2(View parentView) { this(parentView, null); } @@ -452,6 +454,10 @@ public class RadialProgress2 { if (maxIconSize > 0 && iconSize > maxIconSize) { iconSize = maxIconSize; } + if (iconScale != 1f) { + canvas.save(); + canvas.scale(iconScale, iconScale, centerX, centerY); + } mediaActionDrawable.setBounds(centerX - iconSize, centerY - iconSize, centerX + iconSize, centerY + iconSize); mediaActionDrawable.setHasOverlayImage(overlayImageView.hasBitmapImage()); if ((drawMiniIcon || circleCrossfadeColorKey >= 0)) { @@ -522,6 +528,9 @@ public class RadialProgress2 { canvas.restoreToCount(restore); } } + if (iconScale != 1f) { + canvas.restore(); + } } public int getCircleColorKey() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java index 9e18824f4..594a3b2b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -134,7 +134,7 @@ public class ReactedUsersListView extends FrameLayout { @Override public int getItemCount() { - return userReactions.size() + (!customReactionsEmoji.isEmpty() && !MessagesController.getInstance(currentAccount).premiumLocked ? 1 : 0); + return userReactions.size() + (!customReactionsEmoji.isEmpty() && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() ? 1 : 0); } @Override @@ -180,7 +180,7 @@ public class ReactedUsersListView extends FrameLayout { loadingView.setIsSingleCell(true); loadingView.setItemsCount(predictiveCount); addView(loadingView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - if (!addPadding && filter != null && filter instanceof TLRPC.TL_reactionCustomEmoji && !MessagesController.getInstance(currentAccount).premiumLocked) { + if (!addPadding && filter != null && filter instanceof TLRPC.TL_reactionCustomEmoji && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { customReactionsEmoji.clear(); customReactionsEmoji.add(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(filter)); updateCustomReactionsButton(); @@ -346,7 +346,7 @@ public class ReactedUsersListView extends FrameLayout { setIds.add(stickerSet.id); } } - if (MessagesController.getInstance(currentAccount).premiumLocked) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { return; } customEmojiStickerSets.addAll(sets); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java index 8d27acfc4..739b4193e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java @@ -708,12 +708,14 @@ public class ChatCustomReactionsEditActivity extends BaseFragment implements Not emojiKeyboardVisible = false; editText.clearFocus(); updateScrollViewMarginBottom(0); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); bottomDialogLayout.animate().setListener(null).cancel(); bottomDialogLayout.animate().translationY(bottomDialogLayout.getMeasuredHeight()).setDuration(350).withLayer().setInterpolator(CubicBezierInterpolator.DEFAULT).setUpdateListener(animation -> { actionButton.setTranslationY(-(1f - (float) animation.getAnimatedValue()) * bottomDialogLayout.getMeasuredHeight()); }).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); bottomDialogLayout.setVisibility(View.INVISIBLE); } }).start(); 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 95846a567..0c3c43dc4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -567,11 +567,11 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } public boolean showCustomEmojiReaction() { - return (!MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable) || showExpandableReactions; + return allReactionsAvailable || showExpandableReactions; } private boolean showUnlockPremiumButton() { - return !premiumLockedReactions.isEmpty() && !MessagesController.getInstance(currentAccount).premiumLocked; + return !premiumLockedReactions.isEmpty() && !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); } private void showUnlockPremium(float x, float y) { @@ -1085,7 +1085,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio fillRecentReactionsList(visibleReactions); } filterReactions(visibleReactions); - showExpandableReactions = !allReactionsAvailable && visibleReactions.size() > 16; + showExpandableReactions = !allReactionsAvailable && visibleReactions.size() > 16 || allReactionsAvailable && !UserConfig.getInstance(currentAccount).isPremium() && MessagesController.getInstance(currentAccount).premiumFeaturesBlocked(); setVisibleReactionsList(visibleReactions); if (message != null && message.messageOwner.reactions != null && message.messageOwner.reactions.results != null) { 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 0a1d27176..f07567be2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -59,6 +59,8 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ChatActionCell; +import org.telegram.ui.Cells.ChatMessageCell; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1256,6 +1258,7 @@ public class RecyclerListView extends RecyclerView { for (int a = 0; a < 2; a++) { for (int i = count - 1; i >= 0; i--) { final View child = getChildAt(i); + if ((child instanceof ChatMessageCell || child instanceof ChatActionCell) && child.getVisibility() == View.INVISIBLE) continue; final float translationX = a == 0 ? child.getTranslationX() : 0; final float translationY = a == 0 ? child.getTranslationY() : 0; if (x >= child.getLeft() + translationX 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 e5bf8e323..bc2e55cc3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java @@ -52,7 +52,7 @@ public class ReplyMessageLine { private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji; private long emojiDocumentId; - private int backgroundColor, nameColor, color1, color2, color3; + public int backgroundColor, nameColor, color1, color2, color3; private final View parentView; public final AnimatedColor backgroundColorAnimated; public final AnimatedColor color1Animated, color2Animated, color3Animated; @@ -129,9 +129,9 @@ public class ReplyMessageLine { hasColor2 = hasColor3 = false; return; } - color1 = peerColor.getColor1(dark); - color2 = peerColor.getColor2(dark); - color3 = peerColor.getColor3(dark); + color1 = peerColor.getColor(0, resourcesProvider); + color2 = peerColor.getColor(1, resourcesProvider); + color3 = peerColor.getColor(2, resourcesProvider); hasColor2 = color2 != color1; hasColor3 = color3 != color1; if (hasColor3) { @@ -170,8 +170,14 @@ public class ReplyMessageLine { colorId = messageObject.overrideLinkColor; } else if (messageObject.isSponsored() && messageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = messageObject.sponsoredChatInvite.color; + if (type == TYPE_LINK && messageObject.sponsoredChatInvite.chat != null) { + emojiDocumentId = ChatObject.getEmojiId(messageObject.sponsoredChatInvite.chat); + } } else if (messageObject.isSponsored() && messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { colorId = ChatObject.getColorId(messageObject.sponsoredChatInvite.chat); + if (type == TYPE_LINK) { + emojiDocumentId = ChatObject.getEmojiId(messageObject.sponsoredChatInvite.chat); + } } else if (messageObject.messageOwner != null && messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.from_id != null) { long dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.fwd_from.from_id); if (dialogId < 0) { @@ -179,20 +185,35 @@ public class ReplyMessageLine { if (chat != null) { colorId = ChatObject.getColorId(chat); } + if (type == TYPE_LINK) { + emojiDocumentId = ChatObject.getEmojiId(chat); + } } else { TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(dialogId); if (user != null) { colorId = UserObject.getColorId(user); } + if (type == TYPE_LINK) { + emojiDocumentId = UserObject.getEmojiId(user); + } } } else if (DialogObject.isEncryptedDialog(messageObject.getDialogId()) && currentUser != null) { TLRPC.User user = messageObject.isOutOwner() ? UserConfig.getInstance(messageObject.currentAccount).getCurrentUser() : currentUser; if (user == null) user = currentUser; colorId = UserObject.getColorId(user); + if (type == TYPE_LINK) { + emojiDocumentId = UserObject.getEmojiId(user); + } } else if (messageObject.isFromUser() && currentUser != null) { colorId = UserObject.getColorId(currentUser); + if (type == TYPE_LINK) { + emojiDocumentId = UserObject.getEmojiId(currentUser); + } } else if (messageObject.isFromChannel() && currentChat != null) { colorId = ChatObject.getColorId(currentChat); + if (type == TYPE_LINK) { + emojiDocumentId = ChatObject.getEmojiId(currentChat); + } } else { colorId = 0; } @@ -256,8 +277,12 @@ public class ReplyMessageLine { color1 = color2 = color3 = Color.WHITE; backgroundColor = Color.TRANSPARENT; nameColor = Theme.getColor(Theme.key_chat_stickerReplyNameText, resourcesProvider); - } else if (messageObject.isOutOwner()) { - color1 = color2 = color3 = Theme.getColor(hasColor2 || hasColor3 ? Theme.key_chat_outReplyLine2 : Theme.key_chat_outReplyLine, resourcesProvider); + } else if (messageObject.isOutOwner() || type == TYPE_CODE) { + if (type == TYPE_CODE && !messageObject.isOutOwner()) { + color1 = color2 = color3 = Theme.getColor(Theme.key_chat_inCodeBackground, resourcesProvider); + } else { + color1 = color2 = color3 = Theme.getColor(hasColor2 || hasColor3 ? Theme.key_chat_outReplyLine2 : Theme.key_chat_outReplyLine, resourcesProvider); + } if (hasColor3) { reversedOut = true; color1 = Theme.multAlpha(color1, .20f); @@ -269,7 +294,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 && messageObject != null && messageObject.overrideLinkEmoji != -1) { + if ((type == TYPE_REPLY || type == TYPE_LINK) && messageObject != null && messageObject.overrideLinkEmoji != -1) { emojiDocumentId = messageObject.overrideLinkEmoji; } if (emojiDocumentId != 0 && emoji == null) { @@ -445,6 +470,13 @@ public class ReplyMessageLine { drawBackground(canvas, rect, alpha, false, false); } + private float emojiOffsetX, emojiOffsetY; + public ReplyMessageLine offsetEmoji(float ox, float oy) { + this.emojiOffsetX = ox; + this.emojiOffsetY = oy; + return this; + } + public void drawBackground(Canvas canvas, RectF rect, float alpha, boolean hasQuote, boolean emojiOnly) { if (!emojiOnly) { backgroundPath.rewind(); @@ -465,18 +497,19 @@ public class ReplyMessageLine { new IconCoords(30, 3, .78f, .9f), new IconCoords(46, -17, .6f, .6f), new IconCoords(69.66f, -0.666f, .87f, .7f), - new IconCoords(107, -12.6f, 1.03f, .3f), + new IconCoords(98, -12.6f, 1.03f, .3f), new IconCoords(51, 24, 1f, .5f), new IconCoords(6.33f, 20, .77f, .7f), new IconCoords(-19, 12, .8f, .6f, true), - new IconCoords(26, 42, .78f, .9f), +// new IconCoords(26, 42, .78f, .9f), new IconCoords(-22, 36, .7f, .5f, true), - new IconCoords(-1, 48, 1f, .4f), +// new IconCoords(-1, 48, 1f, .4f), }; } canvas.save(); canvas.clipRect(rect); + canvas.translate(emojiOffsetX, emojiOffsetY); float x0 = Math.max(rect.right - dp(15), rect.centerX()); if (hasQuote) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 657d457f2..7494d5536 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -465,7 +465,7 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie } private boolean isSpeedItemVisible() { - if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumLocked) { + if (UserConfig.getInstance(currentAccount).isPremium() || MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { return false; } for (MessageObject obj : selectedFiles.values()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java index 7f097e142..ddd1b0cad 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java @@ -39,9 +39,16 @@ public class SeekBar { default void onSeekBarContinuousDrag(float progress) { } - default void onSeekBarPressed() {} default void onSeekBarReleased() {} + + default boolean isSeekBarDragAllowed() { + return true; + } + + default boolean reverseWaveform() { + return false; + } } private static Paint paint; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java index ce66c1e6e..9bd9c1b70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java @@ -8,11 +8,14 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.RectF; import android.graphics.Shader; import android.os.SystemClock; import android.util.Log; @@ -25,6 +28,8 @@ import androidx.core.math.MathUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; import java.util.ArrayList; @@ -94,6 +99,9 @@ public class SeekBarWaveform { public void setWaveform(byte[] waveform) { waveformBytes = waveform; heights = calculateHeights((int) (width / AndroidUtilities.dpf2(3))); + if (!delegate.isSeekBarDragAllowed()) { + this.progress = 1f; + } } public void setSelected(boolean value) { @@ -117,11 +125,21 @@ public class SeekBarWaveform { appearFloat.setParent(view); } + public void invalidate() { + if (parentView != null) { + parentView.invalidate(); + } + } + public boolean isStartDraging() { return startDraging; } public boolean onTouch(int action, float x, float y) { + if (!delegate.isSeekBarDragAllowed()) { + this.progress = 1f; + return false; + } if (action == MotionEvent.ACTION_DOWN) { if (0 <= x && x <= width && y >= 0 && y <= height) { startX = x; @@ -173,6 +191,10 @@ public class SeekBarWaveform { } public void setProgress(float progress, boolean animated) { + if (!delegate.isSeekBarDragAllowed()) { + this.progress = 1f; + return; + } this.progress = isUnread ? 1f : progress; int currentThumbX = isUnread ? width : thumbX; if (animated && currentThumbX != 0 && progress == 0) { @@ -267,6 +289,28 @@ public class SeekBarWaveform { return heights; } + private boolean exploding = false; + public float explodeProgress; + public void explodeAt(float progress) { + exploding = true; + explodeProgress = progress; + invalidate(); + } + public float explosionRate; + public void setExplosionRate(float explosionRate) { + this.explosionRate = explosionRate; + invalidate(); + } + public void stopExploding() { + exploding = false; + if (particles != null) { + particles.clear(); + } + invalidate(); + } + + private Particles particles; + public void draw(Canvas canvas, View parentView) { if (waveformBytes == null || width == 0 || alpha <= 0) { return; @@ -299,6 +343,7 @@ public class SeekBarWaveform { alphaPath.reset(); } + final boolean reverse = delegate != null && delegate.reverseWaveform(); if (fromHeights != null && toHeights != null) { float t = (width - fromWidth) / (float) (toWidth - fromWidth); int maxlen = Math.max(fromHeights.length, toHeights.length); @@ -312,12 +357,12 @@ public class SeekBarWaveform { int l = MathUtils.clamp((int) Math.floor(barNum / (float) maxlen * minlen), 0, minlen - 1); if (k < l) { float x = AndroidUtilities.lerp((float) l, (float) barNum, T) * AndroidUtilities.dpf2(3); - float h = AndroidUtilities.dpf2(AndroidUtilities.lerp(minarr[l], maxarr[barNum], T)); + float h = AndroidUtilities.dpf2(AndroidUtilities.lerp(minarr[reverse ? minarr.length - 1 - l : l], maxarr[reverse ? maxarr.length - 1 - barNum : barNum], T)); addBar(path, x, h); k = l; } else { float x = AndroidUtilities.lerp((float) l, (float) barNum, T) * AndroidUtilities.dpf2(3); - float h = AndroidUtilities.dpf2(AndroidUtilities.lerp(minarr[l], maxarr[barNum], T)); + float h = AndroidUtilities.dpf2(AndroidUtilities.lerp(minarr[reverse ? minarr.length - 1 - l : l], maxarr[reverse ? maxarr.length - 1 - barNum : barNum], T)); addBar(alphaPath, x, h); alpha = T; } @@ -329,12 +374,18 @@ public class SeekBarWaveform { } float x = barNum * AndroidUtilities.dpf2(3); float bart = MathUtils.clamp(appearProgress * totalBarsCount - barNum, 0, 1); - float h = AndroidUtilities.dpf2(heights[barNum]) * bart; + float h = AndroidUtilities.dpf2(heights[reverse ? heights.length - 1 - barNum : barNum]) * bart; h -= AndroidUtilities.dpf2(1) * (1f - bart); addBar(path, x, h); } } + if (exploding || explosionRate > 0) { + canvas.save(); + final float w = totalBarsCount * AndroidUtilities.dpf2(3); + canvas.clipRect(0, 0, w * (1f - explodeProgress * explosionRate), height); + } + if (alpha > 0) { canvas.save(); canvas.clipPath(alphaPath); @@ -346,6 +397,39 @@ public class SeekBarWaveform { canvas.clipPath(path); drawFill(canvas, this.alpha); canvas.restore(); + + if (exploding || explosionRate > 0) { + canvas.restore(); + if (particles == null) { + particles = new Particles(250, this::invalidate); + } + RectF emitArea = null; + if (explodeProgress < .99f && heights != null) { + int barNum = (int) (totalBarsCount * (1f - explodeProgress)); + if (reverse) { + barNum = (int) (totalBarsCount - 1 - barNum); + } + if (barNum >= 0 && barNum < heights.length) { + float bart = MathUtils.clamp(appearProgress * totalBarsCount - barNum, 0, 1); + float h = AndroidUtilities.dpf2(heights[barNum]) * bart; + emitArea = AndroidUtilities.rectTmp; + final float x = (totalBarsCount * (1f - explodeProgress)) * AndroidUtilities.dpf2(3); + final float strokeWidth = AndroidUtilities.dpf2(2); + final int y = (height - dp(14)) / 2; + h *= waveScaling; + AndroidUtilities.rectTmp.set( + x + AndroidUtilities.dpf2(1) - strokeWidth / 2f, + y + dp(7) + (-h - strokeWidth / 2f), + x + AndroidUtilities.dpf2(1) + strokeWidth / 2f, + y + dp(7) + (h + strokeWidth / 2f) + ); + } + } + particles + .setColor(outerColor) + .setEmitArea(emitArea) + .draw(canvas, explosionRate); + } } private void drawFill(Canvas canvas, float alpha) { @@ -368,7 +452,7 @@ public class SeekBarWaveform { } if (loadingT > 0f) { - if (loadingPaint == null || Math.abs(loadingPaintWidth - width) > AndroidUtilities.dp(8) || loadingPaintColor1 != innerColor || loadingPaintColor2 != outerColor) { + if (loadingPaint == null || Math.abs(loadingPaintWidth - width) > dp(8) || loadingPaintColor1 != innerColor || loadingPaintColor2 != outerColor) { if (loadingPaint == null) { loadingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @@ -393,13 +477,13 @@ public class SeekBarWaveform { private void addBar(Path path, float x, float h) { final float strokeWidth = AndroidUtilities.dpf2(2); - final int y = (height - AndroidUtilities.dp(14)) / 2; + final int y = (height - dp(14)) / 2; h *= waveScaling; AndroidUtilities.rectTmp.set( x + AndroidUtilities.dpf2(1) - strokeWidth / 2f, - y + AndroidUtilities.dp(7) + (-h - strokeWidth / 2f), + y + dp(7) + (-h - strokeWidth / 2f), x + AndroidUtilities.dpf2(1) + strokeWidth / 2f, - y + AndroidUtilities.dp(7) + (h + strokeWidth / 2f) + y + dp(7) + (h + strokeWidth / 2f) ); path.addRoundRect(AndroidUtilities.rectTmp, strokeWidth, strokeWidth, Path.Direction.CW); } @@ -417,4 +501,83 @@ public class SeekBarWaveform { parentView.invalidate(); } } + + public static class Particles { + private final int count; + private Runnable invalidate; + private final ArrayList particles = new ArrayList<>(50); + private final ArrayList deadParticles = new ArrayList<>(50); + + public Particles(int count, Runnable invalidate) { + this.count = count; + this.invalidate = invalidate; + paint.setStrokeWidth(dp(1.33f)); + } + + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private class Particle { + float x, y, v, vx, vy, t, d; + } + + public Particles setColor(int color) { + paint.setColor(color); + return this; + } + + private RectF emitArea; + public Particles setEmitArea(RectF emitArea) { + this.emitArea = emitArea; + return this; + } + + public void clear() { + deadParticles.addAll(particles); + particles.clear(); + } + + private long lastTime; + public void draw(Canvas canvas, float alpha) { + final long now = System.currentTimeMillis(); + final long dt = Math.min(20, (now - lastTime)); + lastTime = now; + for (int i = 0; i < particles.size(); ++i) { + Particle p = particles.get(i); + p.t -= dt / p.d; + if (p.t < 0) { + deadParticles.add(p); + particles.remove(i); + i--; + } else { + p.x += p.vx * p.v * dt / 500.0f; + p.y += p.vy * p.v * dt / 500.0f; + p.vy -= dp(0.33f) * dt / 500.0f; + } + } + if (emitArea != null) { + int count = Math.min(4, this.count - particles.size()); +// double vx = Math.sin(Math.PI / 180.0 * (0 - 90)); +// double vy = -Math.cos(Math.PI / 180.0 * (0 - 90)); + for (int i = 0; i < count; ++i) { + Particle p = deadParticles.isEmpty() ? new Particle() :deadParticles.remove(0); + p.x = emitArea.left + emitArea.width() * Utilities.random.nextFloat(); + p.y = emitArea.top + emitArea.height() * Utilities.random.nextFloat(); + double angle = (Math.PI / 180.0) * (Utilities.random.nextInt(200) - 125); + p.vx = (float) (Math.cos(angle) - Math.sin(angle)) * .8f; + p.vy = (float) (Math.sin(angle) + Math.cos(angle)) - .2f; + p.t = 1f; + p.v = AndroidUtilities.dp(10 + Utilities.random.nextFloat() * 7); + p.d = AndroidUtilities.lerp(420, 550, Utilities.random.nextFloat()); + particles.add(p); + } + } + for (int i = 0; i < particles.size(); ++i) { + Particle p = particles.get(i); + paint.setAlpha((int) (0xFF * alpha * p.t)); + canvas.drawPoint(p.x, p.y, paint); + } + if (invalidate != null) { + invalidate.run(); + } + } + } } 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 b29d2f4c7..8888144a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -148,6 +148,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi private int containerViewTop = -1; private boolean fullyShown = false; private boolean includeStory; + public boolean includeStoryFromMessage; private ChatActivity parentFragment; private Activity parentActivity; @@ -1569,11 +1570,13 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi AndroidUtilities.updateViewVisibilityAnimated(searchGridView, false, 1f, false); } + protected void onShareStory(View cell) { + + } + private void selectDialog(View cell, TLRPC.Dialog dialog) { if (dialog instanceof ShareDialogsAdapter.MyStoryDialog) { - LongSparseArray dids = new LongSparseArray<>(); - dids.put(Long.MAX_VALUE, dialog); - onSend(dids, 1, null); + onShareStory(cell); return; } if (topicsGridView.getVisibility() != View.GONE || parentActivity == null) { @@ -2480,7 +2483,15 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi View view; switch (viewType) { case 0: { - view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE, resourcesProvider); + view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE, resourcesProvider) { + @Override + protected String repostToCustomName() { + if (includeStoryFromMessage) { + return LocaleController.getString(R.string.RepostToStory); + } + return super.repostToCustomName(); + } + }; view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); break; } @@ -2499,6 +2510,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi if (holder.getItemViewType() == 0) { ShareDialogCell cell = (ShareDialogCell) holder.itemView; TLRPC.Dialog dialog = getItem(position); + if (dialog == null) return; cell.setTopic(selectedDialogTopics.get(dialog), false); cell.setDialog(dialog.id, selectedDialogs.indexOfKey(dialog.id) >= 0, null); } @@ -3163,7 +3175,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); } return; } 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 2b6692f31..1063714f7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -58,6 +58,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.recyclerview.widget.GridLayoutManager; @@ -105,6 +106,7 @@ import org.telegram.ui.ArticleViewer; import org.telegram.ui.CalendarActivity; import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ContextLinkCell; +import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DividerCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.LoadingCell; @@ -2285,6 +2287,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return super.drawChild(canvas, child, drawingTime); } + @Override + public Integer getSelectorColor(int position) { + if (getAdapter() == channelRecommendationsAdapter && channelRecommendationsAdapter.more > 0 && position == channelRecommendationsAdapter.getItemCount() - 1) { + return 0; + } + return super.getSelectorColor(position); + } }; mediaPages[a].listView.setFastScrollEnabled(RecyclerListView.FastScroll.DATE_TYPE); @@ -2438,7 +2447,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter onItemClick(position, view, messageObject, 0, mediaPage.selectedType); } } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { - if (view instanceof ProfileSearchCell && position >= 0 && position < channelRecommendationsAdapter.chats.size()) { + if ((view instanceof ProfileSearchCell || y < dp(60)) && position >= 0 && position < channelRecommendationsAdapter.chats.size()) { Bundle args = new Bundle(); args.putLong("chat_id", channelRecommendationsAdapter.chats.get(position).id); profileActivity.presentFragment(new ChatActivity(args)); @@ -2513,13 +2522,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return onItemLongClick(messageObject, view, mediaPage.selectedType); } } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { - Bundle args = new Bundle(); - args.putLong("chat_id", channelRecommendationsAdapter.chats.get(position).id); - final BaseFragment fragment = new ChatActivity(args); - if (profileActivity instanceof ProfileActivity) { - ((ProfileActivity) profileActivity).prepareBlurBitmap(); - } - profileActivity.presentFragmentAsPreview(fragment); + channelRecommendationsAdapter.openPreview(position); return true; } return false; @@ -3404,7 +3407,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } - if (mediaPage.selectedType == 7) { + if (mediaPage.selectedType == TAB_GROUPUSERS) { } else if (mediaPage.selectedType == TAB_STORIES) { if (storiesAdapter.storiesList != null && firstVisibleItem + visibleItemCount > storiesAdapter.storiesList.getLoadedCount() - mediaColumnsCount[1]) { @@ -3522,7 +3525,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[0].selectedType != TAB_ARCHIVED_STORIES && mediaPages[0].selectedType != TAB_VOICE && mediaPages[0].selectedType != TAB_GIF && - mediaPages[0].selectedType != TAB_COMMON_GROUPS + mediaPages[0].selectedType != TAB_COMMON_GROUPS && + mediaPages[0].selectedType != TAB_RECOMMENDED_CHANNELS ); } @@ -4651,8 +4655,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else if (id == NotificationCenter.channelRecommendationsLoaded) { long chatId = (long) args[0]; if (chatId == -dialog_id) { - channelRecommendationsAdapter.update(); + channelRecommendationsAdapter.update(true); updateTabs(true); + checkCurrentTabValid(); } } } @@ -4982,7 +4987,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if ((hasMedia[6] <= 0) == scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { changed++; } - hasRecommendations = DialogObject.isChatDialog(dialog_id) && MessagesController.ChannelRecommendations.hasRecommendations(profileActivity.getCurrentAccount(), -dialog_id); + hasRecommendations = !channelRecommendationsAdapter.chats.isEmpty(); if (hasRecommendations != scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { changed++; } @@ -5332,11 +5337,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } } - if (mediaPages[a].selectedType == 6) { + if (mediaPages[a].selectedType == TAB_COMMON_GROUPS) { if (!commonGroupsAdapter.loading && !commonGroupsAdapter.endReached && commonGroupsAdapter.chats.isEmpty()) { commonGroupsAdapter.getChats(0, 100); } - } else if (mediaPages[a].selectedType == 7) { + } else if (mediaPages[a].selectedType == TAB_GROUPUSERS) { } else if (mediaPages[a].selectedType == TAB_STORIES) { StoriesController.StoriesList storiesList = storiesAdapter.storiesList; @@ -5348,7 +5353,9 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter archivedStoriesAdapter.load(false); mediaPages[a].emptyView.showProgress(storiesList != null && (storiesList.isLoading() || hasInternet() && storiesList.getCount() > 0), animated); fastScrollVisible = storiesList != null && storiesList.getCount() > 0; - } else if (mediaPages[a].selectedType != TAB_RECOMMENDED_CHANNELS) { + } else if (mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { + + } 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; documentsAdapter.notifyDataSetChanged(); @@ -6819,31 +6826,36 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public ChannelRecommendationsAdapter(Context context) { mContext = context; - update(); + update(false); } - public void update() { + public void update(boolean notify) { if (profileActivity == null || !DialogObject.isChatDialog(dialog_id)) { return; } - TLRPC.Chat chat = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChat(-dialog_id); - if (chat == null || !ChatObject.isChannelAndNotMegaGroup(chat)) { + TLRPC.Chat thisChat = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChat(-dialog_id); + if (thisChat == null || !ChatObject.isChannelAndNotMegaGroup(thisChat)) { return; } - MessagesController.ChannelRecommendations rec = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChannelRecommendations(chat.id); + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(profileActivity.getCurrentAccount()).getChannelRecommendations(thisChat.id); chats.clear(); if (rec != null) { - chats.addAll(rec.chats); - more = UserConfig.getInstance(profileActivity.getCurrentAccount()).isPremium() ? 0 : rec.more; - } else { - more = 0; + for (int i = 0; i < rec.chats.size(); ++i) { + TLRPC.Chat chat = rec.chats.get(i); + if (chat != null && ChatObject.isNotInChat(chat)) { + chats.add(chat); + } + } + } + more = chats.isEmpty() || UserConfig.getInstance(profileActivity.getCurrentAccount()).isPremium() ? 0 : rec.more; + if (notify) { + notifyDataSetChanged(); } - notifyDataSetChanged(); } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == 0; + return true; } @Override @@ -6860,12 +6872,6 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter profileActivity.presentFragment(new PremiumPreviewFragment("similar_channels")); } }); - cell.setOnClickListener(v -> { - if (chats.size() <= 0) return; - Bundle args = new Bundle(); - args.putLong("chat_id", chats.get(chats.size() - 1).id); - profileActivity.presentFragment(new ChatActivity(args)); - }); view = cell; } else { // 0 view = new ProfileSearchCell(mContext, resourcesProvider); @@ -6874,6 +6880,52 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter return new RecyclerListView.Holder(view); } + public void openPreview(int position) { + if (position < 0 || position >= chats.size()) return; + TLRPC.Chat chat = chats.get(position); + + Bundle args = new Bundle(); + args.putLong("chat_id", chat.id); + final BaseFragment fragment = new ChatActivity(args); + if (profileActivity instanceof ProfileActivity) { + ((ProfileActivity) profileActivity).prepareBlurBitmap(); + } + + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert, resourcesProvider, ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_SHOWN_FROM_BOTTOM); + previewMenu.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + + ActionBarMenuSubItem openChannel = new ActionBarMenuSubItem(getContext(), false, false); + openChannel.setTextAndIcon(LocaleController.getString(R.string.OpenChannel2), R.drawable.msg_channel); + openChannel.setMinimumWidth(160); + openChannel.setOnClickListener(view -> { + if (profileActivity != null && profileActivity.getParentLayout() != null) { + profileActivity.getParentLayout().expandPreviewFragment(); + } + }); + previewMenu.addView(openChannel); + + ActionBarMenuSubItem joinChannel = new ActionBarMenuSubItem(getContext(), false, false); + joinChannel.setTextAndIcon(LocaleController.getString(R.string.ProfileJoinChannel), R.drawable.msg_addbot); + joinChannel.setMinimumWidth(160); + joinChannel.setOnClickListener(view -> { + profileActivity.finishPreviewFragment(); + chat.left = false; + update(false); + notifyItemRemoved(position); + if (chats.isEmpty()) { + updateTabs(true); + checkCurrentTabValid(); + } + profileActivity.getNotificationCenter().postNotificationName(NotificationCenter.channelRecommendationsLoaded, -dialog_id); + profileActivity.getMessagesController().addUserToChat(chat.id, profileActivity.getUserConfig().getCurrentUser(), 0, null, profileActivity, () -> { + BulletinFactory.of(profileActivity).createSimpleBulletin(R.raw.contact_check, LocaleController.formatString(R.string.YouJoinedChannel, chat == null ? "" : chat.title)).show(); + }); + }); + previewMenu.addView(joinChannel); + + profileActivity.presentFragmentAsPreviewWithMenu(fragment, previewMenu); + } + @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ProfileSearchCell cell = null; @@ -6909,11 +6961,6 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter private final ButtonWithCounterView button; private final LinkSpanDrawable.LinksTextView textView; - @Override - public void setOnClickListener(@Nullable OnClickListener l) { - channelCell.setOnClickListener(l); - } - public MoreRecommendationsCell(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, Runnable onPremiumClick) { super(context); 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 e207e00a5..1db8830bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java @@ -4,6 +4,7 @@ import android.graphics.drawable.Drawable; import android.view.View; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DialogObject; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -31,16 +32,14 @@ public class StatusBadgeComponent { if (chat != null && chat.verified) { statusDrawable.set(verifiedDrawable = (verifiedDrawable == null ? new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable) : verifiedDrawable), animated); statusDrawable.setColor(null); - return statusDrawable; - } - if (user != null && user.verified) { + } else if (chat != null && DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + statusDrawable.set(DialogObject.getEmojiStatusDocumentId(chat.emoji_status), animated); + statusDrawable.setColor(null); + } 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 && user.emoji_status instanceof TLRPC.TL_emojiStatus) { - statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); - statusDrawable.setColor(null); - } else if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); + } else if (user != null && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0) { + statusDrawable.set(DialogObject.getEmojiStatusDocumentId(user.emoji_status), animated); statusDrawable.setColor(null); } else if (user != null && user.premium) { statusDrawable.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java index 984f189be..44fbdfea1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java @@ -189,7 +189,7 @@ public class StickerSetBulletinLayout extends Bulletin.TwoLineLayout { subtitleTextView.setVisibility(ViewPagerFixed.GONE); break; case TYPE_REPLACED_TO_FAVORITES: - if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium() && !MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium() && !MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked()) { titleTextView.setText(LocaleController.formatString("LimitReachedFavoriteStickers", R.string.LimitReachedFavoriteStickers, MessagesController.getInstance(UserConfig.selectedAccount).stickersFavedLimitDefault)); CharSequence str = AndroidUtilities.premiumText(LocaleController.formatString("LimitReachedFavoriteStickersSubtitle", R.string.LimitReachedFavoriteStickersSubtitle, MessagesController.getInstance(UserConfig.selectedAccount).stickersFavedLimitPremium), () -> { Activity activity = AndroidUtilities.findActivity(context); @@ -204,7 +204,7 @@ public class StickerSetBulletinLayout extends Bulletin.TwoLineLayout { } break; case TYPE_REPLACED_TO_FAVORITES_GIFS: - if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium() && !MessagesController.getInstance(UserConfig.selectedAccount).premiumLocked) { + if (!MessagesController.getInstance(UserConfig.selectedAccount).premiumFeaturesBlocked()) { titleTextView.setText(LocaleController.formatString("LimitReachedFavoriteGifs", R.string.LimitReachedFavoriteGifs, MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitDefault)); CharSequence str = AndroidUtilities.premiumText(LocaleController.formatString("LimitReachedFavoriteGifsSubtitle", R.string.LimitReachedFavoriteGifsSubtitle, MessagesController.getInstance(UserConfig.selectedAccount).savedGifsLimitPremium), () -> { Activity activity = AndroidUtilities.findActivity(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java new file mode 100644 index 000000000..929773470 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java @@ -0,0 +1,1115 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.SurfaceTexture; +import android.opengl.EGL14; +import android.opengl.EGLExt; +import android.opengl.GLES20; +import android.opengl.GLES31; +import android.opengl.GLUtils; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; +import android.view.Choreographer; +import android.view.Surface; +import android.view.TextureView; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.zxing.common.detector.MathUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DispatchQueue; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.BaseCell; +import org.telegram.ui.Cells.ChatActionCell; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.ChatActivity; + +import java.util.ArrayList; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL10; + +public class ThanosEffect extends TextureView { + + private static Boolean nothanos = null; + public static boolean supports() { + if (nothanos == null) { + nothanos = MessagesController.getGlobalMainSettings().getBoolean("nothanos", false); + } + return (nothanos == null || !nothanos) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + } + + private DrawingThread drawThread; + + private final Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + if (drawThread != null) { + drawThread.requestDraw(); + if (drawThread.running) { + Choreographer.getInstance().postFrameCallback(this); + } + } + } + }; + + private final ArrayList toSet = new ArrayList<>(); + private static class ToSet { + public final View view; + public final ArrayList views; + public final Runnable startCallback, doneCallback; + + public final Bitmap bitmap; + public final Matrix matrix; + public ToSet(View view, Runnable callback) { + this.view = view; + this.views = null; + this.startCallback = null; + this.doneCallback = callback; + this.bitmap = null; + this.matrix = null; + } + public ToSet(ArrayList views, Runnable callback) { + this.view = null; + this.views = views; + this.startCallback = null; + this.doneCallback = callback; + this.bitmap = null; + this.matrix = null; + } + public ToSet(Matrix matrix, Bitmap bitmap, Runnable startCallback, Runnable doneCallback) { + this.view = null; + this.views = null; + this.startCallback = startCallback; + this.doneCallback = doneCallback; + this.matrix = matrix; + this.bitmap = bitmap; + } + } + + private Runnable whenDone; + public ThanosEffect(@NonNull Context context, Runnable whenDoneCallback) { + super(context); + this.whenDone = whenDoneCallback; + setOpaque(false); + setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { + @Override + public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { + if (drawThread != null) { + drawThread.kill(); + drawThread = null; + } + drawThread = new DrawingThread(surface, ThanosEffect.this::invalidate, ThanosEffect.this::destroy, width, height); + if (!toSet.isEmpty()) { + for (int i = 0; i < toSet.size(); ++i) { + ToSet toSetObj = toSet.get(i); + if (toSetObj.bitmap != null) { + drawThread.animate(toSetObj.matrix, toSetObj.bitmap, toSetObj.startCallback, toSetObj.doneCallback); + } else if (toSetObj.views != null) { + drawThread.animateGroup(toSetObj.views, toSetObj.doneCallback); + } else { + drawThread.animate(toSetObj.view, toSetObj.doneCallback); + } + } + toSet.clear(); + Choreographer.getInstance().postFrameCallback(frameCallback); + } + } + + @Override + public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { + if (drawThread != null) { + drawThread.resize(width, height); + } + } + + @Override + public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { + if (drawThread != null) { + drawThread.kill(); + drawThread = null; + } + if (whenDone != null) { + Runnable runnable = whenDone; + whenDone = null; + runnable.run(); + } + return false; + } + + @Override + public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { + + } + }); + } + + private void destroy() { + if (whenDone != null) { + Runnable runnable = whenDone; + whenDone = null; + runnable.run(); + } + } + + public void scroll(int dx, int dy) { + if (drawThread != null && drawThread.running) { +// post(() -> drawThread.scroll(dx, dy)); + } + } + + public void animateGroup(ArrayList views, Runnable whenDone) { + if (drawThread != null) { + drawThread.animateGroup(views, whenDone); + Choreographer.getInstance().postFrameCallback(frameCallback); + } else { + toSet.add(new ToSet(views, whenDone)); + } + } + + public void animate(View view, Runnable whenDone) { + if (drawThread != null) { + drawThread.animate(view, whenDone); + Choreographer.getInstance().postFrameCallback(frameCallback); + } else { + toSet.add(new ToSet(view, whenDone)); + } + } + + public void animate(Matrix matrix, Bitmap bitmap, Runnable whenStarted, Runnable whenDone) { + if (drawThread != null) { + drawThread.animate(matrix, bitmap, whenStarted, whenDone); + Choreographer.getInstance().postFrameCallback(frameCallback); + } else { + toSet.add(new ToSet(matrix, bitmap, whenStarted, whenDone)); + } + } + + private static class DrawingThread extends DispatchQueue { + + private boolean alive = true; + private final SurfaceTexture surfaceTexture; + private final Runnable invalidate; + private Runnable destroy; + private int width, height; + + public DrawingThread(SurfaceTexture surfaceTexture, Runnable invalidate, Runnable destroy, int width, int height) { + super("ThanosEffect.DrawingThread", false); + + this.surfaceTexture = surfaceTexture; + this.invalidate = invalidate; + this.destroy = destroy; + this.width = width; + this.height = height; + + start(); + } + + public final static int DO_DRAW = 0; + public final static int DO_RESIZE = 1; + public final static int DO_KILL = 2; + public final static int DO_ADD_ANIMATION = 3; + public final static int DO_SCROLL = 4; + + @Override + public void handleMessage(Message inputMessage) { + switch (inputMessage.what) { + case DO_DRAW: { + draw(); + return; + } + case DO_RESIZE: { + resizeInternal(inputMessage.arg1, inputMessage.arg2); + draw(); + return; + } + case DO_KILL: { + killInternal(); + return; + } + case DO_ADD_ANIMATION: { + addAnimationInternal((Animation) inputMessage.obj); + return; + } + case DO_SCROLL: { + for (int i = 0; i < pendingAnimations.size(); ++i) { + Animation anim = pendingAnimations.get(i); + anim.offsetLeft += inputMessage.arg1; + anim.offsetTop += inputMessage.arg2; + } + return; + } + } + } + + @Override + public void run() { + try { + init(); + } catch (Exception e) { + FileLog.e(e); + for (int i = 0; i < toAddAnimations.size(); ++i) { + Animation animation = toAddAnimations.get(i); + if (animation.startCallback != null) { + AndroidUtilities.runOnUIThread(animation.startCallback); + } + animation.done(false); + } + toAddAnimations.clear(); + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getGlobalMainSettings().edit().putBoolean("nothanos", nothanos = true).apply(); + }); + killInternal(); + return; + } + if (!toAddAnimations.isEmpty()) { + for (int i = 0; i < toAddAnimations.size(); ++i) { + addAnimationInternal(toAddAnimations.get(i)); + } + toAddAnimations.clear(); + } + super.run(); + } + + public void requestDraw() { + Handler handler = getHandler(); + if (handler != null) { + handler.sendMessage(handler.obtainMessage(DO_DRAW)); + } + } + + public void resize(int width, int height) { + Handler handler = getHandler(); + if (handler != null) { + handler.sendMessage(handler.obtainMessage(DO_RESIZE, width, height)); + } + } + + public void scroll(int dx, int dy) { + Handler handler = getHandler(); + if (handler != null) { + handler.sendMessage(handler.obtainMessage(DO_SCROLL, dx, dy)); + } + } + + private void resizeInternal(int width, int height) { + if (!alive) return; + this.width = width; + this.height = height; + GLES31.glViewport(0, 0, width, height); + GLES31.glUniform2f(sizeHandle, width, height); + } + + public void kill() { + Handler handler = getHandler(); + if (handler != null) { + handler.sendMessage(handler.obtainMessage(DO_KILL)); + } + } + + private void killInternal() { + if (!alive) return; + alive = false; + for (int i = 0; i < pendingAnimations.size(); ++i) { + Animation animation = pendingAnimations.get(i); + animation.done(false); + } + if (surfaceTexture != null) { + surfaceTexture.release(); + } + Looper looper = Looper.myLooper(); + if (looper != null) { + looper.quit(); + } + if (destroy != null) { + AndroidUtilities.runOnUIThread(destroy); + destroy = null; + } + } + + private EGL10 egl; + private EGLDisplay eglDisplay; + private EGLConfig eglConfig; + private EGLSurface eglSurface; + private EGLContext eglContext; + + private int drawProgram; + + private int matrixHandle; + private int resetHandle; + private int timeHandle; + private int deltaTimeHandle; + private int particlesCountHandle; + private int sizeHandle; + private int gridSizeHandle; + private int rectSizeHandle; + private int seedHandle; + private int rectPosHandle; + private int textureHandle; + private int densityHandle; + private int longevityHandle; + private int offsetHandle; + + public volatile boolean running; + private final ArrayList pendingAnimations = new ArrayList<>(); + + private void init() { + egl = (EGL10) javax.microedition.khronos.egl.EGLContext.getEGL(); + + eglDisplay = egl.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if (eglDisplay == egl.EGL_NO_DISPLAY) { + killInternal(); + return; + } + int[] version = new int[2]; + if (!egl.eglInitialize(eglDisplay, version)) { + killInternal(); + return; + } + + int[] configAttributes = { + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_ALPHA_SIZE, 8, + EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR, + EGL14.EGL_NONE + }; + EGLConfig[] eglConfigs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!egl.eglChooseConfig(eglDisplay, configAttributes, eglConfigs, 1, numConfigs)) { + kill(); + return; + } + eglConfig = eglConfigs[0]; + + int[] contextAttributes = { + EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, + EGL14.EGL_NONE + }; + eglContext = egl.eglCreateContext(eglDisplay, eglConfig, egl.EGL_NO_CONTEXT, contextAttributes); + if (eglContext == null) { + killInternal(); + return; + } + + eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surfaceTexture, null); + if (eglSurface == null) { + killInternal(); + return; + } + + if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + killInternal(); + return; + } + + int vertexShader = GLES31.glCreateShader(GLES31.GL_VERTEX_SHADER); + int fragmentShader = GLES31.glCreateShader(GLES31.GL_FRAGMENT_SHADER); + if (vertexShader == 0 || fragmentShader == 0) { + killInternal(); + return; + } + GLES31.glShaderSource(vertexShader, RLottieDrawable.readRes(null, R.raw.thanos_vertex) + "\n// " + Math.random()); + GLES31.glCompileShader(vertexShader); + int[] status = new int[1]; + GLES31.glGetShaderiv(vertexShader, GLES31.GL_COMPILE_STATUS, status, 0); + if (status[0] != GLES31.GL_TRUE) { + FileLog.e("ThanosEffect, compile vertex shader error: " + GLES31.glGetShaderInfoLog(vertexShader)); + GLES31.glDeleteShader(vertexShader); + killInternal(); + return; + } + GLES31.glShaderSource(fragmentShader, RLottieDrawable.readRes(null, R.raw.thanos_fragment) + "\n// " + Math.random()); + GLES31.glCompileShader(fragmentShader); + GLES31.glGetShaderiv(fragmentShader, GLES31.GL_COMPILE_STATUS, status, 0); + if (status[0] != GLES31.GL_TRUE) { + FileLog.e("ThanosEffect, compile fragment shader error: " + GLES31.glGetShaderInfoLog(fragmentShader)); + GLES31.glDeleteShader(fragmentShader); + killInternal(); + return; + } + drawProgram = GLES31.glCreateProgram(); + if (drawProgram == 0) { + killInternal(); + return; + } + GLES31.glAttachShader(drawProgram, vertexShader); + GLES31.glAttachShader(drawProgram, fragmentShader); + + String[] feedbackVaryings = { "outUV", "outPosition", "outVelocity", "outTime" }; + GLES31.glTransformFeedbackVaryings(drawProgram, feedbackVaryings, GLES31.GL_INTERLEAVED_ATTRIBS); + GLES31.glLinkProgram(drawProgram); + GLES31.glGetProgramiv(drawProgram, GLES31.GL_LINK_STATUS, status, 0); + if (status[0] != GLES31.GL_TRUE) { + FileLog.e("ThanosEffect, link program error: " + GLES31.glGetProgramInfoLog(drawProgram)); + killInternal(); + return; + } + + matrixHandle = GLES31.glGetUniformLocation(drawProgram, "matrix"); + rectSizeHandle = GLES31.glGetUniformLocation(drawProgram, "rectSize"); + rectPosHandle = GLES31.glGetUniformLocation(drawProgram, "rectPos"); + resetHandle = GLES31.glGetUniformLocation(drawProgram, "reset"); + timeHandle = GLES31.glGetUniformLocation(drawProgram, "time"); + deltaTimeHandle = GLES31.glGetUniformLocation(drawProgram, "deltaTime"); + particlesCountHandle = GLES31.glGetUniformLocation(drawProgram, "particlesCount"); + sizeHandle = GLES31.glGetUniformLocation(drawProgram, "size"); + gridSizeHandle = GLES31.glGetUniformLocation(drawProgram, "gridSize"); + textureHandle = GLES31.glGetUniformLocation(drawProgram, "tex"); + seedHandle = GLES31.glGetUniformLocation(drawProgram, "seed"); + densityHandle = GLES31.glGetUniformLocation(drawProgram, "dp"); + longevityHandle = GLES31.glGetUniformLocation(drawProgram, "longevity"); + offsetHandle = GLES31.glGetUniformLocation(drawProgram, "offset"); + + GLES31.glViewport(0, 0, width, height); + GLES31.glEnable(GLES31.GL_BLEND); + GLES31.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); + GLES31.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + GLES31.glUseProgram(drawProgram); + + GLES31.glUniform2f(sizeHandle, width, height); + } + + private final ArrayList toRunStartCallback = new ArrayList<>(); + + private float animationHeightPart(Animation animation) { + int totalHeight = 0; + for (int i = 0; i < pendingAnimations.size(); ++i) { + totalHeight += pendingAnimations.get(i).viewHeight; + } + return (float) animation.viewHeight / totalHeight; + } + + private boolean drawnAnimations = false; + private void draw() { + if (!alive) return; + + GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT); + + for (int i = 0; i < pendingAnimations.size(); ++i) { + Animation animation = pendingAnimations.get(i); + if (animation.firstDraw) { + animation.calcParticlesGrid(animationHeightPart(animation)); + if (animation.startCallback != null) { + toRunStartCallback.add(animation); + } + } + drawnAnimations = true; + animation.draw(); + if (animation.isDead()) { + animation.done(true); + pendingAnimations.remove(i); + running = !pendingAnimations.isEmpty(); + i--; + } + } + + checkGlErrors(); + + try { + egl.eglSwapBuffers(eglDisplay, eglSurface); + } catch (Exception e) { + for (int i = 0; i < toRunStartCallback.size(); ++i) { + AndroidUtilities.runOnUIThread(toRunStartCallback.get(i).startCallback); + } + toRunStartCallback.clear(); + for (int i = 0; i < pendingAnimations.size(); ++i) { + pendingAnimations.get(i).done(false); + } + pendingAnimations.clear(); + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getGlobalMainSettings().edit().putBoolean("nothanos", nothanos = true).apply(); + }); + killInternal(); + return; + } + + for (int i = 0; i < toRunStartCallback.size(); ++i) { + AndroidUtilities.runOnUIThread(toRunStartCallback.get(i).startCallback); + } + toRunStartCallback.clear(); + + if (pendingAnimations.isEmpty() && drawnAnimations) { + killInternal(); + } + }; + + public void layoutAnimations() { + + } + + private final ArrayList toAddAnimations = new ArrayList<>(); + public void animateGroup(ArrayList views, Runnable whenDone) { + if (!alive) return; + Animation animation = new Animation(views, whenDone); + Handler handler = getHandler(); + running = true; + if (handler == null) { + toAddAnimations.add(animation); + } else { + handler.sendMessage(handler.obtainMessage(DO_ADD_ANIMATION, animation)); + } + } + public void animate(View view, Runnable whenDone) { + if (!alive) return; + Animation animation = new Animation(view, whenDone); + Handler handler = getHandler(); + running = true; + if (handler == null) { + toAddAnimations.add(animation); + } else { + handler.sendMessage(handler.obtainMessage(DO_ADD_ANIMATION, animation)); + } + } + public void animate(Matrix matrix, Bitmap bitmap, Runnable whenStart, Runnable whenDone) { + if (!alive) return; + Animation animation = new Animation(matrix, bitmap, whenStart, whenDone); + Handler handler = getHandler(); + running = true; + if (handler == null) { + toAddAnimations.add(animation); + } else { + handler.sendMessage(handler.obtainMessage(DO_ADD_ANIMATION, animation)); + } + } + + private void addAnimationInternal(Animation animation) { + GLES31.glGenTextures(1, animation.texture, 0); + GLES20.glBindTexture(GL10.GL_TEXTURE_2D, animation.texture[0]); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, animation.bitmap, 0); + GLES20.glBindTexture(GL10.GL_TEXTURE_2D, 0); + + animation.bitmap.recycle(); + animation.bitmap = null; + + pendingAnimations.add(animation); + running = true; + + animation.ready = true; + } + + private class Animation { + + public ArrayList views = new ArrayList<>(); + private long lastDrawTime = -1; + public float time = 0; + public boolean firstDraw = true; + public Runnable startCallback, doneCallback; + public volatile boolean ready; + + public float offsetLeft = 0, offsetTop = 0; + public float left = 0; + public float top = 0; + public final float density = AndroidUtilities.density; + public float longevity = 1.5f; + public float timeScale = 1.12f; + public boolean invalidateMatrix = true; + public boolean customMatrix = false; + public final float[] glMatrixValues = new float[9]; + public final float[] matrixValues = new float[9]; + public final Matrix matrix = new Matrix(); + + public int particlesCount; + public int viewWidth, viewHeight; + public int gridWidth, gridHeight; + public float gridSize; + + public final float seed = (float) (Math.random() * 2.); + + public int currentBuffer; + public final int[] texture = new int[1]; + public final int[] buffer = new int[2]; + + private Bitmap bitmap; + + public Animation(Matrix matrix, Bitmap bitmap, Runnable whenStarted, Runnable whenDone) { + float[] v = new float[] { 0, 0, 0, 1, 1, 0, 1, 1 }; + matrix.mapPoints(v); + left = v[0]; + top = v[1]; + viewWidth = (int) MathUtils.distance(v[2], v[3], v[6], v[7]); + viewHeight = (int) MathUtils.distance(v[4], v[5], v[6], v[7]); + customMatrix = true; + this.matrix.set(matrix); + retrieveMatrixValues(); + startCallback = whenStarted; + doneCallback = whenDone; +// longevity = 1.5f * Utilities.clamp(viewWidth / (float) AndroidUtilities.displaySize.x, .6f, 0.2f); + this.bitmap = bitmap; + } + + public Animation(ArrayList views, Runnable whenDone) { + this.views.addAll(views); + int mleft = Integer.MAX_VALUE, mright = Integer.MIN_VALUE; + int mtop = Integer.MAX_VALUE, mbottom = Integer.MIN_VALUE; + for (int i = 0; i < views.size(); ++i) { + View view = views.get(i); + mleft = Math.min(mleft, (int) view.getX()); + mright = Math.max(mright, (int) view.getX() + view.getWidth()); + mtop = Math.min(mtop, (int) view.getY()); + mbottom = Math.max(mbottom, (int) view.getY() + view.getHeight()); + } + top = mtop; + left = mleft; + viewWidth = mright - mleft; + viewHeight = mbottom - mtop; + doneCallback = whenDone; + startCallback = () -> { + for (int j = 0; j < views.size(); ++j) { + views.get(j).setVisibility(View.GONE); + if (views.get(j) instanceof ChatMessageCell) { + ((ChatMessageCell) views.get(j)).setCheckBoxVisible(false, false); + ((ChatMessageCell) views.get(j)).setChecked(false, false, false); + } + } + }; +// longevity = 1.6f * .6f; + + for (int i = 0; i < views.size(); ++i) { + if (views.get(i) instanceof ChatMessageCell) { + ((ChatMessageCell) views.get(i)).drawingToBitmap = true; + } + } + + bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmap); + if (views.size() <= 0) return; + if (!(views.get(0).getParent() instanceof RecyclerListView)) return; + RecyclerListView chatListView = (RecyclerListView) views.get(0).getParent(); + if (!(chatListView.getParent() instanceof ChatActivity.ChatActivityFragmentView)) return; + ChatActivity.ChatActivityFragmentView contentView = (ChatActivity.ChatActivityFragmentView) chatListView.getParent(); + ChatActivity chatActivity = contentView.getChatActivity(); + final ArrayList drawingGroups = new ArrayList<>(10); + ArrayList drawTimeAfter = new ArrayList<>(); + ArrayList drawNamesAfter = new ArrayList<>(); + ArrayList drawCaptionAfter = new ArrayList<>(); + canvas.save(); + for (int k = 0; k < 3; k++) { + drawingGroups.clear(); + if (k == 2 && !chatListView.isFastScrollAnimationRunning()) { + continue; + } + for (int i = 0; i < views.size(); i++) { + View child = views.get(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + if (child.getY() > chatListView.getHeight() || child.getY() + child.getHeight() < 0 || cell.getVisibility() == View.INVISIBLE || cell.getVisibility() == View.GONE) { + continue; + } + + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + MessageObject.GroupedMessagePosition position = group == null || group.positions == null ? null : group.positions.get(cell.getMessageObject()); + if (k == 0) { + if (position != null || cell.getTransitionParams().animateBackgroundBoundsInner) { + if (position == null || (position.last || position.minX == 0 && position.minY == 0)) { + if (position == null || position.last) { + drawTimeAfter.add(cell); + } + if ((position == null || (position.minX == 0 && position.minY == 0)) && cell.hasNameLayout()) { + drawNamesAfter.add(cell); + } + } + if (position != null || cell.getTransitionParams().transformGroupToSingleMessage || cell.getTransitionParams().animateBackgroundBoundsInner) { + if (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + drawCaptionAfter.add(cell); + } + } + } + } + + if (group == null || (k == 0 && group.messages.size() == 1) || (k == 1 && !group.transitionParams.drawBackgroundForDeletedItems)) { + continue; + } + if ((k == 0 && cell.getMessageObject().deleted) || (k == 1 && !cell.getMessageObject().deleted)) { + continue; + } + if ((k == 2 && !cell.willRemovedAfterAnimation()) || (k != 2 && cell.willRemovedAfterAnimation())) { + continue; + } + + if (!drawingGroups.contains(group)) { + group.transitionParams.left = 0; + group.transitionParams.top = 0; + group.transitionParams.right = 0; + group.transitionParams.bottom = 0; + + group.transitionParams.pinnedBotton = false; + group.transitionParams.pinnedTop = false; + group.transitionParams.cell = cell; + drawingGroups.add(group); + } + + group.transitionParams.pinnedTop = cell.isPinnedTop(); + group.transitionParams.pinnedBotton = cell.isPinnedBottom(); + + int left = (cell.getLeft() + cell.getBackgroundDrawableLeft()); + int right = (cell.getLeft() + cell.getBackgroundDrawableRight()); + int top = (cell.getTop() + cell.getBackgroundDrawableTop()); + int bottom = (cell.getTop() + cell.getBackgroundDrawableBottom()); + + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_TOP) == 0) { + top -= AndroidUtilities.dp(10); + } + + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + bottom += AndroidUtilities.dp(10); + } + + if (cell.willRemovedAfterAnimation()) { + group.transitionParams.cell = cell; + } + + if (group.transitionParams.top == 0 || top < group.transitionParams.top) { + group.transitionParams.top = top; + } + if (group.transitionParams.bottom == 0 || bottom > group.transitionParams.bottom) { + group.transitionParams.bottom = bottom; + } + if (group.transitionParams.left == 0 || left < group.transitionParams.left) { + group.transitionParams.left = left; + } + if (group.transitionParams.right == 0 || right > group.transitionParams.right) { + group.transitionParams.right = right; + } + } + } + + for (int i = 0; i < drawingGroups.size(); i++) { + MessageObject.GroupedMessages group = drawingGroups.get(i); + float x = group.transitionParams.cell.getNonAnimationTranslationX(true); + float l = (group.transitionParams.left + x + group.transitionParams.offsetLeft); + float t = (group.transitionParams.top + group.transitionParams.offsetTop); + float r = (group.transitionParams.right + x + group.transitionParams.offsetRight); + float b = (group.transitionParams.bottom + group.transitionParams.offsetBottom); + + if (!group.transitionParams.backgroundChangeBounds) { + t += group.transitionParams.cell.getTranslationY(); + b += group.transitionParams.cell.getTranslationY(); + } + + if (t < chatActivity.chatListViewPaddingTop - chatActivity.chatListViewPaddingVisibleOffset - AndroidUtilities.dp(20)) { + t = chatActivity.chatListViewPaddingTop - chatActivity.chatListViewPaddingVisibleOffset - AndroidUtilities.dp(20); + } + + if (b > chatListView.getMeasuredHeight() + AndroidUtilities.dp(20)) { + b = chatListView.getMeasuredHeight() + AndroidUtilities.dp(20); + } + + t -= top; + b -= top; + + boolean useScale = group.transitionParams.cell.getScaleX() != 1f || group.transitionParams.cell.getScaleY() != 1f; + if (useScale) { + canvas.save(); + canvas.scale(group.transitionParams.cell.getScaleX(), group.transitionParams.cell.getScaleY(), l + (r - l) / 2, t + (b - t) / 2); + } + boolean selected = false; + group.transitionParams.cell.drawBackground(canvas, (int) l, (int) t, (int) r, (int) b, group.transitionParams.pinnedTop, group.transitionParams.pinnedBotton, selected, contentView.getKeyboardHeight()); + group.transitionParams.cell = null; + group.transitionParams.drawCaptionLayout = group.hasCaption; + if (useScale) { + canvas.restore(); + for (int ii = 0; ii < views.size(); ii++) { + View child = views.get(ii); + if (child instanceof ChatMessageCell && ((ChatMessageCell) child).getCurrentMessagesGroup() == group) { + ChatMessageCell cell = ((ChatMessageCell) child); + int left = cell.getLeft(); + int top = cell.getTop(); + child.setPivotX(l - left + (r - l) / 2); + child.setPivotY(t - top + (b - t) / 2); + } + } + } + } + } + for (int i = 0; i < views.size(); ++i) { + View view = views.get(i); + canvas.save(); + canvas.translate(view.getX() - mleft, view.getY() - mtop); + view.draw(canvas); + if (view instanceof ChatMessageCell) { + ((ChatMessageCell) view).drawOutboundsContent(canvas); + } else if (view instanceof ChatActionCell) { + ((ChatActionCell) view).drawOutboundsContent(canvas); + } + canvas.restore(); + } + float listTop = chatListView.getY() + chatActivity.chatListViewPaddingTop - chatActivity.chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4); + int size = drawTimeAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell view = drawTimeAfter.get(a); + drawChildElement(chatListView, chatActivity, canvas, listTop, view, 0, view.getX() - mleft, view.getY() - mtop); + } + drawTimeAfter.clear(); + } + size = drawNamesAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell view = drawNamesAfter.get(a); + drawChildElement(chatListView, chatActivity, canvas, listTop, view, 1, view.getX() - mleft, view.getY() - mtop); + } + drawNamesAfter.clear(); + } + size = drawCaptionAfter.size(); + if (size > 0) { + for (int a = 0; a < size; a++) { + ChatMessageCell cell = drawCaptionAfter.get(a); + if (cell.getCurrentPosition() == null && !cell.getTransitionParams().animateBackgroundBoundsInner) { + continue; + } + drawChildElement(chatListView, chatActivity, canvas, listTop, cell, 2, cell.getX() - mleft, cell.getY() - mtop); + } + drawCaptionAfter.clear(); + } + canvas.restore(); + + for (int i = 0; i < views.size(); ++i) { + if (views.get(i) instanceof ChatMessageCell) { + ((ChatMessageCell) views.get(i)).drawingToBitmap = false; + } + } + } + + private void drawChildElement(View chatListView, ChatActivity chatActivity, Canvas canvas, float listTop, ChatMessageCell cell, int type, float x, float y) { + canvas.save(); + float alpha = cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f; +// canvas.clipRect(chatListView.getLeft() - x, listTop - y, chatListView.getRight() - x, chatListView.getY() + chatListView.getMeasuredHeight() - (chatActivity == null ? 0 : chatActivity.blurredViewBottomOffset) - y); + canvas.translate(x, y); + cell.setInvalidatesParent(true); + if (type == 0) { + cell.drawTime(canvas, alpha, true); + } else if (type == 1) { + cell.drawNamesLayout(canvas, alpha); + } else { + cell.drawCaptionLayout(canvas, cell.getCurrentPosition() != null && (cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_LEFT) == 0, alpha); + } + cell.setInvalidatesParent(false); + canvas.restore(); + } + + public void calcParticlesGrid(float part) { + final int maxParticlesCount; + switch (SharedConfig.getDevicePerformanceClass()) { + case SharedConfig.PERFORMANCE_CLASS_HIGH: + maxParticlesCount = 120_000; + break; + case SharedConfig.PERFORMANCE_CLASS_AVERAGE: + maxParticlesCount = 60_000; + break; + case SharedConfig.PERFORMANCE_CLASS_LOW: + default: + maxParticlesCount = 30_000; + break; + } + float p = Math.max(AndroidUtilities.dpf2(.4f), 1); + particlesCount = Utilities.clamp((int) (viewWidth * viewHeight / (p * p)), (int) (maxParticlesCount * part), 10); + + final float aspectRatio = (float) viewWidth / viewHeight; + gridHeight = (int) Math.round(Math.sqrt(particlesCount / aspectRatio)); + gridWidth = (int) Math.round((float) particlesCount / gridHeight); + while (gridWidth * gridHeight < particlesCount) { + if ((float) gridWidth / gridHeight < aspectRatio) { + gridWidth++; + } else { + gridHeight++; + } + } + particlesCount = gridWidth * gridHeight; + gridSize = Math.max((float) viewWidth / gridWidth, (float) viewHeight / gridHeight); + + GLES31.glGenBuffers(2, buffer, 0); + for (int i = 0; i < 2; ++i) { + GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, buffer[i]); + GLES31.glBufferData(GLES31.GL_ARRAY_BUFFER, particlesCount * 28, null, GLES31.GL_DYNAMIC_DRAW); + } + } + + public Animation(View view, Runnable whenDone) { + this.views.add(view); + viewWidth = view.getWidth(); + viewHeight = view.getHeight(); + top = view.getY(); + left = 0; + if (view instanceof BaseCell) { + viewWidth = Math.max(1, ((BaseCell) view).getBoundsRight() - ((BaseCell) view).getBoundsLeft()); + left += ((BaseCell) view).getBoundsLeft(); + } + doneCallback = whenDone; + startCallback = () -> { + for (int j = 0; j < views.size(); ++j) { + views.get(j).setVisibility(View.GONE); + if (views.get(j) instanceof ChatMessageCell) { + ((ChatMessageCell) views.get(j)).setCheckBoxVisible(false, false); + ((ChatMessageCell) views.get(j)).setChecked(false, false, false); + } + } + }; +// longevity = 1.5f * Utilities.clamp(viewWidth / (float) AndroidUtilities.displaySize.x, .6f, 0.2f); + + bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmap); + canvas.save(); + canvas.translate(-left, 0); + if (view instanceof ChatMessageCell) { + ((ChatMessageCell) view).drawingToBitmap = true; + } + if (view instanceof ChatActionCell && ((ChatActionCell) view).hasGradientService()) { + ((ChatActionCell) view).drawBackground(canvas, true); + } else if (view instanceof ChatMessageCell && ((ChatMessageCell) view).drawBackgroundInParent()) { + ((ChatMessageCell) view).drawBackgroundInternal(canvas, true); + } + view.draw(canvas); + if (view instanceof ChatMessageCell) { + ImageReceiver avatarImage = ((ChatMessageCell) view).getAvatarImage(); + if (avatarImage != null && avatarImage.getVisible()) { + canvas.save(); + canvas.translate(0, -view.getY()); + avatarImage.draw(canvas); + canvas.restore(); + } + ((ChatMessageCell) view).drawingToBitmap = false; + } + if (view instanceof ChatMessageCell) { + ((ChatMessageCell) view).drawOutboundsContent(canvas); + } else if (view instanceof ChatActionCell) { + ((ChatActionCell) view).drawOutboundsContent(canvas); + } + canvas.restore(); + + left += view.getX(); + } + + private void retrieveMatrixValues() { + matrix.getValues(matrixValues); + glMatrixValues[0] = matrixValues[0]; + glMatrixValues[1] = matrixValues[3]; + glMatrixValues[2] = matrixValues[6]; + glMatrixValues[3] = matrixValues[1]; + glMatrixValues[4] = matrixValues[4]; + glMatrixValues[5] = matrixValues[7]; + glMatrixValues[6] = matrixValues[2]; + glMatrixValues[7] = matrixValues[5]; + glMatrixValues[8] = matrixValues[8]; + invalidateMatrix = false; + } + + public void draw() { + final long now = System.nanoTime(); + final double Δt = lastDrawTime < 0 ? 0 : (now - lastDrawTime) / 1_000_000_000.; + lastDrawTime = now; + + if (invalidateMatrix && !customMatrix) { + matrix.reset(); + matrix.postScale(viewWidth, viewHeight); + matrix.postTranslate(left, top); + retrieveMatrixValues(); + } + + time += Δt * timeScale; + + GLES31.glUniformMatrix3fv(matrixHandle, 1, false, glMatrixValues, 0); + GLES31.glUniform1f(resetHandle, firstDraw ? 1f : 0f); + GLES31.glUniform1f(timeHandle, time); + GLES31.glUniform1f(deltaTimeHandle, (float) Δt * timeScale); + GLES31.glUniform1f(particlesCountHandle, particlesCount); + GLES31.glUniform3f(gridSizeHandle, gridWidth, gridHeight, gridSize); + GLES31.glUniform2f(offsetHandle, offsetLeft, offsetTop); + + GLES31.glUniform2f(rectSizeHandle, viewWidth, viewHeight); + GLES31.glUniform1f(seedHandle, seed); + GLES31.glUniform2f(rectPosHandle, 0, 0); + GLES31.glUniform1f(densityHandle, density); + GLES31.glUniform1f(longevityHandle, longevity); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); + GLES31.glUniform1i(textureHandle, 0); + + GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, buffer[currentBuffer]); + GLES31.glVertexAttribPointer(0, 2, GLES31.GL_FLOAT, false, 28, 0); // Initial UV (vec2) + GLES31.glEnableVertexAttribArray(0); + GLES31.glVertexAttribPointer(1, 2, GLES31.GL_FLOAT, false, 28, 8); // Position (vec2) + GLES31.glEnableVertexAttribArray(1); + GLES31.glVertexAttribPointer(2, 2, GLES31.GL_FLOAT, false, 28, 16); // Velocity (vec2) + GLES31.glEnableVertexAttribArray(2); + GLES31.glVertexAttribPointer(3, 1, GLES31.GL_FLOAT, false, 28, 24); // Time (float) + GLES31.glEnableVertexAttribArray(3); + GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer[1 - currentBuffer]); + GLES31.glVertexAttribPointer(0, 2, GLES31.GL_FLOAT, false, 28, 0); // Initial UV (vec2) + GLES31.glEnableVertexAttribArray(0); + GLES31.glVertexAttribPointer(1, 2, GLES31.GL_FLOAT, false, 28, 8); // Position (vec2) + GLES31.glEnableVertexAttribArray(1); + GLES31.glVertexAttribPointer(2, 2, GLES31.GL_FLOAT, false, 28, 16); // Velocity (vec2) + GLES31.glEnableVertexAttribArray(2); + GLES31.glVertexAttribPointer(3, 1, GLES31.GL_FLOAT, false, 28, 24); // Time (float) + GLES31.glEnableVertexAttribArray(3); + + GLES31.glBeginTransformFeedback(GLES31.GL_POINTS); + GLES31.glDrawArrays(GLES31.GL_POINTS, 0, particlesCount); + GLES31.glEndTransformFeedback(); + + GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0); + GLES31.glBindBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0); + + firstDraw = false; + currentBuffer = 1 - currentBuffer; + } + + public boolean isDead() { + return time > longevity + .9f; + } + + public void done(boolean success) { + 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); }; + drawProgram = 0; + } + try { GLES31.glDeleteTextures(1, texture, 0); } catch (Exception e) { FileLog.e(e); }; + + if (doneCallback != null) { + AndroidUtilities.runOnUIThread(() -> { + if (doneCallback != null) { + doneCallback.run(); + } + }); + } + } + } + + private void checkGlErrors() { + int err; + while ((err = GLES31.glGetError()) != GLES31.GL_NO_ERROR) { + FileLog.e("thanos gles error " + err); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java index f94327b3d..c47e1176b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThemeSmallPreviewView.java @@ -52,6 +52,8 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe public final static int TYPE_DEFAULT = 0; public final static int TYPE_GRID = 1; public final static int TYPE_QR = 2; + public final static int TYPE_CHANNEL = 3; + public final static int TYPE_GRID_CHANNEL = 4; private final float STROKE_RADIUS = AndroidUtilities.dp(8); private final float INNER_RADIUS = AndroidUtilities.dp(6); @@ -94,7 +96,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe backupImageView.getImageReceiver().setCrossfadeWithOldImage(true); backupImageView.getImageReceiver().setAllowStartLottieAnimation(false); backupImageView.getImageReceiver().setAutoRepeat(0); - if (currentType == TYPE_DEFAULT || currentType == TYPE_QR) { + if (currentType == TYPE_DEFAULT || currentType == TYPE_CHANNEL || currentType == TYPE_QR) { addView(backupImageView, LayoutHelper.createFrame(28, 28, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 12)); } else { addView(backupImageView, LayoutHelper.createFrame(36, 36, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 12)); @@ -107,12 +109,12 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (currentType == TYPE_GRID) { + if (currentType == TYPE_GRID || currentType == TYPE_GRID_CHANNEL) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = (int) (width * 1.2f); super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } else { - int width = AndroidUtilities.dp(77); + int width = AndroidUtilities.dp(currentType == TYPE_DEFAULT ? 77 : 83); int height = MeasureSpec.getSize(heightMeasureSpec); if (height == 0) { height = (int) (width * 1.35f); @@ -173,6 +175,18 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe super.dispatchDraw(canvas); } + public TLRPC.WallPaper fallbackWallpaper; + public void setFallbackWallpaper(TLRPC.WallPaper wallPaper) { + if (fallbackWallpaper != wallPaper) { + this.fallbackWallpaper = wallPaper; + if (chatThemeItem != null && (chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.wallpaper == null)) { + ChatThemeBottomSheet.ChatThemeItem item = chatThemeItem; + chatThemeItem = null; + setItem(item, false); + } + } + } + public int lastThemeIndex; public void setItem(ChatThemeBottomSheet.ChatThemeItem item, boolean animated) { boolean itemChanged = chatThemeItem != item; @@ -203,11 +217,15 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe thumb = Emoji.getEmojiDrawable(item.chatTheme.getEmoticon()); } backupImageView.setImage(ImageLocation.getForDocument(document), "50_50", thumb, null); - if (item.chatTheme.wallpaper != null) { + TLRPC.WallPaper wallPaper = item.chatTheme.wallpaper; + if (wallPaper == null) { + wallPaper = fallbackWallpaper; + } + if (wallPaper != null) { if (attached && chatBackgroundDrawable != null) { chatBackgroundDrawable.onDetachedFromWindow(ThemeSmallPreviewView.this); } - chatBackgroundDrawable = new ChatBackgroundDrawable(item.chatTheme.wallpaper, false, true); + chatBackgroundDrawable = new ChatBackgroundDrawable(wallPaper, false, true); chatBackgroundDrawable.setParent(this); if (attached) { chatBackgroundDrawable.onAttachedToWindow(ThemeSmallPreviewView.this); @@ -219,6 +237,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe chatBackgroundDrawable = null; } } + backupImageView.setVisibility(item.chatTheme.showAsDefaultStub && fallbackWallpaper != null ? View.GONE : View.VISIBLE); if (itemChanged || darkModeChanged) { if (animated) { @@ -314,7 +333,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe } if (chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.showAsDefaultStub) { - setContentDescription(LocaleController.getString("ChatNoTheme", R.string.ChatNoTheme)); + setContentDescription(LocaleController.getString(R.string.ChatNoTheme)); } else { setContentDescription(chatThemeItem.chatTheme.getEmoticon()); } @@ -494,7 +513,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe bitmapDrawable.setFilterBitmap(true); drawable = bitmapDrawable; } - } else { + } else if (!(chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.showAsDefaultStub)) { drawable = new MotionBackgroundDrawable(0xffdbddbb, 0xff6ba587, 0xffd5d88d, 0xff88b884, true); } } @@ -510,19 +529,33 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe } noThemeTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG + TextPaint.SUBPIXEL_TEXT_FLAG); noThemeTextPaint.setColor(getThemedColor(Theme.key_chat_emojiPanelTrendingDescription)); - noThemeTextPaint.setTextSize(AndroidUtilities.dp(14)); - noThemeTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + noThemeTextPaint.setTextSize(AndroidUtilities.dp(noThemeStringTextSize())); + noThemeTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + int width = AndroidUtilities.dp(52); + if (currentType == TYPE_CHANNEL || currentType == TYPE_GRID_CHANNEL) { + width = AndroidUtilities.dp(77); + } textLayout = StaticLayoutEx.createStaticLayout2( - LocaleController.getString("ChatNoTheme", R.string.ChatNoTheme), + noThemeString(), noThemeTextPaint, - AndroidUtilities.dp(52), + width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, true, - TextUtils.TruncateAt.END, AndroidUtilities.dp(52), 3 + TextUtils.TruncateAt.END, + width, + 3 ); return textLayout; } + protected int noThemeStringTextSize() { + return 14; + } + + protected String noThemeString() { + return LocaleController.getString(R.string.ChatNoTheme); + } + private int getThemedColor(int key) { return Theme.getColor(key, resourcesProvider); } @@ -594,7 +627,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe outlineBackgroundPaint.setAlpha(wasAlpha); } canvas.restore(); - } else { + } else if (!(chatThemeItem != null && chatThemeItem.chatTheme != null && chatThemeItem.chatTheme.showAsDefaultStub && chatBackgroundDrawable != null)) { canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint); } } @@ -616,13 +649,15 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe rectF.set(INNER_RECT_SPACE, INNER_RECT_SPACE, getWidth() - INNER_RECT_SPACE, getHeight() - INNER_RECT_SPACE); if (chatThemeItem.chatTheme == null || (chatThemeItem.chatTheme.showAsDefaultStub && chatThemeItem.chatTheme.wallpaper == null)) { - canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint); - canvas.save(); - StaticLayout textLayout = getNoThemeStaticLayout(); - canvas.translate((getWidth() - textLayout.getWidth()) * 0.5f, AndroidUtilities.dp(18)); - textLayout.draw(canvas); - canvas.restore(); - } else { + if (fallbackWallpaper == null) { + canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint); + canvas.save(); + StaticLayout textLayout = getNoThemeStaticLayout(); + canvas.translate((getWidth() - textLayout.getWidth()) * 0.5f, AndroidUtilities.dp(18)); + textLayout.draw(canvas); + canvas.restore(); + } + } else if (currentType != TYPE_GRID_CHANNEL) { if (currentType == TYPE_QR) { if (chatThemeItem.icon != null) { float left = (getWidth() - chatThemeItem.icon.getWidth()) * 0.5f; @@ -630,9 +665,9 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe } } else { float bubbleTop = INNER_RECT_SPACE + AndroidUtilities.dp(8); - float bubbleLeft = INNER_RECT_SPACE + AndroidUtilities.dp(22); - if (currentType == TYPE_DEFAULT) { - rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH, bubbleTop + BUBBLE_HEIGHT); + float bubbleLeft = INNER_RECT_SPACE + AndroidUtilities.dp(currentType == TYPE_CHANNEL ? 5 : 22); + if (currentType == TYPE_DEFAULT || currentType == TYPE_CHANNEL) { + rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH * (currentType == TYPE_CHANNEL ? 1.2f : 1f), bubbleTop + BUBBLE_HEIGHT); } else { bubbleTop = getMeasuredHeight() * 0.12f; bubbleLeft = getMeasuredWidth() - getMeasuredWidth() * 0.65f; @@ -641,8 +676,8 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe rectF.set(bubbleLeft, bubbleTop, bubbleRight, bubbleBottom); } - Paint paint = outBubblePaintSecond; - if (currentType == TYPE_DEFAULT) { + Paint paint = currentType == TYPE_CHANNEL ? inBubblePaint : outBubblePaintSecond; + if (currentType == TYPE_DEFAULT || currentType == TYPE_CHANNEL) { canvas.drawRoundRect(rectF, rectF.height() * 0.5f, rectF.height() * 0.5f, paint); } else { messageDrawableOut.setBounds((int) rectF.left, (int) rectF.top - AndroidUtilities.dp(2), (int) rectF.right + AndroidUtilities.dp(4), (int) rectF.bottom + AndroidUtilities.dp(2)); @@ -650,10 +685,10 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe messageDrawableOut.draw(canvas, paint); } - if (currentType == TYPE_DEFAULT) { + if (currentType == TYPE_DEFAULT || currentType == TYPE_CHANNEL) { bubbleLeft = INNER_RECT_SPACE + AndroidUtilities.dp(5); bubbleTop += BUBBLE_HEIGHT + AndroidUtilities.dp(4); - rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH, bubbleTop + BUBBLE_HEIGHT); + rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH * (currentType == TYPE_CHANNEL ? 0.8f : 1f), bubbleTop + BUBBLE_HEIGHT); } else { bubbleTop = getMeasuredHeight() * 0.35f; bubbleLeft = getMeasuredWidth() * 0.1f; @@ -662,7 +697,7 @@ public class ThemeSmallPreviewView extends FrameLayout implements NotificationCe rectF.set(bubbleLeft, bubbleTop, bubbleRight, bubbleBottom); } - if (currentType == TYPE_DEFAULT) { + if (currentType == TYPE_DEFAULT || currentType == TYPE_CHANNEL) { canvas.drawRoundRect(rectF, rectF.height() * 0.5f, rectF.height() * 0.5f, inBubblePaint); } else { messageDrawableIn.setBounds((int) rectF.left - AndroidUtilities.dp(4), (int) rectF.top - AndroidUtilities.dp(2), (int) rectF.right, (int) rectF.bottom + AndroidUtilities.dp(2)); 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 098537e44..261be2988 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 @@ -6,6 +6,8 @@ import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; import android.graphics.SurfaceTexture; import android.hardware.HardwareBuffer; import android.opengl.EGL14; @@ -87,12 +89,12 @@ public class SpoilerEffect2 { private static int getSize() { switch (SharedConfig.getDevicePerformanceClass()) { case SharedConfig.PERFORMANCE_CLASS_HIGH: - return Math.min(900, (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 1.0f)); + return Math.min(1280, (int) ((AndroidUtilities.displaySize.x + AndroidUtilities.displaySize.y) / 2f * 1.0f)); case SharedConfig.PERFORMANCE_CLASS_AVERAGE: - return Math.min(900, (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f)); + return Math.min(900, (int) ((AndroidUtilities.displaySize.x + AndroidUtilities.displaySize.y) / 2f * .8f)); default: case SharedConfig.PERFORMANCE_CLASS_LOW: - return Math.min(720, (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .7f)); + return Math.min(720, (int) ((AndroidUtilities.displaySize.x + AndroidUtilities.displaySize.y) / 2f * .7f)); } } @@ -170,6 +172,10 @@ public class SpoilerEffect2 { } public void draw(Canvas canvas, View view, int w, int h, float alpha) { + draw(canvas, view, w, h, alpha, false); + } + + public void draw(Canvas canvas, View view, int w, int h, float alpha, boolean toBitmap) { if (canvas == null || view == null) { return; } @@ -192,8 +198,18 @@ public class SpoilerEffect2 { if ((index % 4) == 3) { canvas.scale(1, -1, ow / 2f, oh / 2f); } - textureView.setAlpha(alpha); - textureView.draw(canvas); + if (toBitmap) { + Bitmap bitmap = textureView.getBitmap(); + if (bitmap != null) { + Paint paint = new Paint(Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + canvas.drawBitmap(bitmap, 0, 0, paint); + bitmap.recycle(); + } + } else { + textureView.setAlpha(alpha); + textureView.draw(canvas); + } canvas.restore(); } 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 f5a1655ce..3ededd5cd 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 @@ -8,11 +8,13 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.os.SystemClock; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; @@ -34,6 +36,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.RLottieDrawable; public class AcceptDeclineView extends View { @@ -76,15 +79,23 @@ public class AcceptDeclineView extends View { boolean retryMod; Drawable rippleDrawable; - private boolean screenWasWakeup; Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - Drawable arrowDrawable; - - float arrowProgress; + private RLottieDrawable callAcceptDrawable; + private final ImageWithWavesView.AvatarWavesDrawable avatarWavesDrawable; + private final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public AcceptDeclineView(@NonNull Context context) { super(context); + avatarWavesDrawable = new ImageWithWavesView.AvatarWavesDrawable(AndroidUtilities.dp(45), AndroidUtilities.dp(50), AndroidUtilities.dp(8), 4); + avatarWavesDrawable.muteToStatic = true; + avatarWavesDrawable.muteToStaticProgress = 0f; + avatarWavesDrawable.wavesEnter = 0; + avatarWavesDrawable.setAmplitude(0); + + maskPaint.setColor(Color.BLACK); + maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); buttonWidth = AndroidUtilities.dp(60); acceptDrawable = new FabBackgroundDrawable(); @@ -112,15 +123,16 @@ public class AcceptDeclineView extends View { callDrawable = ContextCompat.getDrawable(context, R.drawable.calls_decline).mutate(); cancelDrawable = ContextCompat.getDrawable(context, R.drawable.ic_close_white).mutate(); cancelDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); - - acceptCirclePaint.setColor(0x3f45bc4d); + callAcceptDrawable = new RLottieDrawable(R.raw.call_accept, "" + R.raw.call_accept, AndroidUtilities.dp(48), AndroidUtilities.dp(48), true, null); + callAcceptDrawable.setAutoRepeat(1); + callAcceptDrawable.setCustomEndFrame(90); + callAcceptDrawable.setMasterParent(this); + acceptCirclePaint.setColor(Color.WHITE); + acceptCirclePaint.setAlpha(20); rippleDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(52), 0, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.3f))); rippleDrawable.setCallback(this); - - arrowDrawable = ContextCompat.getDrawable(context, R.drawable.call_arrow_right); } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -144,10 +156,11 @@ 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, 0xFFFF3846); + rippleDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(52), 0, retryMod ? Color.WHITE : 0xFFFF3846); captured = true; leftDrag = true; setPressed(true); + invalidate(); return true; } if (rightAnimator == null && acceptRect.contains((int) event.getX(), (int) event.getY())) { @@ -158,43 +171,12 @@ public class AcceptDeclineView extends View { if (rightAnimator != null) { rightAnimator.cancel(); } + invalidate(); return true; } break; case MotionEvent.ACTION_MOVE: if (captured) { - float dx = event.getX() - startX; - if (!startDrag && Math.abs(dx) > touchSlop) { - if (!retryMod) { - startX = event.getX(); - dx = 0; - startDrag = true; - setPressed(false); - getParent().requestDisallowInterceptTouchEvent(true); - } else { - setPressed(false); - captured = false; - } - } - if (startDrag) { - if (leftDrag) { - leftOffsetX = dx; - if (leftOffsetX < 0) { - leftOffsetX = 0; - } else if (leftOffsetX > maxOffset) { - leftOffsetX = maxOffset; - dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0)); - } - } else { - rigthOffsetX = dx; - if (rigthOffsetX > 0) { - rigthOffsetX = 0; - } else if (rigthOffsetX < -maxOffset) { - rigthOffsetX = -maxOffset; - dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0)); - } - } - } return true; } break; @@ -212,7 +194,7 @@ public class AcceptDeclineView extends View { animator.start(); leftAnimator = animator; if (listener != null) { - if ((!startDrag && Math.abs(dy) < touchSlop && !screenWasWakeup) || leftOffsetX > maxOffset * 0.8f) { + if ((!startDrag && Math.abs(dy) < touchSlop) || leftOffsetX > maxOffset * 0.8f) { listener.onDecline(); } } @@ -226,7 +208,7 @@ public class AcceptDeclineView extends View { animator.start(); rightAnimator = animator; if (listener != null) { - if ((!startDrag && Math.abs(dy) < touchSlop && !screenWasWakeup) || -rigthOffsetX > maxOffset * 0.8f) { + if ((!startDrag && Math.abs(dy) < touchSlop) || -rigthOffsetX > maxOffset * 0.8f) { listener.onAccept(); } } @@ -238,7 +220,6 @@ public class AcceptDeclineView extends View { setPressed(false); break; } - return false; } @@ -275,68 +256,33 @@ public class AcceptDeclineView extends View { invalidate(); } - - float k = 0.6f; - if (screenWasWakeup && !retryMod) { - - arrowProgress += 16 / 1500f; - if (arrowProgress > 1) { - arrowProgress = 0; - } - - int cY = (int) (AndroidUtilities.dp(40) + buttonWidth / 2f); - float startX = AndroidUtilities.dp(46) + buttonWidth + AndroidUtilities.dp(8); - float endX = getMeasuredWidth() / 2f - AndroidUtilities.dp(8); - - float lineLength = AndroidUtilities.dp(10); - - float stepProgress = (1f - k) / 3f; - for (int i = 0; i < 3; i++) { - int x = (int) (startX + (endX - startX - lineLength) / 3 * i); - - float alpha = 0.5f; - float startAlphaFrom = i * stepProgress; - if (arrowProgress > startAlphaFrom && arrowProgress < startAlphaFrom + k) { - float p = (arrowProgress - startAlphaFrom) / k; - if (p > 0.5) p = 1f - p; - alpha = 0.5f + p; - } - canvas.save(); - canvas.clipRect(leftOffsetX + AndroidUtilities.dp(46) + buttonWidth / 2,0,getMeasuredHeight(),getMeasuredWidth() >> 1); - arrowDrawable.setAlpha((int) (255 * alpha)); - arrowDrawable.setBounds(x, cY - arrowDrawable.getIntrinsicHeight() / 2, x + arrowDrawable.getIntrinsicWidth(), cY + arrowDrawable.getIntrinsicHeight() / 2); - arrowDrawable.draw(canvas); - canvas.restore(); - - x = (int) (getMeasuredWidth() - (startX + (endX - startX - lineLength) / 3 * i)); - canvas.save(); - canvas.clipRect(getMeasuredWidth() >> 1, 0, rigthOffsetX + getMeasuredWidth() - AndroidUtilities.dp(46) - buttonWidth / 2, getMeasuredHeight()); - canvas.rotate(180, x - arrowDrawable.getIntrinsicWidth() / 2f, cY); - arrowDrawable.setBounds(x - arrowDrawable.getIntrinsicWidth(), cY - arrowDrawable.getIntrinsicHeight() / 2, x, cY + arrowDrawable.getIntrinsicHeight() / 2); - arrowDrawable.draw(canvas); - canvas.restore(); - } - invalidate(); - } bigRadius += AndroidUtilities.dp(8) * 0.005f; canvas.save(); canvas.translate(0, AndroidUtilities.dp(40)); canvas.save(); - canvas.translate(leftOffsetX + AndroidUtilities.dp(46), 0); - declineDrawable.draw(canvas); - - canvas.save(); - canvas.translate(buttonWidth / 2f - declineLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(8)); - declineLayout.draw(canvas); - declineRect.set(AndroidUtilities.dp(46), AndroidUtilities.dp(40), AndroidUtilities.dp(46) + buttonWidth, AndroidUtilities.dp(40) + buttonWidth); - canvas.restore(); + canvas.translate(rigthOffsetX + getMeasuredWidth() - AndroidUtilities.dp(46) - buttonWidth, 0); if (retryMod) { - cancelDrawable.draw(canvas); + canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), linePaint, Canvas.ALL_SAVE_FLAG); + declineDrawable.draw(canvas); + if (cancelDrawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) cancelDrawable; + if (bitmapDrawable.getBitmap() != null) { + canvas.drawBitmap(bitmapDrawable.getBitmap(), null, bitmapDrawable.getBounds(), maskPaint); + } + } + canvas.restore(); } else { + declineDrawable.draw(canvas); callDrawable.draw(canvas); } + canvas.save(); + canvas.translate(buttonWidth / 2f - declineLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(4)); + declineLayout.draw(canvas); + declineRect.set(getMeasuredWidth() - AndroidUtilities.dp(46) - buttonWidth, AndroidUtilities.dp(40), getMeasuredWidth() - AndroidUtilities.dp(46), AndroidUtilities.dp(40) + buttonWidth); + canvas.restore(); + if (leftDrag) { rippleDrawable.setBounds(AndroidUtilities.dp(4), AndroidUtilities.dp(4), buttonWidth - AndroidUtilities.dp(4), buttonWidth - AndroidUtilities.dp(4)); rippleDrawable.draw(canvas); @@ -345,30 +291,30 @@ public class AcceptDeclineView extends View { canvas.restore(); canvas.save(); - canvas.translate(rigthOffsetX + getMeasuredWidth() - AndroidUtilities.dp(46) - buttonWidth, 0); + canvas.translate(leftOffsetX + AndroidUtilities.dp(46), 0); if (!retryMod) { - canvas.drawCircle(buttonWidth / 2f, buttonWidth / 2f, buttonWidth / 2f - AndroidUtilities.dp(4) + bigRadius, acceptCirclePaint); - canvas.drawCircle(buttonWidth / 2f, buttonWidth / 2f, buttonWidth / 2f - AndroidUtilities.dp(4) + smallRadius, acceptCirclePaint); + avatarWavesDrawable.update(); + int cx = (int) (buttonWidth / 2f); + avatarWavesDrawable.draw(canvas, cx, cx, this); } acceptDrawable.draw(canvas); - acceptRect.set(getMeasuredWidth() - AndroidUtilities.dp(46) - buttonWidth, AndroidUtilities.dp(40), getMeasuredWidth() - AndroidUtilities.dp(46), AndroidUtilities.dp(40) + buttonWidth); + acceptRect.set(AndroidUtilities.dp(46), AndroidUtilities.dp(40), AndroidUtilities.dp(46) + buttonWidth, AndroidUtilities.dp(40) + buttonWidth); if (retryMod) { canvas.save(); - canvas.translate(buttonWidth / 2f - retryLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(8)); + canvas.translate(buttonWidth / 2f - retryLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(4)); retryLayout.draw(canvas); canvas.restore(); } else { canvas.save(); - canvas.translate(buttonWidth / 2f - acceptLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(8)); + canvas.translate(buttonWidth / 2f - acceptLayout.getWidth() / 2f, buttonWidth + AndroidUtilities.dp(4)); acceptLayout.draw(canvas); canvas.restore(); } canvas.save(); - canvas.translate(-AndroidUtilities.dp(1), AndroidUtilities.dp(1)); - canvas.rotate(-135, callDrawable.getBounds().centerX(), callDrawable.getBounds().centerY()); - callDrawable.draw(canvas); + canvas.translate(AndroidUtilities.dp(6), AndroidUtilities.dp(6)); + callAcceptDrawable.draw(canvas); canvas.restore(); if (!leftDrag) { @@ -378,6 +324,10 @@ public class AcceptDeclineView extends View { canvas.restore(); canvas.restore(); + + if (captured) { + invalidate(); + } } public void setListener(Listener listener) { @@ -390,16 +340,43 @@ public class AcceptDeclineView extends View { void onDecline(); } + private ValueAnimator callAnimator; + public void setRetryMod(boolean retryMod) { this.retryMod = retryMod; if (retryMod) { declineDrawable.setColor(Color.WHITE); - screenWasWakeup = false; } else { - declineDrawable.setColor(0xFFe61e44); + callAcceptDrawable.start(); + avatarWavesDrawable.setShowWaves(true, this); + declineDrawable.setColor(0xFFF01D2C); + + callAnimator = ValueAnimator.ofInt(0, 60, 0, 0, 60, 0, 0, 0, 0); + callAnimator.addUpdateListener(a -> { + avatarWavesDrawable.setAmplitude((int) a.getAnimatedValue()); + }); + + callAnimator.setDuration(1500); + callAnimator.setRepeatMode(ValueAnimator.RESTART); + callAnimator.setRepeatCount(ValueAnimator.INFINITE); + callAnimator.start(); } } + public void stopAnimations() { + if (callAnimator != null) { + callAnimator.cancel(); + callAnimator = null; + callAcceptDrawable.stop(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopAnimations(); + } + @Override protected void drawableStateChanged() { super.drawableStateChanged(); @@ -407,7 +384,7 @@ public class AcceptDeclineView extends View { } @Override - public boolean verifyDrawable(Drawable drawable) { + public boolean verifyDrawable(@NonNull Drawable drawable) { return rippleDrawable == drawable || super.verifyDrawable(drawable); } @@ -490,10 +467,6 @@ public class AcceptDeclineView extends View { return accessibilityNodeProvider; } - public void setScreenWasWakeup(boolean screenWasWakeup) { - this.screenWasWakeup = screenWasWakeup; - } - public static abstract class AcceptDeclineAccessibilityNodeProvider extends AccessibilityNodeProvider { private final View hostView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EmojiRationalLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EmojiRationalLayout.java new file mode 100644 index 000000000..a97fa69e2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EmojiRationalLayout.java @@ -0,0 +1,30 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.RectF; +import android.widget.LinearLayout; + +@SuppressLint("ViewConstructor") +public class EmojiRationalLayout extends LinearLayout { + + private final RectF bgRect = new RectF(); + private final VoIPBackgroundProvider backgroundProvider; + + public EmojiRationalLayout(Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + bgRect.set(0, 0, getWidth(), getHeight()); + backgroundProvider.setDarkTranslation(getX(), getY()); + canvas.drawRoundRect(bgRect, dp(20), dp(20), backgroundProvider.getDarkPaint()); + super.dispatchDraw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EndCloseLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EndCloseLayout.java new file mode 100644 index 000000000..1f7fc064d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/EndCloseLayout.java @@ -0,0 +1,252 @@ +package org.telegram.ui.Components.voip; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ArgbEvaluator; +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.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.transition.ChangeBounds; +import android.transition.TransitionManager; +import android.transition.TransitionSet; +import android.transition.TransitionValues; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; + +public class EndCloseLayout extends FrameLayout { + private final EndCloseView endCloseView; + private final TransitionSet transitionSet; + private boolean isClosedState = false; + + public EndCloseLayout(@NonNull Context context) { + super(context); + setWillNotDraw(false); + endCloseView = new EndCloseView(context); + this.addView(endCloseView, LayoutHelper.createFrame(52, 52, Gravity.RIGHT)); + + transitionSet = new TransitionSet(); + transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); + transitionSet.addTransition(new ChangeBounds() { + + public void captureStartValues(TransitionValues transitionValues) { + super.captureStartValues(transitionValues); + if (transitionValues.view instanceof EndCloseView) { + int color = ((EndCloseView) transitionValues.view).backColor; + int round = ((EndCloseView) transitionValues.view).round; + int declineCallAlpha = ((EndCloseView) transitionValues.view).callDeclineAlpha; + int closeTextAlpha = ((EndCloseView) transitionValues.view).closeTextAlpha; + transitionValues.values.put("back_color_end_close", color); + transitionValues.values.put("round_end_close", round); + transitionValues.values.put("decline_call_alpha_end_close", declineCallAlpha); + transitionValues.values.put("close_text_alpha_end_close", closeTextAlpha); + } + } + + public void captureEndValues(TransitionValues transitionValues) { + super.captureEndValues(transitionValues); + if (transitionValues.view instanceof EndCloseView) { + int color = ((EndCloseView) transitionValues.view).backColor; + int round = ((EndCloseView) transitionValues.view).round; + int declineCallAlpha = ((EndCloseView) transitionValues.view).callDeclineAlpha; + int closeTextAlpha = ((EndCloseView) transitionValues.view).closeTextAlpha; + transitionValues.values.put("back_color_end_close", color); + transitionValues.values.put("round_end_close", round); + transitionValues.values.put("decline_call_alpha_end_close", declineCallAlpha); + transitionValues.values.put("close_text_alpha_end_close", closeTextAlpha); + } + } + + @Override + public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { + if (startValues != null && endValues != null && startValues.view instanceof EndCloseView) { + AnimatorSet animatorSet = new AnimatorSet(); + Animator animator = super.createAnimator(sceneRoot, startValues, endValues); + if (animator != null) { + animatorSet.playTogether(animator); + } + final Integer startTextColor = (Integer) startValues.values.get("back_color_end_close"); + final Integer endTextColor = (Integer) endValues.values.get("back_color_end_close"); + final Integer startRound = (Integer) startValues.values.get("round_end_close"); + final Integer endRound = (Integer) endValues.values.get("round_end_close"); + final Integer startDeclineCallAlpha = (Integer) startValues.values.get("decline_call_alpha_end_close"); + final Integer endDeclineCallAlpha = (Integer) endValues.values.get("decline_call_alpha_end_close"); + final Integer startCloseTextAlpha = (Integer) startValues.values.get("close_text_alpha_end_close"); + final Integer endCloseTextAlpha = (Integer) endValues.values.get("close_text_alpha_end_close"); + + ValueAnimator colorAnimator = new ValueAnimator(); + colorAnimator.setIntValues(startTextColor, endTextColor); + colorAnimator.setEvaluator(new ArgbEvaluator()); + colorAnimator.addUpdateListener(a -> ((EndCloseView) startValues.view).backColor = (int) a.getAnimatedValue()); + animatorSet.playTogether(colorAnimator); + + ValueAnimator roundAnimator = ValueAnimator.ofInt(startRound, endRound); + roundAnimator.addUpdateListener(animation -> ((EndCloseView) startValues.view).round = (int) animation.getAnimatedValue()); + animatorSet.playTogether(roundAnimator); + + ValueAnimator declineCallAlphaAnimator = ValueAnimator.ofInt(startDeclineCallAlpha, endDeclineCallAlpha, endDeclineCallAlpha, endDeclineCallAlpha, endDeclineCallAlpha, endDeclineCallAlpha, endDeclineCallAlpha); + declineCallAlphaAnimator.addUpdateListener(animation -> ((EndCloseView) startValues.view).callDeclineAlpha = (int) animation.getAnimatedValue()); + animatorSet.playTogether(declineCallAlphaAnimator); + + ValueAnimator closeTextAlphaAnimator = ValueAnimator.ofInt(startCloseTextAlpha, startCloseTextAlpha, (int) (endCloseTextAlpha * 0.25f), (int) (endCloseTextAlpha * 0.5f), (int) (endCloseTextAlpha * 0.75f), endCloseTextAlpha); + closeTextAlphaAnimator.addUpdateListener(animation -> ((EndCloseView) startValues.view).closeTextAlpha = (int) animation.getAnimatedValue()); + animatorSet.playTogether(closeTextAlphaAnimator); + + animatorSet.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + startValues.view.setEnabled(false); + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + startValues.view.setEnabled(true); + } + }); + return animatorSet; + } else { + return super.createAnimator(sceneRoot, startValues, endValues); + } + } + }); + transitionSet.setDuration(500); + transitionSet.setInterpolator(CubicBezierInterpolator.DEFAULT); + } + + public EndCloseView getEndCloseView() { + return endCloseView; + } + + public void switchToClose(OnClickListener onClickListener, boolean animate) { + if (isClosedState) return; + isClosedState = true; + + if (animate) { + TransitionManager.beginDelayedTransition(this, transitionSet); + } + + endCloseView.closeTextAlpha = 255; + endCloseView.backColor = 0xFFffffff; + endCloseView.callDeclineAlpha = 0; + endCloseView.round = AndroidUtilities.dp(8); + ViewGroup.LayoutParams lp = endCloseView.getLayoutParams(); + lp.width = ViewGroup.LayoutParams.MATCH_PARENT; + endCloseView.setLayoutParams(lp); + AndroidUtilities.runOnUIThread(() -> endCloseView.setOnClickListener(onClickListener), 500); + } + + static class EndCloseView extends View { + private Drawable rippleDrawable; + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaintMask = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final RectF backgroundRect = new RectF(); + private final Drawable callDeclineDrawable; + private final String closeText; + public int backColor = 0xFFf4606c; + public int round = AndroidUtilities.dp(26); + public int callDeclineAlpha = 255; + public int closeTextAlpha = 0; + + public EndCloseView(@NonNull Context context) { + super(context); + callDeclineDrawable = ContextCompat.getDrawable(getContext(), R.drawable.calls_decline).mutate(); + callDeclineDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); + textPaintMask.setTextSize(AndroidUtilities.dp(18)); + textPaintMask.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textPaintMask.setTextAlign(Paint.Align.CENTER); + textPaintMask.setColor(0xff000000); + textPaintMask.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + textPaint.setTextSize(AndroidUtilities.dp(18)); + textPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setColor(Color.BLACK); + setLayerType(View.LAYER_TYPE_HARDWARE, null); + setClickable(true); + closeText = LocaleController.getString("Close", R.string.Close); + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + if (rippleDrawable != null) { + rippleDrawable.setState(getDrawableState()); + } + } + + @Override + public boolean verifyDrawable(@NonNull Drawable drawable) { + return rippleDrawable == drawable || super.verifyDrawable(drawable); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (rippleDrawable != null) { + rippleDrawable.jumpToCurrentState(); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (!isEnabled()) { + return false; + } + return super.dispatchTouchEvent(ev); + } + + @Override + protected void onDraw(Canvas canvas) { + float cx = getWidth() / 2f; + float cy = getHeight() / 2f; + backgroundPaint.setColor(backColor); + backgroundRect.set(0, 0, getWidth(), getHeight()); + canvas.drawRoundRect(backgroundRect, round, round, backgroundPaint); + + callDeclineDrawable.setBounds( + (int) (cx - callDeclineDrawable.getIntrinsicWidth() / 2f), (int) (cy - callDeclineDrawable.getIntrinsicHeight() / 2), + (int) (cx + callDeclineDrawable.getIntrinsicWidth() / 2), (int) (cy + callDeclineDrawable.getIntrinsicHeight() / 2) + ); + callDeclineDrawable.setAlpha(callDeclineAlpha); + callDeclineDrawable.draw(canvas); + + textPaintMask.setAlpha(closeTextAlpha); + int maxDarkAlpha = (int) (255 * 0.15f); + textPaint.setAlpha(maxDarkAlpha * (closeTextAlpha / 255)); + canvas.drawText(closeText, cx, cy + AndroidUtilities.dp(6), textPaintMask); + canvas.drawText(closeText, cx, cy + AndroidUtilities.dp(6), textPaint); + + if (rippleDrawable == null) { + rippleDrawable = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector), 8, 8); + rippleDrawable.setCallback(this); + } + rippleDrawable.setBounds(0, 0, getWidth(), getHeight()); + rippleDrawable.draw(canvas); + } + } +} + + diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/FabBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/FabBackgroundDrawable.java index 00970215c..f5b08b01b 100755 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/FabBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/FabBackgroundDrawable.java @@ -62,7 +62,6 @@ public class FabBackgroundDrawable extends Drawable { shadowBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ALPHA_8); Canvas c = new Canvas(shadowBitmap); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); - p.setShadowLayer(AndroidUtilities.dp(3.33333f), 0, AndroidUtilities.dp(0.666f), 0xFFFFFFFF); c.drawCircle(size / 2, size / 2, size / 2 - AndroidUtilities.dp(4), p); } 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 new file mode 100644 index 000000000..4b177f694 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java @@ -0,0 +1,40 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.RectF; +import android.view.View; +import android.widget.TextView; +import org.telegram.messenger.R; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; + +@SuppressLint("ViewConstructor") +public class HideEmojiTextView extends TextView { + + private final RectF bgRect = new RectF(); + private final VoIPBackgroundProvider backgroundProvider; + + public HideEmojiTextView(Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); + setText(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)); + } + + @Override + protected void onDraw(Canvas canvas) { + bgRect.set(0, 0, getWidth(), getHeight()); + backgroundProvider.setDarkTranslation(getX() + ((View) getParent()).getX(), getY() + ((View) getParent()).getY()); + canvas.drawRoundRect(bgRect, dp(16), dp(16), backgroundProvider.getDarkPaint()); + super.onDraw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/ImageWithWavesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/ImageWithWavesView.java new file mode 100644 index 000000000..d7847f721 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/ImageWithWavesView.java @@ -0,0 +1,267 @@ +package org.telegram.ui.Components.voip; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.LiteMode; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; + +public class ImageWithWavesView extends FrameLayout { + private final AvatarWavesDrawable avatarWavesDrawable; + private final BackupImageView backupImageView; + private AnimatorSet animatorSet; + private boolean isConnectedCalled; + private boolean isMuted; + private final boolean allowAnimations; + + public ImageWithWavesView(Context context) { + super(context); + avatarWavesDrawable = new AvatarWavesDrawable(AndroidUtilities.dp(104), AndroidUtilities.dp(111), AndroidUtilities.dp(12), 8); + avatarWavesDrawable.setAmplitude(3f); + avatarWavesDrawable.setShowWaves(true, this); + backupImageView = new BackupImageView(context); + addView(backupImageView, LayoutHelper.createFrame(135, 135, Gravity.CENTER)); + setWillNotDraw(false); + animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(this, View.SCALE_X, 1.f, 1.05f, 1f, 1.05f, 1f), + ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.f, 1.05f, 1f, 1.05f, 1f) + ); + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); + animatorSet.setDuration(3000); + allowAnimations = LiteMode.isEnabled(LiteMode.FLAG_CALLS_ANIMATIONS); + if (allowAnimations) { + animatorSet.start(); + } + setClipChildren(false); + } + + public void setImage(ImageLocation imageLocation, String imageFilter, String ext, Drawable thumb, Object parentObject) { + backupImageView.setImage(imageLocation, imageFilter, ext, thumb, parentObject); + } + + public void setImage(ImageLocation imageLocation, String imageFilter, Drawable thumb, Object parentObject) { + backupImageView.setImage(imageLocation, imageFilter, thumb, parentObject); + } + + public void setRoundRadius(int value) { + backupImageView.setRoundRadius(value); + } + + public void setShowWaves(boolean showWaves) { + avatarWavesDrawable.setShowWaves(showWaves, this); + } + + public void setMute(boolean isMuted, boolean isFast) { + if (this.isMuted != isMuted) { + this.isMuted = isMuted; + if (isMuted) { + avatarWavesDrawable.setAmplitude(3f); + } + avatarWavesDrawable.setMuteToStatic(isMuted, isFast, this); + } + } + + public void setAmplitude(double value) { + if (isMuted) return; + if (value > 1.5f) { + avatarWavesDrawable.setAmplitude(value); + } else { + avatarWavesDrawable.setAmplitude(0); + } + } + + public void onConnected() { + if (isConnectedCalled) { + return; + } + if (animatorSet != null) { + animatorSet.cancel(); + } + isConnectedCalled = true; + animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(this, View.SCALE_X, this.getScaleX(), 1.05f, 1f), + ObjectAnimator.ofFloat(this, View.SCALE_Y, this.getScaleY(), 1.05f, 1f) + ); + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); + animatorSet.setDuration(400); + animatorSet.start(); + } + + public void onNeedRating() { + setShowWaves(false); + if (animatorSet != null) { + animatorSet.cancel(); + } + animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofFloat(this, View.ALPHA, this.getAlpha(), 1f), + ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, this.getTranslationY(), -(float) AndroidUtilities.dp(24)), + ObjectAnimator.ofFloat(this, View.SCALE_X, this.getScaleX(), 0.9f, 1f), + ObjectAnimator.ofFloat(this, View.SCALE_Y, this.getScaleY(), 0.9f, 1f) + ); + animatorSet.setInterpolator(CubicBezierInterpolator.DEFAULT); + animatorSet.setDuration(300); + animatorSet.setStartDelay(250); + animatorSet.start(); + } + + @Override + protected void onDraw(Canvas canvas) { + if(allowAnimations) { + avatarWavesDrawable.update(); + int cx = getWidth() / 2; + int cy = getHeight() / 2; + avatarWavesDrawable.draw(canvas, cx, cy, this); + } + super.onDraw(canvas); + } + + public static class AvatarWavesDrawable { + + float amplitude; + float animateToAmplitude; + float animateAmplitudeDiff; + float wavesEnter = 0f; + boolean showWaves; + + private final VoipBlobDrawable blobDrawable; + private final VoipBlobDrawable blobDrawable2; + + public boolean muteToStatic = false; + public float muteToStaticProgress = 1f; + + private ValueAnimator animator; + private int muteToStaticInvalidationCount; + + public AvatarWavesDrawable(int minRadius, int maxRadius, int diff, int n) { + blobDrawable = new VoipBlobDrawable(n - 1); + blobDrawable2 = new VoipBlobDrawable(n); + blobDrawable.minRadius = minRadius; + blobDrawable.maxRadius = maxRadius; + blobDrawable2.minRadius = minRadius - diff; + blobDrawable2.maxRadius = maxRadius - diff; + blobDrawable.generateBlob(); + blobDrawable2.generateBlob(); + blobDrawable.paint.setColor(Color.WHITE); + blobDrawable.paint.setAlpha(20); + blobDrawable2.paint.setColor(Color.WHITE); + blobDrawable2.paint.setAlpha(36); + } + + public void update() { + if (animateToAmplitude != amplitude) { + amplitude += animateAmplitudeDiff * 16; + if (animateAmplitudeDiff > 0) { + if (amplitude > animateToAmplitude) { + amplitude = animateToAmplitude; + } + } else { + if (amplitude < animateToAmplitude) { + amplitude = animateToAmplitude; + } + } + } + + if (showWaves && wavesEnter != 1f) { + wavesEnter += 16 / 350f; + if (wavesEnter > 1f) { + wavesEnter = 1f; + } + } else if (!showWaves && wavesEnter != 0) { + wavesEnter -= 16 / 350f; + if (wavesEnter < 0f) { + wavesEnter = 0f; + } + } + } + + public void draw(Canvas canvas, float cx, float cy, View parentView) { + float scaleBlob = 0.8f + 0.4f * amplitude; + if (showWaves || wavesEnter != 0) { + canvas.save(); + float wavesEnter = CubicBezierInterpolator.DEFAULT.getInterpolation(this.wavesEnter); + + canvas.scale(scaleBlob * wavesEnter, scaleBlob * wavesEnter, cx, cy); + + blobDrawable.update(amplitude, 1f, muteToStaticProgress); + blobDrawable.draw(cx, cy, canvas, blobDrawable.paint); + + blobDrawable2.update(amplitude, 1f, muteToStaticProgress); + blobDrawable2.draw(cx, cy, canvas, blobDrawable.paint); + canvas.restore(); + } + + if (muteToStatic && muteToStaticInvalidationCount == 0) { + return; + } + + if (muteToStaticInvalidationCount != 0) { + muteToStaticInvalidationCount--; + } + + if (wavesEnter != 0) { + parentView.invalidate(); + } + } + + public void setShowWaves(boolean show, View parentView) { + if (showWaves != show) { + parentView.invalidate(); + } + showWaves = show; + } + + public void setAmplitude(double value) { + float amplitude = (float) value / 80f; + if (!showWaves) { + amplitude = 0; + } + if (amplitude > 1f) { + amplitude = 1f; + } else if (amplitude < 0) { + amplitude = 0; + } + animateToAmplitude = amplitude; + animateAmplitudeDiff = (animateToAmplitude - this.amplitude) / 200; + } + + public void setMuteToStatic(boolean mute, boolean isFast, View parentView) { + if (muteToStatic != mute) { + muteToStatic = mute; + if (animator != null) { + animator.removeAllUpdateListeners(); + animator.cancel(); + } + if (mute) { + animator = ValueAnimator.ofFloat(muteToStaticProgress, 0f); + muteToStaticInvalidationCount = (int) (2000 / AndroidUtilities.screenRefreshTime); + } else { + muteToStaticInvalidationCount = 0; + animator = ValueAnimator.ofFloat(muteToStaticProgress, 1f); + } + animator.addUpdateListener(a -> muteToStaticProgress = (float) a.getAnimatedValue()); + if (isFast) { + animator.setDuration(150); + } else { + animator.setDuration(1000); + } + animator.start(); + parentView.invalidate(); + } + } + } +} 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 new file mode 100644 index 000000000..02f6189fd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/PrivateVideoPreviewDialogNew.java @@ -0,0 +1,797 @@ +package org.telegram.ui.Components.voip; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Camera; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.media.projection.MediaProjectionManager; +import android.os.Build; +import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.voip.VideoCapturerDevice; +import org.telegram.messenger.voip.VoIPService; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BitmapShaderTools; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.MotionBackgroundDrawable; +import org.telegram.ui.LaunchActivity; +import org.webrtc.RendererCommon; + +import java.io.File; +import java.io.FileOutputStream; + +@TargetApi(21) +public abstract class PrivateVideoPreviewDialogNew extends FrameLayout implements VoIPService.StateListener { + + private boolean isDismissed; + + private FrameLayout viewPager; + private TextView positiveButton; + private LinearLayout titlesLayout; + private VoIpBitmapTextView[] titles; + private VoIPTextureView textureView; + private int visibleCameraPage = 1; + private boolean cameraReady; + private ActionBar actionBar; + + private float pageOffset; + private int strangeCurrentPage; + private int realCurrentPage; + private int previousPage = -1; + + private float openProgress1 = 0f; + private float openProgress2 = 0f; + private float closeProgress = 0f; + private float openTranslationX; + private float openTranslationY; + private final float startLocationX; + private final float startLocationY; + private final Path clipPath = new Path(); + private final Camera camera = new Camera(); + private final Matrix matrixRight = new Matrix(); + private final Matrix matrixLeft = new Matrix(); + private boolean positiveButtonDrawText; + + private final BitmapShaderTools bgGreenShaderTools = new BitmapShaderTools(80, 80); + private final BitmapShaderTools bgBlueVioletShaderTools = new BitmapShaderTools(80, 80); + private final MotionBackgroundDrawable bgGreen = new MotionBackgroundDrawable(0xFF5FD051, 0xFF00B48E, 0xFFA9CC66, 0xFF5AB147, 0, false, true); + private final MotionBackgroundDrawable bgBlueViolet = new MotionBackgroundDrawable(0xFF00A3E6, 0xFF296EF7, 0xFF18CEE2, 0xFF3FB2FF, 0, false, true); + private final GestureDetector scrollGestureDetector; + + public PrivateVideoPreviewDialogNew(Context context, float startLocationX, float startLocationY) { + super(context); + + this.startLocationX = startLocationX; + this.startLocationY = startLocationY; + titles = new VoIpBitmapTextView[3]; + scrollGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + private boolean startDragging; + private boolean lockDragging; + + @Override + public boolean onDown(@NonNull MotionEvent e) { + startDragging = true; + return super.onDown(e); + } + + @Override + public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) { + float dx = e1.getX() - e2.getX(); + float dy = e1.getY() - e2.getY(); + if (Math.abs(dx) > AndroidUtilities.getPixelsInCM(0.4f, true) && Math.abs(dx) / 3 > dy && startDragging && !lockDragging) { + startDragging = false; + Runnable action = () -> { + if (dx > 0) { + if (realCurrentPage < 2) { + setCurrentPage(realCurrentPage + 1, true); + } + } else { + if (realCurrentPage > 0) { + setCurrentPage(realCurrentPage - 1, true); + } + } + lockDragging = false; + }; + if (scrollAnimator != null) { + lockDragging = true; + AndroidUtilities.runOnUIThread(action, scrollAnimator.getDuration() - scrollAnimator.getCurrentPlayTime() + 50); + } else { + action.run(); + } + } + return super.onScroll(e1, e2, distanceX, distanceY); + } + }); + viewPager = new FrameLayout(context) { + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + scrollGestureDetector.onTouchEvent(event); + return super.onTouchEvent(event); + } + }; + viewPager.setClickable(true); + + addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + textureView = new VoIPTextureView(context, false, false); + textureView.renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL); + textureView.scaleType = VoIPTextureView.SCALE_TYPE_FIT; + textureView.clipToTexture = true; + textureView.renderer.setAlpha(0); + textureView.renderer.setRotateTextureWithScreen(true); + textureView.renderer.setUseCameraRotation(true); + addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + actionBar = new ActionBar(context); + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setBackgroundColor(Color.TRANSPARENT); + actionBar.setItemsColor(Theme.getColor(Theme.key_voipgroup_actionBarItems), false); + actionBar.setOccupyStatusBar(true); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + dismiss(false, false); + } + } + }); + addView(actionBar); + + positiveButton = new TextView(getContext()) { + private final Paint whitePaint = new Paint(); + private final Paint[] gradientPaint = new Paint[titles.length]; + + { + bgGreen.setBounds(0, 0, 80, 80); + bgBlueViolet.setBounds(0, 0, 80, 80); + bgGreenShaderTools.setBounds(0, 0, 80, 80); + bgBlueVioletShaderTools.setBounds(0, 0, 80, 80); + bgGreen.setAlpha(255); + bgBlueViolet.setAlpha(255); + bgGreenShaderTools.getCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + bgBlueVioletShaderTools.getCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + bgGreen.draw(bgGreenShaderTools.getCanvas()); + bgBlueViolet.draw(bgBlueVioletShaderTools.getCanvas()); + whitePaint.setColor(Color.WHITE); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + for (int a = 0; a < gradientPaint.length; a++) { + if (a == 0) { + gradientPaint[a] = bgGreenShaderTools.paint; + } else if (a == 1) { + gradientPaint[a] = bgBlueVioletShaderTools.paint; + } else { + gradientPaint[a] = bgGreenShaderTools.paint; + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + bgGreenShaderTools.setBounds(-getX(), -getY(), PrivateVideoPreviewDialogNew.this.getWidth() - getX(), PrivateVideoPreviewDialogNew.this.getHeight() - getY()); + bgBlueVioletShaderTools.setBounds(-getX(), -getY(), PrivateVideoPreviewDialogNew.this.getWidth() - getX(), PrivateVideoPreviewDialogNew.this.getHeight() - getY()); + + AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + gradientPaint[strangeCurrentPage].setAlpha(255); + int round = AndroidUtilities.dp(8) + (int) ((AndroidUtilities.dp(26) - AndroidUtilities.dp(8)) * (1f - openProgress1)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, round, round, gradientPaint[strangeCurrentPage]); + if (pageOffset > 0 && strangeCurrentPage + 1 < gradientPaint.length) { + gradientPaint[strangeCurrentPage + 1].setAlpha((int) (255 * pageOffset)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, round, round, gradientPaint[strangeCurrentPage + 1]); + } + if (openProgress1 < 1f) { + whitePaint.setAlpha((int) (255 * (1f - openProgress1))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, round, round, whitePaint); + } + super.onDraw(canvas); + + if (positiveButtonDrawText) { + int xPos = (getWidth() / 2); + int yPos = (int) ((getHeight() / 2) - ((positiveButton.getPaint().descent() + positiveButton.getPaint().ascent()) / 2)); + canvas.drawText(LocaleController.getString("VoipShareVideo", R.string.VoipShareVideo), xPos, yPos, positiveButton.getPaint()); + } + } + }; + positiveButton.setMaxLines(1); + positiveButton.setEllipsize(null); + positiveButton.setMinWidth(AndroidUtilities.dp(64)); + positiveButton.setTag(Dialog.BUTTON_POSITIVE); + positiveButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + positiveButton.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText)); + positiveButton.setGravity(Gravity.CENTER); + positiveButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + positiveButton.getPaint().setTextAlign(Paint.Align.CENTER); + + 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)))); + } + positiveButton.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12)); + positiveButton.setOnClickListener(view -> { + if (isDismissed) { + return; + } + if (realCurrentPage == 0) { + MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE); + ((Activity) getContext()).startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), LaunchActivity.SCREEN_CAPTURE_REQUEST_CODE); + } else { + dismiss(false, true); + } + }); + + addView(positiveButton, LayoutHelper.createFrame(52, 52, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 80)); + + titlesLayout = new LinearLayout(context) { + + @Override + protected void dispatchDraw(Canvas canvas) { + int halfWidth = getWidth() / 2; + int halfHeight = getHeight() / 2; + + camera.save(); + camera.rotateY(7); + camera.getMatrix(matrixRight); + camera.restore(); + matrixRight.preTranslate(-halfWidth, -halfHeight); + matrixRight.postTranslate(halfWidth, halfHeight); + canvas.save(); + canvas.clipRect(halfWidth, 0, getWidth(), getHeight()); + canvas.concat(matrixRight); + super.dispatchDraw(canvas); + canvas.restore(); + + camera.save(); + camera.rotateY(-7); + camera.getMatrix(matrixLeft); + camera.restore(); + matrixLeft.preTranslate(-halfWidth, -halfHeight); + matrixLeft.postTranslate(halfWidth, halfHeight); + canvas.save(); + canvas.clipRect(0, 0, halfWidth, getHeight()); + canvas.concat(matrixLeft); + super.dispatchDraw(canvas); + canvas.restore(); + } + }; + titlesLayout.setClipChildren(false); + addView(titlesLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 64, Gravity.BOTTOM)); + + for (int i = 0; i < titles.length; i++) { + String text; + if (i == 0) { + text = LocaleController.getString("VoipPhoneScreen", R.string.VoipPhoneScreen); + } else if (i == 1) { + text = LocaleController.getString("VoipFrontCamera", R.string.VoipFrontCamera); + } else { + text = LocaleController.getString("VoipBackCamera", R.string.VoipBackCamera); + } + titles[i] = new VoIpBitmapTextView(context, 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; + titles[i].setOnClickListener(view -> { + if (scrollAnimator != null || view.getAlpha() == 0f) return; + setCurrentPage(num, true); + }); + } + + setWillNotDraw(false); + + VoIPService service = VoIPService.getSharedInstance(); + if (service != null) { + textureView.renderer.setMirror(service.isFrontFaceCamera()); + textureView.renderer.init(VideoCapturerDevice.getEglBase().getEglBaseContext(), new RendererCommon.RendererEvents() { + @Override + public void onFirstFrameRendered() { + + } + + @Override + public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) { + + } + }); + service.setLocalSink(textureView.renderer, false); + } + createPages(viewPager); + + ValueAnimator openAnimator1 = ValueAnimator.ofFloat(0f, 1f); + openAnimator1.addUpdateListener(animation -> { + openProgress1 = (float) animation.getAnimatedValue(); + float startLocationXWithOffset = startLocationX + AndroidUtilities.dp(28); + float startLocationYWithOffset = startLocationY + AndroidUtilities.dp(52); + openTranslationX = startLocationXWithOffset - (startLocationXWithOffset * openProgress1); + openTranslationY = startLocationYWithOffset - (startLocationYWithOffset * openProgress1); + invalidate(); + }); + openAnimator1.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isDismissed) { + afterOpened(); + } + } + }); + ValueAnimator openAnimator2 = ValueAnimator.ofFloat(0f, 1f); + openAnimator2.addUpdateListener(animation -> { + openProgress2 = (float) animation.getAnimatedValue(); + int w = AndroidUtilities.displaySize.x - AndroidUtilities.dp(36) - AndroidUtilities.dp(52); + positiveButton.getLayoutParams().width = AndroidUtilities.dp(52) + (int) (w * openProgress2); + positiveButton.requestLayout(); + }); + int openAnimationTime = 320; + openAnimator1.setInterpolator(CubicBezierInterpolator.DEFAULT); + openAnimator1.setDuration(openAnimationTime); + openAnimator1.start(); + openAnimator2.setInterpolator(CubicBezierInterpolator.DEFAULT); + openAnimator2.setDuration(openAnimationTime); + openAnimator2.setStartDelay(openAnimationTime / 10); + openAnimator2.start(); + titlesLayout.setAlpha(0f); + titlesLayout.setScaleY(0.8f); + titlesLayout.setScaleX(0.8f); + titlesLayout.animate().alpha(1f).scaleX(1f).scaleY(1f).setStartDelay(120).setDuration(250).start(); + positiveButton.setTranslationY(AndroidUtilities.dp(53)); + positiveButton.setTranslationX(startLocationX - (AndroidUtilities.displaySize.x / 2f) + AndroidUtilities.dp(8) + AndroidUtilities.dp(26)); + positiveButton.animate().translationY(0).translationX(0).setDuration(openAnimationTime).start(); + positiveButtonDrawText = true; + setCurrentPage(1, false); + } + + private void showStub(boolean show, boolean animate) { + ImageView imageView = viewPager.findViewWithTag("image_stab"); + if (!show) { + imageView.setVisibility(GONE); + return; + } + Bitmap bitmap = null; + try { + File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb" + visibleCameraPage + ".jpg"); + bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + } catch (Throwable ignore) { + + } + + if (bitmap != null && bitmap.getPixel(0, 0) != 0) { + imageView.setImageBitmap(bitmap); + } else { + imageView.setImageResource(R.drawable.icplaceholder); + } + if (animate) { + imageView.setVisibility(VISIBLE); + imageView.setAlpha(0f); + imageView.animate().alpha(1f).setDuration(250).start(); + } else { + imageView.setAlpha(1f); + imageView.setVisibility(VISIBLE); + } + } + + private ValueAnimator scrollAnimator; + + private void setCurrentPage(int position, boolean animate) { + if (strangeCurrentPage == position || realCurrentPage == position) return; + + if (animate) { + if (realCurrentPage == 0) { + //switch from screencast to any camera + if (visibleCameraPage != position) { + visibleCameraPage = position; + cameraReady = false; + showStub(true, true); + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().switchCamera(); + } + } else { + showStub(false, false); + textureView.animate().alpha(1f).setDuration(250).start(); + } + } else { + if (position == 0) { + //switch to screencast from any camera + viewPager.findViewWithTag("screencast_stub").setVisibility(VISIBLE); + saveLastCameraBitmap(); + showStub(false, false); + textureView.animate().alpha(0f).setDuration(250).start(); + } else { + //switch between cameras + saveLastCameraBitmap(); + visibleCameraPage = position; + cameraReady = false; + showStub(true, false); + textureView.animate().alpha(0f).setDuration(250).start(); + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().switchCamera(); + } + } + } + + if (position > realCurrentPage) { + //to the right + previousPage = realCurrentPage; + realCurrentPage = realCurrentPage + 1; + scrollAnimator = ValueAnimator.ofFloat(0.1f, 1f); + } else { + //to the left + previousPage = realCurrentPage; + realCurrentPage = realCurrentPage - 1; + strangeCurrentPage = position; + scrollAnimator = ValueAnimator.ofFloat(1f, 0f); + } + + scrollAnimator.addUpdateListener(animation -> { + pageOffset = (float) animation.getAnimatedValue(); + updateTitlesLayout(); + }); + scrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + previousPage = -1; + strangeCurrentPage = position; + pageOffset = 0; + scrollAnimator = null; + updateTitlesLayout(); + } + }); + scrollAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + scrollAnimator.setDuration(350); + scrollAnimator.start(); + } else { + realCurrentPage = position; + strangeCurrentPage = position; + pageOffset = 0; + updateTitlesLayout(); + textureView.setVisibility(VISIBLE); + cameraReady = false; + visibleCameraPage = 1; + showStub(true, false); + } + } + + private void createPages(FrameLayout container) { + { + FrameLayout frameLayout = new FrameLayout(getContext()); + frameLayout.setBackground(new MotionBackgroundDrawable(0xff212E3A, 0xff2B5B4D, 0xff245863, 0xff274558, true)); + + ImageView imageView = new ImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(R.drawable.screencast_big); + frameLayout.addView(imageView, LayoutHelper.createFrame(82, 82, Gravity.CENTER, 0, 0, 0, 60)); + + TextView textView = new TextView(getContext()); + textView.setText(LocaleController.getString("VoipVideoPrivateScreenSharing", R.string.VoipVideoPrivateScreenSharing)); + textView.setGravity(Gravity.CENTER); + textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); + textView.setTextColor(0xffffffff); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 21, 28, 21, 0)); + frameLayout.setTag("screencast_stub"); + frameLayout.setVisibility(GONE); + container.addView(frameLayout); + } + { + ImageView imageView = new ImageView(getContext()); + imageView.setTag("image_stab"); + imageView.setImageResource(R.drawable.icplaceholder); + imageView.setScaleType(ImageView.ScaleType.FIT_XY); + container.addView(imageView); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (openProgress1 < 1f) { + int maxWidth = AndroidUtilities.displaySize.x; + int maxHeight = AndroidUtilities.displaySize.y + AndroidUtilities.statusBarHeight + AndroidUtilities.navigationBarHeight; + float rounded = AndroidUtilities.dp(28) - (AndroidUtilities.dp(28) * openProgress1); + clipPath.reset(); + clipPath.addCircle(startLocationX + AndroidUtilities.dp(33.5f), startLocationY + AndroidUtilities.dp(26.6f), AndroidUtilities.dp(26), Path.Direction.CW); + int minWidth = AndroidUtilities.dp(52); + int minHeight = AndroidUtilities.dp(52); + int width = AndroidUtilities.lerp(minWidth, maxWidth, openProgress1); + int height = AndroidUtilities.lerp(minHeight, maxHeight, openProgress1); + float x = openTranslationX - ((1f - openProgress1) * AndroidUtilities.dp(20f)); + float y = openTranslationY - ((1f - openProgress1) * AndroidUtilities.dp(51)); + clipPath.addRoundRect(x, y, x + width, y + height, rounded, rounded, Path.Direction.CW); + canvas.clipPath(clipPath); + } + + if (closeProgress > 0f) { + int[] loc = getFloatingViewLocation(); + int x = (int) (closeProgress * loc[0]); + int y = (int) (closeProgress * loc[1]); + int destWidth = loc[2]; + int w = AndroidUtilities.displaySize.x; + float currentWidth = destWidth + ((w - destWidth) * (1f - closeProgress)); + float scale = currentWidth / w; + clipPath.reset(); + clipPath.addRoundRect(0f, 0f, getWidth() * scale, getHeight() * scale, AndroidUtilities.dp(6), AndroidUtilities.dp(6), Path.Direction.CW); + canvas.translate(x, y); + canvas.clipPath(clipPath); + canvas.scale(scale, scale); + } + + super.dispatchDraw(canvas); + } + + public void dismiss(boolean screencast, boolean apply) { + if (isDismissed || openProgress1 != 1f) { + return; + } + beforeClosed(); + isDismissed = true; + saveLastCameraBitmap(); + onDismiss(screencast, apply); + if (isHasVideoOnMainScreen() && apply) { + ValueAnimator closeAnimator = ValueAnimator.ofFloat(0f, 1f); + closeAnimator.addUpdateListener(animation -> { + closeProgress = (float) animation.getAnimatedValue(); + invalidate(); + }); + closeAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + closeAnimator.setStartDelay(60); + closeAnimator.setDuration(350); + closeAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (getParent() != null) { + ((ViewGroup) getParent()).removeView(PrivateVideoPreviewDialogNew.this); + } + } + }); + closeAnimator.start(); + positiveButton.animate().setStartDelay(60).alpha(0f).setDuration(100).start(); + actionBar.animate().setStartDelay(60).alpha(0f).setDuration(100).start(); + titlesLayout.animate().setStartDelay(60).alpha(0f).setDuration(100).start(); + } else { + if (apply) { + animate().setStartDelay(60).alpha(0f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (getParent() != null) { + ((ViewGroup) getParent()).removeView(PrivateVideoPreviewDialogNew.this); + } + } + }); + } else { + ValueAnimator openAnimator1 = ValueAnimator.ofFloat(1f, 0f); + openAnimator1.addUpdateListener(animation -> { + openProgress1 = (float) animation.getAnimatedValue(); + float startLocationXWithOffset = startLocationX + AndroidUtilities.dp(28); + float startLocationYWithOffset = startLocationY + AndroidUtilities.dp(52); + openTranslationX = startLocationXWithOffset - (startLocationXWithOffset * openProgress1); + openTranslationY = startLocationYWithOffset - (startLocationYWithOffset * openProgress1); + invalidate(); + }); + openAnimator1.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (getParent() != null) { + ((ViewGroup) getParent()).removeView(PrivateVideoPreviewDialogNew.this); + } + } + }); + ValueAnimator openAnimator2 = ValueAnimator.ofFloat(1f, 0f); + openAnimator2.addUpdateListener(animation -> { + openProgress2 = (float) animation.getAnimatedValue(); + int w = AndroidUtilities.displaySize.x - AndroidUtilities.dp(36) - AndroidUtilities.dp(52); + positiveButton.getLayoutParams().width = AndroidUtilities.dp(52) + (int) (w * openProgress2); + positiveButton.requestLayout(); + }); + int closeAnimationTime = 320; + openAnimator1.setInterpolator(CubicBezierInterpolator.DEFAULT); + openAnimator1.setDuration(closeAnimationTime); + openAnimator1.start(); + openAnimator2.setInterpolator(CubicBezierInterpolator.DEFAULT); + openAnimator2.setDuration(closeAnimationTime); + openAnimator2.start(); + titlesLayout.setAlpha(1f); + titlesLayout.setScaleY(1f); + titlesLayout.setScaleX(1f); + titlesLayout.animate().alpha(0f).scaleX(0.8f).scaleY(0.8f).setDuration(250).start(); + positiveButton.animate().translationY(AndroidUtilities.dp(53)).translationX(startLocationX - (AndroidUtilities.displaySize.x / 2f) + AndroidUtilities.dp(8) + AndroidUtilities.dp(26)).setDuration((long) (closeAnimationTime * 0.6f)).start(); + animate().alpha(0f).setDuration((long) (closeAnimationTime * (2f / 8f))).setStartDelay((long) (closeAnimationTime * (6f / 8f))).start(); + } + } + + invalidate(); + } + + public void setBottomPadding(int padding) { + LayoutParams layoutParams = (LayoutParams) positiveButton.getLayoutParams(); + layoutParams.bottomMargin = AndroidUtilities.dp(80) + padding; + + layoutParams = (LayoutParams) titlesLayout.getLayoutParams(); + layoutParams.bottomMargin = padding; + } + + private void updateTitlesLayout() { + View current = titles[strangeCurrentPage]; + View next = strangeCurrentPage < titles.length - 1 ? titles[strangeCurrentPage + 1] : null; + + float currentCx = current.getLeft() + current.getMeasuredWidth() / 2; + float tx = getMeasuredWidth() / 2 - currentCx; + if (next != null) { + float nextCx = next.getLeft() + next.getMeasuredWidth() / 2; + tx -= (nextCx - currentCx) * pageOffset; + } + for (int i = 0; i < titles.length; i++) { + float alpha; + float scale; + if (i < strangeCurrentPage || i > strangeCurrentPage + 1) { + alpha = 0.7f; + scale = 0.9f; + } else if (i == strangeCurrentPage) { + //movement to the right or selected + alpha = 1.0f - 0.3f * pageOffset; + scale = 1.0f - 0.1f * pageOffset; + } else { + alpha = 0.7f + 0.3f * pageOffset; + scale = 0.9f + 0.1f * pageOffset; + } + titles[i].setAlpha(alpha); + titles[i].setScaleX(scale); + titles[i].setScaleY(scale); + titles[i].setTranslationX(tx); + } + positiveButton.invalidate(); + if (realCurrentPage == 0) { + titles[2].setAlpha(0.7f * pageOffset); + } + if (realCurrentPage == 2) { + if (pageOffset > 0f) { + titles[0].setAlpha(0.7f * (1f - pageOffset)); + } else { + titles[0].setAlpha(0f); + } + } + if (realCurrentPage == 1) { + if (previousPage == 0) { + titles[2].setAlpha(0.7f * pageOffset); + } + if (previousPage == 2) { + titles[0].setAlpha(0.7f * (1f - pageOffset)); + } + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + VoIPService service = VoIPService.getSharedInstance(); + if (service != null) service.registerStateListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + VoIPService service = VoIPService.getSharedInstance(); + if (service != null) service.unregisterStateListener(this); + } + + private void saveLastCameraBitmap() { + if (!cameraReady) { + return; + } + try { + Bitmap bitmap = textureView.renderer.getBitmap(); + if (bitmap != null) { + Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), textureView.renderer.getMatrix(), true); + bitmap.recycle(); + bitmap = newBitmap; + Bitmap lastBitmap = Bitmap.createScaledBitmap(bitmap, 80, (int) (bitmap.getHeight() / (bitmap.getWidth() / 80.0f)), true); + if (lastBitmap != null) { + if (lastBitmap != bitmap) { + bitmap.recycle(); + } + Utilities.blurBitmap(lastBitmap, 7, 1, lastBitmap.getWidth(), lastBitmap.getHeight(), lastBitmap.getRowBytes()); + File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb" + visibleCameraPage + ".jpg"); + FileOutputStream stream = new FileOutputStream(file); + lastBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + View view = viewPager.findViewWithTag("image_stab"); + if (view instanceof ImageView) { + ((ImageView) view).setImageBitmap(lastBitmap); + } + } + } + } catch (Throwable ignore) { + + } + } + + @Override + public void onCameraFirstFrameAvailable() { + if (!cameraReady) { + cameraReady = true; + if (realCurrentPage != 0) textureView.animate().alpha(1f).setDuration(250).start(); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateTitlesLayout(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return true; + } + + protected void onDismiss(boolean screencast, boolean apply) { + + } + + protected int[] getFloatingViewLocation() { + return null; + } + + protected boolean isHasVideoOnMainScreen() { + return false; + } + + protected void afterOpened() { + + } + + protected void beforeClosed() { + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + measureChildWithMargins(titlesLayout, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY), 0); + } + + @Override + public void onCameraSwitch(boolean isFrontFace) { + update(); + } + + public void update() { + if (VoIPService.getSharedInstance() != null) { + textureView.renderer.setMirror(VoIPService.getSharedInstance().isFrontFaceCamera()); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RateCallLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RateCallLayout.java new file mode 100644 index 000000000..9c93ddc7d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/RateCallLayout.java @@ -0,0 +1,274 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieImageView; + +@SuppressLint("ViewConstructor") +public class RateCallLayout extends FrameLayout { + + private final RateCallContainer rateCallContainer; + private final FrameLayout starsContainer; + private final StarContainer[] startsViews = new StarContainer[5]; + private final VoIPBackgroundProvider backgroundProvider; + private OnRateSelected onRateSelected; + + public interface OnRateSelected { + void onRateSelected(int count); + } + + public RateCallLayout(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + setWillNotDraw(false); + rateCallContainer = new RateCallContainer(context, backgroundProvider); + starsContainer = new FrameLayout(context); + rateCallContainer.setVisibility(GONE); + starsContainer.setVisibility(GONE); + + int starMargin = 4; + for (int i = 0; i < 5; i++) { + startsViews[i] = new StarContainer(context); + startsViews[i].setAllStarsProvider(() -> startsViews); + startsViews[i].setOnSelectedStar((x, y, starsCount) -> { + if (starsCount >= 4) { + final RLottieImageView img = new RLottieImageView(context); + final int rateAnimationSize = 133; + final int rateAnimationSizeDp = AndroidUtilities.dp(rateAnimationSize); + img.setAnimation(R.raw.rate, rateAnimationSize, rateAnimationSize); + int[] location = new int[2]; + getLocationOnScreen(location); + int viewX = location[0]; + int viewY = location[1]; + addView(img, LayoutHelper.createFrame(rateAnimationSize, rateAnimationSize)); + img.setTranslationX((x - viewX) - (rateAnimationSizeDp / 2f)); + img.setTranslationY((y - viewY) - (rateAnimationSizeDp / 2f)); + + img.setOnAnimationEndListener(() -> AndroidUtilities.runOnUIThread(() -> removeView(img))); + img.playAnimation(); + } + if (onRateSelected != null) onRateSelected.onRateSelected(starsCount); + }, i); + starsContainer.addView(startsViews[i], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, i * (StarContainer.starSize + starMargin), 0, 0, 0)); + } + + addView(rateCallContainer, LayoutHelper.createFrame(300, 152, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + addView(starsContainer, LayoutHelper.createFrame((StarContainer.starSize * 5) + (starMargin * 4), 100, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 90, 0, 0)); + } + + public void show(OnRateSelected onRateSelected) { + this.onRateSelected = onRateSelected; + + rateCallContainer.setVisibility(VISIBLE); + starsContainer.setVisibility(VISIBLE); + + AnimatorSet backSet = new AnimatorSet(); + backSet.playTogether( + ObjectAnimator.ofFloat(rateCallContainer, View.ALPHA, 0, 1f), + ObjectAnimator.ofFloat(rateCallContainer, View.SCALE_X, 0.7f, 1f), + ObjectAnimator.ofFloat(rateCallContainer, View.SCALE_Y, 0.7f, 1f), + ObjectAnimator.ofFloat(rateCallContainer, View.TRANSLATION_Y, AndroidUtilities.dp(24), 0) + ); + backSet.setInterpolator(CubicBezierInterpolator.DEFAULT); + backSet.setDuration(250); + + for (int i = 0; i < startsViews.length; i++) { + AnimatorSet starSet = new AnimatorSet(); + startsViews[i].setAlpha(0f); + starSet.playTogether( + ObjectAnimator.ofFloat(startsViews[i], View.ALPHA, 0, 1f), + ObjectAnimator.ofFloat(startsViews[i], View.SCALE_X, 0.3f, 1f), + ObjectAnimator.ofFloat(startsViews[i], View.SCALE_Y, 0.3f, 1f), + ObjectAnimator.ofFloat(startsViews[i], View.TRANSLATION_Y, AndroidUtilities.dp(30), 0) + ); + starSet.setDuration(250); + starSet.setStartDelay(i * 16L); + starSet.start(); + } + backSet.start(); + } + + public static class StarContainer extends FrameLayout { + + private static final int starSize = 37; + + interface OnSelectedStar { + void onSelected(float x, float y, int starsCount); + } + + interface AllStarsProvider { + StarContainer[] getAllStartsViews(); + } + + public RLottieImageView defaultStar; + public RLottieImageView selectedStar; + private final Drawable rippleDrawable; + private OnSelectedStar onSelectedStar; + private AllStarsProvider allStarsProvider; + private int pos = 0; + + public void setOnSelectedStar(OnSelectedStar onSelectedStar, int pos) { + this.onSelectedStar = onSelectedStar; + this.pos = pos; + } + + public void setAllStarsProvider(AllStarsProvider allStarsProvider) { + this.allStarsProvider = allStarsProvider; + } + + public StarContainer(@NonNull Context context) { + super(context); + setWillNotDraw(false); + defaultStar = new RLottieImageView(context); + selectedStar = new RLottieImageView(context); + + defaultStar.setAnimation(R.raw.star_stroke, starSize, starSize); + selectedStar.setAnimation(R.raw.star_fill, starSize, starSize); + selectedStar.setAlpha(0f); + addView(defaultStar, LayoutHelper.createFrame(starSize, starSize)); + addView(selectedStar, LayoutHelper.createFrame(starSize, starSize)); + rippleDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(starSize), 0, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.3f))); + rippleDrawable.setCallback(this); + setClickable(true); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + rippleDrawable.setBounds(0, 0, getWidth(), getHeight()); + rippleDrawable.draw(canvas); + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + if (rippleDrawable != null) rippleDrawable.setState(getDrawableState()); + } + + @Override + public boolean verifyDrawable(@NonNull Drawable drawable) { + return rippleDrawable == drawable || super.verifyDrawable(drawable); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (rippleDrawable != null) rippleDrawable.jumpToCurrentState(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (allStarsProvider != null) { + RateCallLayout.StarContainer[] starsViews = allStarsProvider.getAllStartsViews(); + for (int i = 0; i <= pos; i++) { + RLottieImageView defaultStar = starsViews[i].defaultStar; + RLottieImageView selectedStar = starsViews[i].selectedStar; + defaultStar.animate().alpha(0f).scaleX(0.8f).scaleY(0.8f).setDuration(250).start(); + selectedStar.animate().alpha(1f).scaleX(0.8f).scaleY(0.8f).setDuration(250).start(); + } + + for (int i = pos + 1; i < starsViews.length; i++) { + RLottieImageView defaultStar = starsViews[i].defaultStar; + RLottieImageView selectedStar = starsViews[i].selectedStar; + defaultStar.animate().alpha(1f).scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + selectedStar.animate().alpha(0f).scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + } + } + break; + case MotionEvent.ACTION_UP: + if (allStarsProvider != null) { + RateCallLayout.StarContainer[] starsViews = allStarsProvider.getAllStartsViews(); + for (int i = 0; i <= pos; i++) { + RLottieImageView defaultStar = starsViews[i].defaultStar; + RLottieImageView selectedStar = starsViews[i].selectedStar; + defaultStar.animate().scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + selectedStar.animate().scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + } + } + if (onSelectedStar != null) { + int[] location = new int[2]; + getLocationOnScreen(location); + int viewX = location[0]; + int viewY = location[1]; + onSelectedStar.onSelected(viewX + (getWidth() / 2f), viewY + (getHeight() / 2f), this.pos + 1); + } + break; + case MotionEvent.ACTION_CANCEL: + if (allStarsProvider != null) { + RateCallLayout.StarContainer[] starsViews = allStarsProvider.getAllStartsViews(); + for (StarContainer starsView : starsViews) { + RLottieImageView defaultStar = starsView.defaultStar; + RLottieImageView selectedStar = starsView.selectedStar; + defaultStar.animate().alpha(1f).scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + selectedStar.animate().alpha(0f).scaleX(1.0f).scaleY(1.0f).setDuration(250).start(); + } + } + break; + } + return super.dispatchTouchEvent(event); + } + } + + public static class RateCallContainer extends FrameLayout { + + private final TextView titleTextView; + private final TextView messageTextView; + private final VoIPBackgroundProvider backgroundProvider; + private final RectF bgRect = new RectF(); + + public RateCallContainer(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); + setWillNotDraw(false); + titleTextView = new TextView(context); + titleTextView.setTextColor(Color.WHITE); + titleTextView.setText(LocaleController.getString("VoipRateCallTitle", R.string.VoipRateCallTitle)); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + titleTextView.setGravity(Gravity.CENTER_HORIZONTAL); + titleTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + messageTextView = new TextView(context); + messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + messageTextView.setTextColor(Color.WHITE); + messageTextView.setGravity(Gravity.CENTER_HORIZONTAL); + messageTextView.setText(LocaleController.getString("VoipRateCallDescription", R.string.VoipRateCallDescription)); + + addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 0, 24, 0, 0)); + addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 0, 50, 0, 0)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + bgRect.set(0, 0, getWidth(), getHeight()); + backgroundProvider.setDarkTranslation(getX() + ((View) getParent()).getX(), getY() + ((View) getParent()).getY()); + canvas.drawRoundRect(bgRect, dp(28), dp(28), backgroundProvider.getDarkPaint()); + super.dispatchDraw(canvas); + } + } +} 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 new file mode 100644 index 000000000..5cf249533 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPBackgroundProvider.java @@ -0,0 +1,205 @@ +package org.telegram.ui.Components.voip; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.graphics.Canvas; +import android.graphics.Color; +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; +import java.util.List; + +public class VoIPBackgroundProvider { + + public static final float DARK_LIGHT_PERCENT = 0.14f; + public static final int DARK_LIGHT_DEFAULT_ALPHA = (int) (255 * DARK_LIGHT_PERCENT); + public static final int REVEAL_SCALE_FACTOR = 4; + + private final BitmapShaderTools lightShaderTools = new BitmapShaderTools(80, 80); + private final BitmapShaderTools darkShaderTools = new BitmapShaderTools(80, 80); + private BitmapShaderTools revealShaderTools; + private BitmapShaderTools revealDarkShaderTools; + private boolean isReveal; + private int totalWidth = 0; + private int totalHeight = 0; + private int degree; + private boolean hasVideo; + private final Paint whiteVideoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint darkVideoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint darkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final List views = new ArrayList<>(); + public final float scale = 1.12f; + + public VoIPBackgroundProvider() { + darkShaderTools.setBounds(0, 0, 80, 80); + lightShaderTools.setBounds(0, 0, 80, 80); + whiteVideoPaint.setColor(Color.WHITE); + whiteVideoPaint.setAlpha(DARK_LIGHT_DEFAULT_ALPHA); + darkVideoPaint.setColor(Color.BLACK); + darkVideoPaint.setAlpha((int) (255 * 0.4f)); + darkPaint.setColor(Color.BLACK); + darkPaint.setAlpha(DARK_LIGHT_DEFAULT_ALPHA); + darkShaderTools.paint.setAlpha(180); + } + + public void invalidateViews() { + for (View view : views) { + view.invalidate(); + } + } + + public void attach(View view) { + views.add(view); + } + + public void detach(View view) { + views.remove(view); + } + + public void setHasVideo(boolean hasVideo) { + if (this.hasVideo && !hasVideo) { + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1f, 0f); + valueAnimator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + darkPaint.setAlpha((int) (DARK_LIGHT_DEFAULT_ALPHA * val)); + darkVideoPaint.setAlpha((int) ((int) (255 * 0.4f) * val)); + whiteVideoPaint.setAlpha((int) (DARK_LIGHT_DEFAULT_ALPHA * val)); + invalidateViews(); + }); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setDuration(80); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + VoIPBackgroundProvider.this.hasVideo = false; + darkPaint.setAlpha(DARK_LIGHT_DEFAULT_ALPHA); + darkVideoPaint.setAlpha((int) (255 * 0.4f)); + whiteVideoPaint.setAlpha(DARK_LIGHT_DEFAULT_ALPHA); + invalidateViews(); + } + }); + valueAnimator.start(); + ValueAnimator valueAnimator2 = ValueAnimator.ofFloat(0f, 1f); + valueAnimator2.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + darkShaderTools.paint.setAlpha((int) (180 * val)); + lightShaderTools.paint.setAlpha((int) (255 * val)); + invalidateViews(); + }); + valueAnimator2.setInterpolator(new LinearInterpolator()); + valueAnimator2.setStartDelay(80); + valueAnimator2.setDuration(80); + valueAnimator2.start(); + } else { + this.hasVideo = hasVideo; + } + invalidateViews(); + } + + public Canvas getLightCanvas() { + return lightShaderTools.getCanvas(); + } + + public Canvas getRevealCanvas() { + return revealShaderTools.getCanvas(); + } + + public Canvas getRevealDrakCanvas() { + return revealDarkShaderTools.getCanvas(); + } + + public Canvas getDarkCanvas() { + return darkShaderTools.getCanvas(); + } + + public int getTotalWidth() { + return totalWidth; + } + + public void setTotalSize(int totalWidth, int totalHeight) { + this.totalWidth = totalWidth; + this.totalHeight = totalHeight; + this.revealShaderTools = new BitmapShaderTools(totalWidth / REVEAL_SCALE_FACTOR, totalHeight / REVEAL_SCALE_FACTOR); + this.revealDarkShaderTools = new BitmapShaderTools(totalWidth / REVEAL_SCALE_FACTOR, totalHeight / REVEAL_SCALE_FACTOR); + this.revealDarkShaderTools.paint.setAlpha(180); + } + + public int getTotalHeight() { + return totalHeight; + } + + public void setTotalHeight(int totalHeight) { + this.totalHeight = totalHeight; + } + + public int getDegree() { + return degree; + } + + public void setDegree(int degree) { + this.degree = degree; + invalidateViews(); + } + + public void setLightTranslation(float x, float y) { + float finalSize = (float) totalHeight * scale; + float s = finalSize / (float) lightShaderTools.getBitmap().getHeight(); + float dx = (totalHeight * scale - totalWidth) / 2f; + float dy = (totalHeight * scale - totalHeight) / 2f; + lightShaderTools.setMatrix(-x - dx, -y - dy, s, degree); + revealShaderTools.setBounds(-x, -y, totalWidth - x, totalHeight - y); + } + + public void setDarkTranslation(float x, float y) { + float finalSize = (float) totalHeight * scale; + float s = finalSize / (float) darkShaderTools.getBitmap().getHeight(); + float dx = (finalSize - totalWidth) / 2f; + float dy = (finalSize - totalHeight) / 2f; + darkShaderTools.setMatrix(-x - dx, -y - dy, s, degree); + revealDarkShaderTools.setBounds(-x, -y, totalWidth - x, totalHeight - y); + } + + public boolean isReveal() { + return isReveal; + } + + public void setReveal(boolean clipping) { + isReveal = clipping; + } + + public Paint getRevealPaint() { + return revealShaderTools.paint; + } + + public Paint getRevealDarkPaint() { + return revealDarkShaderTools.paint; + } + + public Paint getLightPaint() { + if (hasVideo) { + return whiteVideoPaint; + } + return lightShaderTools.paint; + } + + public Paint getDarkPaint() { + if (hasVideo) { + return darkVideoPaint; + } + return darkShaderTools.paint; + } + + public Paint getDarkPaint(boolean ignoreShader) { + if (ignoreShader) { + return darkPaint; + } + return getDarkPaint(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPEllipsizeSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPEllipsizeSpan.java new file mode 100644 index 000000000..a3ed2e702 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPEllipsizeSpan.java @@ -0,0 +1,54 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.SystemClock; +import android.text.style.ReplacementSpan; +import android.view.View; + +import org.telegram.ui.Components.CubicBezierInterpolator; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class VoIPEllipsizeSpan extends ReplacementSpan { + + private final CubicBezierInterpolator interpolator = new CubicBezierInterpolator(0.33, 0.00, 0.67, 1.00); + + private final View[] parents; + + public VoIPEllipsizeSpan(View... parents) { + this.parents = parents; + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return dp(20); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + canvas.save(); + canvas.translate(x + dp(4), y / 2f); + long time = SystemClock.uptimeMillis() % 250 + 500; + for (int i = 0; i < 3; i++) { + long pointTime = (time + i * 250L) % 750; + float moveFraction = Math.min(1, pointTime / 667f); + float scale; + if (moveFraction <= 0.425f) { + scale = interpolator.getInterpolation(moveFraction / 0.425f); + } else { + scale = 1f - interpolator.getInterpolation((moveFraction - 0.425f) / 0.575f); + } + moveFraction = interpolator.getInterpolation(moveFraction); + canvas.drawCircle(dpf2(1.667f + moveFraction * 16f), dp(3), dpf2(2 * scale), paint); + } + canvas.restore(); + for (View parent : parents) { + parent.invalidate(); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPFloatingLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPFloatingLayout.java index 8825892d1..f264bd640 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPFloatingLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPFloatingLayout.java @@ -78,6 +78,7 @@ public class VoIPFloatingLayout extends FrameLayout { public float updatePositionFromX; public float updatePositionFromY; public boolean switchingToPip; + public boolean isAppearing; Drawable outerShadow; ValueAnimator switchToFloatingModeAnimator; @@ -266,12 +267,16 @@ public class VoIPFloatingLayout extends FrameLayout { protected void dispatchDraw(Canvas canvas) { boolean animated = false; if (updatePositionFromX >= 0) { - animate().setListener(null).cancel(); + if(!isAppearing) { + animate().setListener(null).cancel(); + } setTranslationX(updatePositionFromX); setTranslationY(updatePositionFromY); - setScaleX(1f); - setScaleY(1f); - setAlpha(1f); + if(!isAppearing) { + setScaleX(1f); + setScaleY(1f); + setAlpha(1f); + } updatePositionFromX = -1f; updatePositionFromY = -1f; } @@ -359,7 +364,7 @@ public class VoIPFloatingLayout extends FrameLayout { .translationX(xPoint) .translationY(yPoint) .alpha(1f) - .setStartDelay(0) + .setStartDelay(uiVisible ? 0 : 150) .setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } else { if (!alwaysFloating) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java index 9f5e1ee90..bdb2fad73 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java @@ -394,6 +394,23 @@ public class VoIPHelper { return false; } + public static void sendCallRating(final long callID, final long accessHash, final int account, int rating) { + final int currentAccount = UserConfig.selectedAccount; + final TLRPC.TL_phone_setCallRating req = new TLRPC.TL_phone_setCallRating(); + req.rating = rating; + req.comment = ""; + req.peer = new TLRPC.TL_inputPhoneCall(); + req.peer.access_hash = accessHash; + req.peer.id = callID; + req.user_initiative = false; + ConnectionsManager.getInstance(account).sendRequest(req, (response, error) -> { + if (response instanceof TLRPC.TL_updates) { + TLRPC.TL_updates updates = (TLRPC.TL_updates) response; + MessagesController.getInstance(currentAccount).processUpdates(updates, false); + } + }); + } + public static void showRateAlert(Context context, TLRPC.TL_messageActionPhoneCall call) { SharedPreferences prefs = MessagesController.getNotificationsSettings(UserConfig.selectedAccount); // always called from chat UI Set hashes = prefs.getStringSet("calls_access_hashes", (Set) Collections.EMPTY_SET); 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 d34b13d07..caee01690 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 @@ -1,11 +1,19 @@ package org.telegram.ui.Components.voip; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Color; -import android.os.Build; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; import android.transition.ChangeBounds; import android.transition.Fade; import android.transition.TransitionManager; @@ -23,16 +31,16 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; -import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.StaticLayoutEx; import java.util.ArrayList; import java.util.HashMap; +@SuppressLint("ViewConstructor") public class VoIPNotificationsLayout extends LinearLayout { HashMap viewsByTag = new HashMap<>(); @@ -42,32 +50,49 @@ public class VoIPNotificationsLayout extends LinearLayout { boolean lockAnimation; boolean wasChanged; Runnable onViewsUpdated; + VoIPBackgroundProvider backgroundProvider; + TextPaint textPaint = new TextPaint(); - public VoIPNotificationsLayout(Context context) { + public VoIPNotificationsLayout(Context context, VoIPBackgroundProvider backgroundProvider) { super(context); setOrientation(VERTICAL); + this.backgroundProvider = backgroundProvider; + transitionSet = new TransitionSet(); + transitionSet.addTransition(new Fade(Fade.OUT).setDuration(150)) + .addTransition(new ChangeBounds().setDuration(200)) + .addTransition(new Visibility() { + @Override + public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + AnimatorSet set = new AnimatorSet(); + view.setAlpha(0); + view.setScaleY(0.6f); + view.setScaleX(0.6f); + set.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1f), + ObjectAnimator.ofFloat(view, View.SCALE_X, 0.6f, 1f), + ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.6f, 1f) + ); + set.setInterpolator(CubicBezierInterpolator.EASE_OUT_BACK); + return set; + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - transitionSet = new TransitionSet(); - transitionSet.addTransition(new Fade(Fade.OUT).setDuration(150)) - .addTransition(new ChangeBounds().setDuration(200)) - .addTransition(new Visibility() { - @Override - public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { - AnimatorSet set = new AnimatorSet(); - view.setAlpha(0); - set.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1f), - ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, view.getMeasuredHeight(), 0) - ); - - set.setInterpolator(CubicBezierInterpolator.DEFAULT); - - return set; + @Override + public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + AnimatorSet set = new AnimatorSet(); + if (view instanceof NotificationView) { + ((NotificationView) view).ignoreShader = true; } - }.setDuration(200)); - transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); - } + set.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, 0.7f, 0f), + ObjectAnimator.ofFloat(view, View.SCALE_X, 1f, 0.6f), + ObjectAnimator.ofFloat(view, View.SCALE_Y, 1f, 0.6f) + ); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + return set; + } + }.setDuration(200)); + transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); + textPaint.setTextSize(dp(14)); } public void addNotification(int iconRes, String text, String tag, boolean animated) { @@ -75,15 +100,13 @@ public class VoIPNotificationsLayout extends LinearLayout { return; } - NotificationView view = new NotificationView(getContext()); + NotificationView view = new NotificationView(getContext(), backgroundProvider, iconRes); view.tag = tag; + view.setText(text); view.iconView.setImageResource(iconRes); - view.textView.setText(text); + viewsByTag.put(tag, view); - if (animated) { - view.startAnimation(); - } if (lockAnimation) { viewToAdd.add(view); } else { @@ -92,8 +115,16 @@ public class VoIPNotificationsLayout extends LinearLayout { } } + public CharSequence ellipsize(CharSequence text) { + if (text == null) { + return ""; + } + return TextUtils.ellipsize(text, textPaint, dp(300), TextUtils.TruncateAt.END); + } + public void removeNotification(String tag) { NotificationView view = viewsByTag.remove(tag); + backgroundProvider.detach(view); if (view != null) { if (lockAnimation) { if (viewToAdd.remove(view)) { @@ -119,11 +150,9 @@ public class VoIPNotificationsLayout extends LinearLayout { if (viewToAdd.isEmpty() && viewToRemove.isEmpty()) { return; } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - ViewParent parent = getParent(); - if (parent != null) { - TransitionManager.beginDelayedTransition(this, transitionSet); - } + ViewParent parent = getParent(); + if (parent != null) { + TransitionManager.beginDelayedTransition(this, transitionSet); } for (int i = 0; i < viewToAdd.size(); i++) { @@ -160,11 +189,9 @@ public class VoIPNotificationsLayout extends LinearLayout { public void beforeLayoutChanges() { wasChanged = false; if (!lockAnimation) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - ViewParent parent = getParent(); - if (parent != null) { - TransitionManager.beginDelayedTransition(this, transitionSet); - } + ViewParent parent = getParent(); + if (parent != null) { + TransitionManager.beginDelayedTransition(this, transitionSet); } } } @@ -186,37 +213,58 @@ public class VoIPNotificationsLayout extends LinearLayout { public String tag; ImageView iconView; TextView textView; + boolean ignoreShader; + private final VoIPBackgroundProvider backgroundProvider; + private final RectF bgRect = new RectF(); - public NotificationView(@NonNull Context context) { + public NotificationView(@NonNull Context context, VoIPBackgroundProvider backgroundProvider, int iconRes) { super(context); setFocusable(true); setFocusableInTouchMode(true); - + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); iconView = new ImageView(context); - setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(16), ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.4f)))); - addView(iconView, LayoutHelper.createFrame(24, 24, 0, 10, 4, 10, 4)); + addView(iconView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL, 10, 2, 10, 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, 44, 4, 16, 4)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, iconRes == 0 ? 14 : 42, 2, 14, 2)); + } + + public void setText(CharSequence text) { + int maxWidth = AndroidUtilities.displaySize.x - dp(120); + StaticLayout staticLayout = StaticLayoutEx.createStaticLayout(text, textView.getPaint(), + maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, + false, TextUtils.TruncateAt.END, maxWidth, 10); + int maxRowLength = 0; + for (int a = 0; a < staticLayout.getLineCount(); ++a) { + maxRowLength = (int) Math.max(maxRowLength, Math.ceil(staticLayout.getLineWidth(a))); + } + textView.setMaxWidth(maxRowLength); + textView.setText(text); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + bgRect.set(0, 0, getWidth(), getHeight()); + backgroundProvider.setDarkTranslation(getX() + ((View) getParent()).getX(), getY() + ((View) getParent()).getY()); + canvas.drawRoundRect(bgRect, dp(16), dp(16), backgroundProvider.getDarkPaint(ignoreShader)); + super.dispatchDraw(canvas); } public void startAnimation() { - textView.setVisibility(View.GONE); + textView.setVisibility(View.INVISIBLE); postDelayed(() -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - TransitionSet transitionSet = new TransitionSet(); - transitionSet. - addTransition(new Fade(Fade.IN).setDuration(150)) - .addTransition(new ChangeBounds().setDuration(200)); - transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); - ViewParent parent = getParent(); - if (parent != null) { - TransitionManager.beginDelayedTransition((ViewGroup) parent, transitionSet); - } + TransitionSet transitionSet = new TransitionSet(); + transitionSet. + addTransition(new Fade(Fade.IN).setDuration(150)) + .addTransition(new ChangeBounds().setDuration(200)); + transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); + ViewParent parent = getParent(); + if (parent != null) { + TransitionManager.beginDelayedTransition((ViewGroup) parent, transitionSet); } - textView.setVisibility(View.VISIBLE); }, 400); } 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 2f7dde5ab..e7a2d062e 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 @@ -1,16 +1,19 @@ package org.telegram.ui.Components.voip; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.RectF; import android.text.SpannableString; import android.text.SpannableStringBuilder; -import android.text.TextPaint; +import android.text.Spanned; import android.text.TextUtils; -import android.text.style.CharacterStyle; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -23,29 +26,29 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.Components.CubicBezierInterpolator; -import org.telegram.ui.Components.EllipsizeSpanAnimator; import org.telegram.ui.Components.LayoutHelper; -import java.util.ArrayList; - +@SuppressLint("ViewConstructor") public class VoIPStatusTextView extends FrameLayout { TextView[] textView = new TextView[2]; TextView reconnectTextView; + TextView badConnectionTextView; + FrameLayout badConnectionLayer; VoIPTimerView timerView; CharSequence nextTextToSet; boolean animationInProgress; - private boolean attachedToWindow; - ValueAnimator animator; boolean timerShowing; - EllipsizeSpanAnimator ellipsizeAnimator; + VoIPBackgroundProvider backgroundProvider; - public VoIPStatusTextView(@NonNull Context context) { + public VoIPStatusTextView(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { super(context); + this.backgroundProvider = backgroundProvider; + for (int i = 0; i < 2; i++) { textView[i] = new TextView(context); textView[i].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); @@ -55,6 +58,34 @@ public class VoIPStatusTextView extends FrameLayout { addView(textView[i]); } + badConnectionLayer = new FrameLayout(context); + badConnectionTextView = new TextView(context) { + + private final RectF bgRect = new RectF(); + + { + backgroundProvider.attach(this); + } + + @Override + protected void onDraw(Canvas canvas) { + bgRect.set(0, 0, getWidth(), getHeight()); + float x = getX() + ((View) getParent()).getX() + VoIPStatusTextView.this.getX() + ((View) VoIPStatusTextView.this.getParent()).getX(); + float y = getY() + ((View) getParent()).getY() + VoIPStatusTextView.this.getY() + ((View) VoIPStatusTextView.this.getParent()).getY(); + backgroundProvider.setDarkTranslation(x, y); + canvas.drawRoundRect(bgRect, dp(16), dp(16), backgroundProvider.getDarkPaint()); + super.onDraw(canvas); + } + }; + badConnectionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + badConnectionTextView.setTextColor(Color.WHITE); + badConnectionTextView.setGravity(Gravity.CENTER_HORIZONTAL); + badConnectionTextView.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(2), AndroidUtilities.dp(12), AndroidUtilities.dp(2)); + badConnectionTextView.setText(LocaleController.getString("VoipWeakNetwork", R.string.VoipWeakNetwork)); + badConnectionLayer.addView(badConnectionTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + badConnectionLayer.setVisibility(View.GONE); + addView(badConnectionLayer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 44, 0, 0)); + reconnectTextView = new TextView(context); reconnectTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); reconnectTextView.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000); @@ -62,34 +93,25 @@ public class VoIPStatusTextView extends FrameLayout { reconnectTextView.setGravity(Gravity.CENTER_HORIZONTAL); addView(reconnectTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 22, 0, 0)); - ellipsizeAnimator = new EllipsizeSpanAnimator(this); SpannableStringBuilder ssb = new SpannableStringBuilder(LocaleController.getString("VoipReconnecting", R.string.VoipReconnecting)); - SpannableString ell = new SpannableString("..."); - ellipsizeAnimator.wrap(ell, 0); + SpannableString ell = new SpannableString("."); + ell.setSpan(new VoIPEllipsizeSpan(reconnectTextView), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append(ell); reconnectTextView.setText(ssb); reconnectTextView.setVisibility(View.GONE); timerView = new VoIPTimerView(context); addView(timerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - } public void setText(String text, boolean ellipsis, boolean animated) { CharSequence nextString = text; if (ellipsis) { SpannableStringBuilder ssb = new SpannableStringBuilder(text); - ellipsizeAnimator.reset(); - SpannableString ell = new SpannableString("..."); - ellipsizeAnimator.wrap(ell, 0); + SpannableString ell = new SpannableString("."); + ell.setSpan(new VoIPEllipsizeSpan(textView), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append(ell); nextString = ssb; - - ellipsizeAnimator.addView(textView[0]); - ellipsizeAnimator.addView(textView[1]); - } else { - ellipsizeAnimator.removeView(textView[0]); - ellipsizeAnimator.removeView(textView[1]); } if (TextUtils.isEmpty(textView[0].getText())) { @@ -153,9 +175,6 @@ public class VoIPStatusTextView extends FrameLayout { timerShowing = true; replaceViews(textView[0], timerView, null); } - - ellipsizeAnimator.removeView(textView[0]); - ellipsizeAnimator.removeView(textView[1]); } @@ -169,17 +188,10 @@ public class VoIPStatusTextView extends FrameLayout { animator = ValueAnimator.ofFloat(0, 1f); animator.addUpdateListener(valueAnimator -> { float v = (float) valueAnimator.getAnimatedValue(); - float inScale = 0.4f + 0.6f * v; - float outScale = 0.4f + 0.6f * (1f - v); - in.setTranslationY(AndroidUtilities.dp(10) * (1f - v)); + in.setTranslationY(AndroidUtilities.dp(8) * (1f - v)); in.setAlpha(v); - in.setScaleX(inScale); - in.setScaleY(inScale); - - out.setTranslationY(-AndroidUtilities.dp(10) * v); + out.setTranslationY(-AndroidUtilities.dp(6) * v); out.setAlpha(1f - v); - out.setScaleX(outScale); - out.setScaleY(outScale); }); animator.addListener(new AnimatorListenerAdapter() { @Override @@ -244,26 +256,40 @@ public class VoIPStatusTextView extends FrameLayout { }).setDuration(150).start(); } } + } - if (showReconnecting) { - ellipsizeAnimator.addView(reconnectTextView); + public void showBadConnection(boolean showBadConnection, boolean animated) { + if (!animated) { + badConnectionLayer.animate().setListener(null).cancel(); + badConnectionLayer.setVisibility(showBadConnection ? View.VISIBLE : View.GONE); } else { - ellipsizeAnimator.removeView(reconnectTextView); + if (showBadConnection) { + if (badConnectionLayer.getVisibility() == View.VISIBLE) { + return; + } + badConnectionLayer.setVisibility(View.VISIBLE); + badConnectionLayer.setAlpha(0f); + badConnectionLayer.setScaleY(0.6f); + badConnectionLayer.setScaleX(0.6f); + badConnectionLayer.animate().setListener(null).cancel(); + badConnectionLayer.animate().alpha(1f).scaleX(1f).scaleY(1f) + .setInterpolator(CubicBezierInterpolator.EASE_OUT_BACK) + .setDuration(300).start(); + } else { + if (badConnectionLayer.getVisibility() == View.GONE) { + return; + } + badConnectionLayer.animate().alpha(0f).scaleX(0.6f).scaleY(0.6f).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + badConnectionLayer.setVisibility(View.GONE); + } + }).setDuration(300).start(); + } } } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - attachedToWindow = true; - ellipsizeAnimator.onAttachedToWindow(); + public void setDrawCallIcon() { + timerView.setDrawCallIcon(); } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - attachedToWindow = false; - ellipsizeAnimator.onDetachedFromWindow(); - } - } 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 7b63a6dcf..7b55ea576 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 @@ -5,14 +5,17 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.view.View; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; import org.telegram.messenger.voip.VoIPService; public class VoIPTimerView extends View { @@ -24,6 +27,8 @@ public class VoIPTimerView extends View { String currentTimeStr; TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); private int signalBarCount = 4; + private boolean isDrawCallIcon = false; + private final Drawable callsDeclineDrawable; Runnable updater = () -> { if (getVisibility() == View.VISIBLE) { @@ -38,6 +43,8 @@ public class VoIPTimerView extends View { 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); + callsDeclineDrawable.setBounds(0, 0, AndroidUtilities.dp(24), AndroidUtilities.dp(24)); } @Override @@ -92,11 +99,16 @@ public class VoIPTimerView extends View { canvas.save(); canvas.translate((getMeasuredWidth() - totalWidth) / 2f, 0); canvas.save(); - canvas.translate(0, (getMeasuredHeight() - AndroidUtilities.dp(11)) / 2f); - for (int i = 0; i < 4; i++) { - Paint p = i + 1 > signalBarCount ? inactivePaint : activePaint; - rectF.set(AndroidUtilities.dpf2(4.16f) * i, AndroidUtilities.dpf2(2.75f) * (3 - i), AndroidUtilities.dpf2(4.16f) * i + AndroidUtilities.dpf2(2.75f), AndroidUtilities.dp(11)); - canvas.drawRoundRect(rectF, AndroidUtilities.dpf2(0.7f), AndroidUtilities.dpf2(0.7f), p); + if (isDrawCallIcon) { + canvas.translate(-AndroidUtilities.dp(7), -AndroidUtilities.dp(3)); + callsDeclineDrawable.draw(canvas); + } else { + canvas.translate(0, (getMeasuredHeight() - AndroidUtilities.dp(11)) / 2f); + for (int i = 0; i < 4; i++) { + Paint p = i + 1 > signalBarCount ? inactivePaint : activePaint; + rectF.set(AndroidUtilities.dpf2(4.16f) * i, AndroidUtilities.dpf2(2.75f) * (3 - i), AndroidUtilities.dpf2(4.16f) * i + AndroidUtilities.dpf2(2.75f), AndroidUtilities.dp(11)); + canvas.drawRoundRect(rectF, AndroidUtilities.dpf2(0.7f), AndroidUtilities.dpf2(0.7f), p); + } } canvas.restore(); @@ -111,4 +123,9 @@ public class VoIPTimerView extends View { signalBarCount = count; invalidate(); } + + public void setDrawCallIcon() { + isDrawCallIcon = true; + invalidate(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java index 7cf8598bf..1228014d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java @@ -76,6 +76,8 @@ public class VoIPToggleButton extends FrameLayout { private float radius; private ValueAnimator checkAnimator; + private ValueAnimator pressedScaleAnimator; + private float pressedScale = 1.0f; private RLottieImageView lottieImageView; @@ -96,7 +98,7 @@ public class VoIPToggleButton extends FrameLayout { textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); textView.setTextColor(Color.WHITE); textView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - textLayoutContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, radius + 4, 0, 0)); + textLayoutContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, radius + 6, 0, 0)); this.textView[i] = textView; } textView[1].setVisibility(View.GONE); @@ -122,9 +124,25 @@ public class VoIPToggleButton extends FrameLayout { drawBackground = value; } + public 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(); + } + @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.scale(pressedScale, pressedScale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + if (animateBackground && replaceProgress != 0) { circlePaint.setColor(ColorUtils.blendARGB(backgroundColor, animateToBackgroundColor, replaceProgress)); } else { @@ -229,6 +247,7 @@ public class VoIPToggleButton extends FrameLayout { } } } + canvas.restore(); } public void setBackgroundColor(int backgroundColor, int backgroundColorChecked) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java index e5779637b..1aeccf27f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java @@ -84,24 +84,24 @@ public class VoIPWindowView extends FrameLayout { } else if (event.getAction() == MotionEvent.ACTION_MOVE) { float dx = event.getX() - startX; float dy = event.getY() - startY; - if (!startDragging && Math.abs(dx) > AndroidUtilities.getPixelsInCM(0.4f, true) && Math.abs(dx) / 3 > dy) { - startX = event.getX(); - dx = 0; + if (!startDragging && Math.abs(dy) > AndroidUtilities.getPixelsInCM(0.4f, true) && Math.abs(dy) / 3 > dx) { + startY = event.getY(); + dy = 0; startDragging = true; } if (startDragging) { - if (dx < 0) { - dx = 0; + if (dy < 0) { + dy = 0; } if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); - setTranslationX(dx); + setTranslationY(dy); } return startDragging; } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { - float x = getTranslationX(); + float y = getTranslationY(); if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } @@ -110,12 +110,12 @@ public class VoIPWindowView extends FrameLayout { float velX = velocityTracker.getXVelocity(); float velY = velocityTracker.getYVelocity(); - final boolean backAnimation = x < getMeasuredWidth() / 3.0f && (velX < 3500 || velX < velY); + final boolean backAnimation = y < getMeasuredHeight() / 3.0f && (velX < 3500 || velX < velY); if (!backAnimation) { - float distToMove = getMeasuredWidth() - getTranslationX(); - finish(Math.max((int) (200.0f / getMeasuredWidth() * distToMove), 50)); + float distToMove = getMeasuredHeight() - getTranslationY(); + finish(Math.max((int) (200.0f / getMeasuredHeight() * distToMove), 50)); } else { - animate().translationX(0).start(); + animate().translationY(0).start(); } startDragging = false; } @@ -123,7 +123,7 @@ public class VoIPWindowView extends FrameLayout { } public void finish() { - finish(150); + finish(330); } public void finish(long animDuration) { @@ -141,7 +141,7 @@ public class VoIPWindowView extends FrameLayout { } else { int account = UserConfig.selectedAccount; notificationsLocker.lock(); - animate().translationX(getMeasuredWidth()).setListener(new AnimatorListenerAdapter() { + animate().translationY(getMeasuredHeight()).alpha(0f).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { notificationsLocker.unlock(); @@ -166,8 +166,9 @@ public class VoIPWindowView extends FrameLayout { public void startEnterTransition() { if (!lockOnScreen) { - setTranslationX(getMeasuredWidth()); - animate().translationX(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + setTranslationY(getMeasuredHeight()); + setAlpha(0f); + animate().translationY(0).alpha(1f).setDuration(330).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpBitmapTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpBitmapTextView.java new file mode 100644 index 000000000..e569d15fa --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpBitmapTextView.java @@ -0,0 +1,70 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.text.TextPaint; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; + +/** + * Fixed ANR on Samsung after one and a half minutes. + * Anr occurs due to drawing long text. + */ +@SuppressLint("ViewConstructor") +public class VoIpBitmapTextView extends View { + + private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final float textWidth; + private final String text; + private volatile Bitmap bitmap; + + public VoIpBitmapTextView(Context context, String text) { + super(context); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setTextSize(dp(13)); + textPaint.setColor(Color.WHITE); + textPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textWidth = textPaint.measureText(text); + this.text = text; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec((int) textWidth + getPaddingLeft() + getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY) + ); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + Utilities.globalQueue.postRunnable(() -> { + bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + int xPos = (getMeasuredWidth() / 2); + int yPos = (int) ((getMeasuredHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)); + canvas.drawText(text, xPos, yPos, textPaint); + postInvalidate(); + }); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (bitmap != null) { + canvas.drawBitmap(bitmap, 0, 0, paint); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpGradientLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpGradientLayout.java new file mode 100644 index 000000000..0dd78bb05 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpGradientLayout.java @@ -0,0 +1,402 @@ +package org.telegram.ui.Components.voip; + +import static org.telegram.ui.Components.voip.VoIPBackgroundProvider.REVEAL_SCALE_FACTOR; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LiteMode; +import org.telegram.ui.Components.MotionBackgroundDrawable; + +@SuppressLint("ViewConstructor") +public class VoIpGradientLayout extends FrameLayout { + + public enum GradientState { + CALLING, + CONNECTED, + BAD_CONNECTION + } + + private final MotionBackgroundDrawable bgBlueViolet; + private final MotionBackgroundDrawable bgBlueGreen; + private final MotionBackgroundDrawable bgGreen; + private final MotionBackgroundDrawable bgOrangeRed; + + private final MotionBackgroundDrawable bgBlueVioletDark; + private final MotionBackgroundDrawable bgBlueGreenDark; + private final MotionBackgroundDrawable bgGreenDark; + private final MotionBackgroundDrawable bgOrangeRedDark; + + private final MotionBackgroundDrawable bgBlueVioletLight; + private final MotionBackgroundDrawable bgBlueGreenLight; + private final MotionBackgroundDrawable bgGreenLight; + private final MotionBackgroundDrawable bgOrangeRedLight; + private final MotionBackgroundDrawable bgGreenLightReveal; + private final MotionBackgroundDrawable bgGreenDarkReveal; + + private int alphaBlueViolet = 0; + private int alphaBlueGreen = 0; + private int alphaGreen = 0; + private int alphaOrangeRed = 0; + private float clipRadius = 0f; + private boolean showClip = false; + private final Path clipPath = new Path(); + private int clipCx = 0; + private int clipCy = 0; + private ValueAnimator callingAnimator; + private ValueAnimator badConnectionAnimator; + private AnimatorSet connectedAnimatorSet; + private final AnimatorSet defaultAnimatorSet; + private GradientState state; + private boolean isPaused = false; + public volatile boolean lockDrawing = false; + private final VoIPBackgroundProvider backgroundProvider; + private boolean allowAnimations; + + public VoIpGradientLayout(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + allowAnimations = LiteMode.isEnabled(LiteMode.FLAG_CALLS_ANIMATIONS); + bgBlueViolet = new MotionBackgroundDrawable(0xFFB456D8, 0xFF8148EC, 0xFF20A4D7, 0xFF3F8BEA, 0, false, true); + bgBlueGreen = new MotionBackgroundDrawable(0xFF4576E9, 0xFF3B7AF1, 0xFF08B0A3, 0xFF17AAE4, 0, false, true); + bgGreen = new MotionBackgroundDrawable(0xFF07A9AC, 0xFF07BA63, 0xFFA9CC66, 0xFF5AB147, 0, false, true); + bgOrangeRed = new MotionBackgroundDrawable(0xFFE86958, 0xFFE7618F, 0xFFDB904C, 0xFFDE7238, 0, false, true); + + bgBlueVioletDark = new MotionBackgroundDrawable(0xFFA736D0, 0xFF6A2BDD, 0xFF0F95C9, 0xFF287AE1, 0, false, true); + bgBlueGreenDark = new MotionBackgroundDrawable(0xFF2D60D6, 0xFF2C6ADF, 0xFF009595, 0xFF0291C9, 0, false, true); + bgGreenDark = new MotionBackgroundDrawable(0xFF008B8E, 0xFF01934C, 0xFF8FBD37, 0xFF319D27, 0, false, true); + bgOrangeRedDark = new MotionBackgroundDrawable(0xFFE23F29, 0xFFE6306F, 0xFFC77616, 0xFFD75A16, 0, false, true); + + bgBlueVioletLight = new MotionBackgroundDrawable(0xFFD664FF, 0xFF9258FD, 0xFF2DC0F9, 0xFF57A1FF, 0, false, true); + bgBlueGreenLight = new MotionBackgroundDrawable(0xFF558BFF, 0xFF5FABFF, 0xFF04DCCC, 0xFF28C2FF, 0, false, true); + bgGreenLight = new MotionBackgroundDrawable(0xFF00D2D5, 0xFF09E279, 0xFFC7EF60, 0xFF6DD957, 0, false, true); + bgOrangeRedLight = new MotionBackgroundDrawable(0xFFFF7866, 0xFFFF82A5, 0xFFFEB055, 0xFFFF8E51, 0, false, true); + bgGreenLightReveal = new MotionBackgroundDrawable(0xFF00D2D5, 0xFF09E279, 0xFFC7EF60, 0xFF6DD957, 0, false, true); + bgGreenDarkReveal = new MotionBackgroundDrawable(0xFF008B8E, 0xFF01934C, 0xFF8FBD37, 0xFF319D27, 0, false, true); + + bgBlueVioletDark.setBounds(0, 0, 80, 80); + bgBlueGreenDark.setBounds(0, 0, 80, 80); + bgGreenDark.setBounds(0, 0, 80, 80); + bgOrangeRedDark.setBounds(0, 0, 80, 80); + + bgBlueVioletLight.setBounds(0, 0, 80, 80); + bgBlueGreenLight.setBounds(0, 0, 80, 80); + bgGreenLight.setBounds(0, 0, 80, 80); + bgOrangeRedLight.setBounds(0, 0, 80, 80); + + setWillNotDraw(false); + setLayerType(View.LAYER_TYPE_HARDWARE, null); + + defaultAnimatorSet = new AnimatorSet(); + ValueAnimator rotationAnimator = ValueAnimator.ofInt(0, 360); + rotationAnimator.addUpdateListener(animation -> { + backgroundProvider.setDegree((int) animation.getAnimatedValue()); + int degree = backgroundProvider.getDegree(); + if ((degree >= 0 && degree <= 2) || (degree >= 180 && degree <= 182)) { + if (isPaused) { + defaultAnimatorSet.pause(); + if (connectedAnimatorSet != null) { + connectedAnimatorSet.pause(); + } + } + } + }); + rotationAnimator.setRepeatCount(ValueAnimator.INFINITE); + rotationAnimator.setRepeatMode(ValueAnimator.RESTART); + defaultAnimatorSet.setInterpolator(new LinearInterpolator()); + defaultAnimatorSet.playTogether(rotationAnimator); + defaultAnimatorSet.setDuration(12000); + if (allowAnimations) { + defaultAnimatorSet.start(); + } + switchToCalling(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (defaultAnimatorSet != null) { + defaultAnimatorSet.cancel(); + } + if (connectedAnimatorSet != null) { + connectedAnimatorSet.cancel(); + } + if (callingAnimator != null) { + callingAnimator.cancel(); + } + } + + public void switchToCalling() { + if (state == GradientState.CALLING) { + return; + } + state = GradientState.CALLING; + alphaBlueGreen = 255; + callingAnimator = ValueAnimator.ofInt(255, 0, 255); + callingAnimator.addUpdateListener(animation -> { + alphaBlueViolet = (int) animation.getAnimatedValue(); + invalidate(); + }); + callingAnimator.setRepeatCount(ValueAnimator.INFINITE); + callingAnimator.setRepeatMode(ValueAnimator.RESTART); + callingAnimator.setInterpolator(new LinearInterpolator()); + callingAnimator.setDuration(12000); + if (allowAnimations) { + callingAnimator.start(); + } + } + + public boolean isConnectedCalled() { + return state == GradientState.CONNECTED || state == GradientState.BAD_CONNECTION; + } + + public void switchToCallConnected(int x, int y) { + switchToCallConnected(x, y, true); + } + + public void switchToCallConnected(int x, int y, boolean animated) { + if (state == GradientState.CONNECTED || state == GradientState.BAD_CONNECTION) { + return; + } + state = GradientState.CONNECTED; + if (callingAnimator != null) { + callingAnimator.removeAllUpdateListeners(); + callingAnimator.cancel(); + callingAnimator = null; + } + clipCx = x; + clipCy = y; + int w = AndroidUtilities.displaySize.x; + int h = AndroidUtilities.displaySize.y + AndroidUtilities.statusBarHeight + AndroidUtilities.navigationBarHeight; + double d1 = Math.sqrt((w - x) * (w - x) + (h - y) * (h - y)); + double d2 = Math.sqrt(x * x + (h - y) * (h - y)); + double d3 = Math.sqrt(x * x + y * y); + double d4 = Math.sqrt((w - x) * (w - x) + y * y); + double revealMaxRadius = Math.max(Math.max(Math.max(d1, d2), d3), d4); + + showClip = true; + backgroundProvider.setReveal(true); + ValueAnimator revealAnimator = ValueAnimator.ofFloat(0f, (float) revealMaxRadius); + revealAnimator.addUpdateListener(animation -> { + clipRadius = (float) animation.getAnimatedValue(); + invalidate(); + backgroundProvider.invalidateViews(); + }); + revealAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + showClip = false; + backgroundProvider.setReveal(false); + if (allowAnimations) { + if (defaultAnimatorSet != null) { + defaultAnimatorSet.cancel(); + defaultAnimatorSet.start(); + } + } + switchToConnectedAnimator(); + } + }); + revealAnimator.setDuration(animated ? 400 : 0); + revealAnimator.start(); + } + + private void switchToConnectedAnimator() { + if (connectedAnimatorSet != null) { + return; + } + if (callingAnimator != null) { + callingAnimator.removeAllUpdateListeners(); + callingAnimator.cancel(); + callingAnimator = null; + } + alphaGreen = 255; + connectedAnimatorSet = new AnimatorSet(); + ValueAnimator blueGreenAnimator = ValueAnimator.ofInt(0, 255, 255, 255, 0); + blueGreenAnimator.addUpdateListener(animation2 -> { + alphaBlueGreen = (int) animation2.getAnimatedValue(); + invalidate(); + }); + blueGreenAnimator.setRepeatCount(ValueAnimator.INFINITE); + blueGreenAnimator.setRepeatMode(ValueAnimator.RESTART); + + ValueAnimator blueVioletAnimator = ValueAnimator.ofInt(0, 0, 255, 0, 0); + blueVioletAnimator.addUpdateListener(animation2 -> { + alphaBlueViolet = (int) animation2.getAnimatedValue(); + invalidate(); + }); + blueVioletAnimator.setRepeatCount(ValueAnimator.INFINITE); + blueVioletAnimator.setRepeatMode(ValueAnimator.RESTART); + + connectedAnimatorSet.playTogether(blueVioletAnimator, blueGreenAnimator); + connectedAnimatorSet.setInterpolator(new LinearInterpolator()); + connectedAnimatorSet.setDuration(24000); + if (allowAnimations) { + connectedAnimatorSet.start(); + } else { + alphaBlueGreen = 0; + alphaBlueViolet = 0; + } + invalidate(); + } + + public void showToBadConnection() { + if (state == GradientState.BAD_CONNECTION) { + return; + } + state = GradientState.BAD_CONNECTION; + badConnectionAnimator = ValueAnimator.ofInt(alphaOrangeRed, 255); + badConnectionAnimator.addUpdateListener(animation -> { + alphaOrangeRed = (int) animation.getAnimatedValue(); + invalidate(); + backgroundProvider.invalidateViews(); + }); + badConnectionAnimator.setDuration(500); + badConnectionAnimator.start(); + } + + public void hideBadConnection() { + if (state == GradientState.CONNECTED) { + return; + } + state = GradientState.CONNECTED; + switchToConnectedAnimator(); + if (badConnectionAnimator != null) { + badConnectionAnimator.removeAllUpdateListeners(); + badConnectionAnimator.cancel(); + } + badConnectionAnimator = ValueAnimator.ofInt(alphaOrangeRed, 0); + badConnectionAnimator.addUpdateListener(animation -> { + alphaOrangeRed = (int) animation.getAnimatedValue(); + invalidate(); + backgroundProvider.invalidateViews(); + }); + badConnectionAnimator.setDuration(500); + badConnectionAnimator.start(); + } + + public void pause() { + if (isPaused) { + return; + } + isPaused = true; + } + + public void resume() { + if (!isPaused) { + return; + } + isPaused = false; + if (defaultAnimatorSet.isPaused()) { + defaultAnimatorSet.resume(); + } + if (connectedAnimatorSet != null && connectedAnimatorSet.isPaused()) { + connectedAnimatorSet.resume(); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + bgGreen.setBounds(0, 0, getWidth(), getHeight()); + bgOrangeRed.setBounds(0, 0, getWidth(), getHeight()); + bgBlueGreen.setBounds(0, 0, getWidth(), getHeight()); + bgBlueViolet.setBounds(0, 0, getWidth(), getHeight()); + bgGreenLightReveal.setBounds(0, 0, getWidth() / REVEAL_SCALE_FACTOR, getHeight() / REVEAL_SCALE_FACTOR); + bgGreenDarkReveal.setBounds(0, 0, getWidth() / REVEAL_SCALE_FACTOR, getHeight() / REVEAL_SCALE_FACTOR); + backgroundProvider.setTotalSize(getWidth(), getHeight()); + } + + @Override + protected void onDraw(Canvas canvas) { + if (lockDrawing) { + return; + } + float halfWidth = getWidth() / 2f; + float halfHeight = getHeight() / 2f; + canvas.save(); + canvas.scale(backgroundProvider.scale, backgroundProvider.scale, halfWidth, halfHeight); + canvas.rotate(backgroundProvider.getDegree(), halfWidth, halfHeight); + + backgroundProvider.getLightCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + backgroundProvider.getDarkCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + + if (alphaGreen != 0 && alphaOrangeRed != 255) { + bgGreen.setAlpha(alphaGreen); + bgGreenLight.setAlpha(alphaGreen); + bgGreenDark.setAlpha(alphaGreen); + + bgGreen.draw(canvas); + bgGreenLight.draw(backgroundProvider.getLightCanvas()); + bgGreenDark.draw(backgroundProvider.getDarkCanvas()); + } + if (alphaBlueGreen != 0 && alphaOrangeRed != 255) { + bgBlueGreen.setAlpha(alphaBlueGreen); + bgBlueGreenDark.setAlpha(alphaBlueGreen); + bgBlueGreenLight.setAlpha(alphaBlueGreen); + + bgBlueGreen.draw(canvas); + bgBlueGreenDark.draw(backgroundProvider.getDarkCanvas()); + bgBlueGreenLight.draw(backgroundProvider.getLightCanvas()); + } + if (alphaBlueViolet != 0 && alphaOrangeRed != 255) { + bgBlueViolet.setAlpha(alphaBlueViolet); + bgBlueVioletDark.setAlpha(alphaBlueViolet); + bgBlueVioletLight.setAlpha(alphaBlueViolet); + + bgBlueViolet.draw(canvas); + bgBlueVioletDark.draw(backgroundProvider.getDarkCanvas()); + bgBlueVioletLight.draw(backgroundProvider.getLightCanvas()); + } + + if (alphaOrangeRed != 0) { + bgOrangeRed.setAlpha(alphaOrangeRed); + bgOrangeRedDark.setAlpha(alphaOrangeRed); + bgOrangeRedLight.setAlpha(alphaOrangeRed); + + bgOrangeRed.draw(canvas); + bgOrangeRedDark.draw(backgroundProvider.getDarkCanvas()); + bgOrangeRedLight.draw(backgroundProvider.getLightCanvas()); + } + canvas.restore(); + + if (showClip) { + clipPath.rewind(); + clipPath.addCircle(clipCx, clipCy, clipRadius, Path.Direction.CW); + canvas.clipPath(clipPath); + canvas.scale(backgroundProvider.scale, backgroundProvider.scale, halfWidth, halfHeight); + bgGreen.setAlpha(255); + bgGreen.draw(canvas); + + clipPath.rewind(); + clipPath.addCircle(clipCx / (float) REVEAL_SCALE_FACTOR, clipCy / (float) REVEAL_SCALE_FACTOR, clipRadius / REVEAL_SCALE_FACTOR, Path.Direction.CW); + backgroundProvider.getRevealCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + backgroundProvider.getRevealCanvas().save(); + backgroundProvider.getRevealCanvas().clipPath(clipPath); + bgGreenLightReveal.setAlpha(255); + bgGreenLightReveal.draw(backgroundProvider.getRevealCanvas()); + backgroundProvider.getRevealCanvas().restore(); + + backgroundProvider.getRevealDrakCanvas().drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + backgroundProvider.getRevealDrakCanvas().save(); + backgroundProvider.getRevealDrakCanvas().clipPath(clipPath); + bgGreenDarkReveal.setAlpha(255); + bgGreenDarkReveal.draw(backgroundProvider.getRevealDrakCanvas()); + backgroundProvider.getRevealDrakCanvas().restore(); + } + super.onDraw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpHintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpHintView.java new file mode 100644 index 000000000..cec7d97b0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpHintView.java @@ -0,0 +1,44 @@ +package org.telegram.ui.Components.voip; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; + +import org.telegram.ui.Stories.recorder.HintView2; + +@SuppressLint("ViewConstructor") +public class VoIpHintView extends HintView2 { + + private final Paint mainPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final VoIPBackgroundProvider backgroundProvider; + + public VoIpHintView(Context context, int direction, VoIPBackgroundProvider backgroundProvider, boolean withCloseBtn) { + super(context, direction); + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); + mainPaint.setPathEffect(new CornerPathEffect(rounding)); + if (withCloseBtn) { + setCloseButton(true); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + backgroundProvider.setDarkTranslation(getX(), getY()); + super.dispatchDraw(canvas); + } + + protected void drawBgPath(Canvas canvas) { + mainPaint.setShader(backgroundProvider.getDarkPaint().getShader()); + int alpha = Math.min(backgroundPaint.getAlpha(), backgroundProvider.getDarkPaint().getAlpha()); + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), alpha, Canvas.ALL_SAVE_FLAG); + canvas.drawPath(path, mainPaint); + if (backgroundProvider.isReveal()) { + mainPaint.setShader(backgroundProvider.getRevealDarkPaint().getShader()); + canvas.drawPath(path, mainPaint); + } + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSnowView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSnowView.java new file mode 100644 index 000000000..f5e705fad --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSnowView.java @@ -0,0 +1,39 @@ +package org.telegram.ui.Components.voip; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.View; + +import org.telegram.messenger.LiteMode; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.SnowflakesEffect; + +public class VoIpSnowView extends View { + private SnowflakesEffect snowflakesEffect; + private boolean isPaused; + + public VoIpSnowView(Context context) { + super(context); + } + + { + if (LiteMode.isEnabled(LiteMode.FLAG_CALLS_ANIMATIONS) && Theme.getEventType() == 0) { + snowflakesEffect = new SnowflakesEffect(0); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (isPaused) { + return; + } + if (snowflakesEffect != null) { + snowflakesEffect.onDraw(this, canvas); + } + } + + 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 new file mode 100644 index 000000000..8f48d428d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIpSwitchLayout.java @@ -0,0 +1,482 @@ +package org.telegram.ui.Components.voip; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; + +@SuppressLint("ViewConstructor") +public class VoIpSwitchLayout extends FrameLayout { + + public enum Type { + MICRO, + CAMERA, + VIDEO, + BLUETOOTH, + SPEAKER, + } + + private final VoIPBackgroundProvider backgroundProvider; + private VoIpButtonView voIpButtonView; + private Type type; + private final TextView currentTextView; + private final TextView newTextView; + public int animationDelay; + + public void setOnBtnClickedListener(VoIpButtonView.OnBtnClickedListener onBtnClickedListener) { + voIpButtonView.setOnBtnClickedListener(onBtnClickedListener); + } + + public VoIpSwitchLayout(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + setWillNotDraw(true); + voIpButtonView = new VoIpButtonView(context, backgroundProvider); + addView(voIpButtonView, LayoutHelper.createFrame(VoIpButtonView.ITEM_SIZE + 1.5f, VoIpButtonView.ITEM_SIZE + 1.5f, Gravity.CENTER_HORIZONTAL)); + + currentTextView = new TextView(context); + currentTextView.setGravity(Gravity.CENTER_HORIZONTAL); + currentTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); + currentTextView.setTextColor(Color.WHITE); + currentTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + addView(currentTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, VoIpButtonView.ITEM_SIZE + 6, 0, 2)); + + newTextView = new TextView(context); + newTextView.setGravity(Gravity.CENTER_HORIZONTAL); + newTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); + newTextView.setTextColor(Color.WHITE); + newTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + addView(newTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, VoIpButtonView.ITEM_SIZE + 6, 0, 2)); + currentTextView.setVisibility(GONE); + newTextView.setVisibility(GONE); + } + + private void setText(Type type, boolean isSelectedState) { + final String newText; + switch (type) { + case MICRO: + if (isSelectedState) { + newText = LocaleController.getString("VoipUnmute", R.string.VoipUnmute); + } else { + newText = LocaleController.getString("VoipMute", R.string.VoipMute); + } + break; + case CAMERA: + newText = LocaleController.getString("VoipFlip", R.string.VoipFlip); + break; + case VIDEO: + if (isSelectedState) { + newText = LocaleController.getString("VoipStartVideo", R.string.VoipStartVideo); + } else { + newText = LocaleController.getString("VoipStopVideo", R.string.VoipStopVideo); + } + break; + case BLUETOOTH: + newText = LocaleController.getString("VoipAudioRoutingBluetooth", R.string.VoipAudioRoutingBluetooth); + break; + case SPEAKER: + newText = LocaleController.getString("VoipSpeaker", R.string.VoipSpeaker); + break; + default: + newText = ""; + } + + if (currentTextView.getVisibility() == GONE && newTextView.getVisibility() == GONE) { + currentTextView.setVisibility(VISIBLE); + currentTextView.setText(newText); + newTextView.setText(newText); + return; + } + + if (newTextView.getText().equals(newText) && currentTextView.getText().equals(newText)) { + return; + } + + currentTextView.animate().alpha(0f).translationY(-AndroidUtilities.dp(4)).setDuration(140).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + currentTextView.setText(newText); + currentTextView.setTranslationY(0); + currentTextView.setAlpha(1.0f); + } + }).start(); + newTextView.setText(newText); + newTextView.setVisibility(VISIBLE); + newTextView.setAlpha(0); + newTextView.setTranslationY(AndroidUtilities.dp(5)); + newTextView.animate().alpha(1.0f).translationY(0).setDuration(150).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + newTextView.setVisibility(GONE); + } + }).start(); + } + + private void attachNewButton(int rawRes, int size, boolean isSelected, Type type) { + final VoIpButtonView newVoIpButtonView = new VoIpButtonView(getContext(), backgroundProvider); + if (rawRes == R.raw.camera_flip2) { + newVoIpButtonView.singleIcon = new RLottieDrawable(rawRes, "" + rawRes, size, size, true, null); + newVoIpButtonView.singleIcon.setMasterParent(newVoIpButtonView); + } else { + newVoIpButtonView.unSelectedIcon = new RLottieDrawable(rawRes, "" + rawRes, size, size, true, null); + newVoIpButtonView.selectedIcon = new RLottieDrawable(rawRes, "" + rawRes, size, size, true, null); + newVoIpButtonView.selectedIcon.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + } + 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)); + final VoIpButtonView oldVoIpButton = voIpButtonView; + voIpButtonView = newVoIpButtonView; + newVoIpButtonView.animate().alpha(1f).setDuration(250).start(); + oldVoIpButton.animate().alpha(0f).setDuration(250).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + removeView(oldVoIpButton); + } + }).start(); + } + + public void setType(Type newType, boolean isSelected) { + setType(newType, isSelected, false); + } + + public void setType(Type newType, boolean isSelected, boolean fast) { + if (this.type == newType && isSelected == voIpButtonView.isSelectedState) { + if (getVisibility() != View.VISIBLE) { + setVisibility(View.VISIBLE); + } + return; + } + if (getVisibility() != View.VISIBLE) { + setVisibility(View.VISIBLE); + } + int size = AndroidUtilities.dp(VoIpButtonView.ITEM_SIZE + 1.5f); + boolean ignoreSetState = false; + switch (newType) { + case MICRO: + if (this.type != Type.MICRO) { + voIpButtonView.unSelectedIcon = new RLottieDrawable(R.raw.call_mute, "" + R.raw.call_mute, size, size, true, null); + voIpButtonView.selectedIcon = new RLottieDrawable(R.raw.call_mute, "" + R.raw.call_mute, size, size, true, null); + voIpButtonView.selectedIcon.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + voIpButtonView.selectedIcon.setMasterParent(voIpButtonView); + } + break; + case VIDEO: + //R.drawable.calls_sharescreen screencast is not used in the design + if (this.type != Type.VIDEO) { + voIpButtonView.unSelectedIcon = new RLottieDrawable(R.raw.video_stop, "" + R.raw.video_stop, size, size, true, null); + voIpButtonView.selectedIcon = new RLottieDrawable(R.raw.video_stop, "" + R.raw.video_stop, size, size, true, null); + voIpButtonView.selectedIcon.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + voIpButtonView.selectedIcon.setMasterParent(voIpButtonView); + } + break; + case CAMERA: + if (this.type == Type.SPEAKER || this.type == Type.BLUETOOTH) { + ignoreSetState = true; + attachNewButton(R.raw.camera_flip2, size, isSelected, newType); + } else if (this.type != Type.CAMERA) { + voIpButtonView.singleIcon = new RLottieDrawable(R.raw.camera_flip2, "" + R.raw.camera_flip2, size, size, true, null); + voIpButtonView.singleIcon.setMasterParent(voIpButtonView); + } + break; + case SPEAKER: + if (this.type == Type.BLUETOOTH) { + ignoreSetState = isSelected == voIpButtonView.isSelectedState; + RLottieDrawable icon = isSelected ? voIpButtonView.selectedIcon : voIpButtonView.unSelectedIcon; + icon.setMasterParent(voIpButtonView); + icon.setOnAnimationEndListener(() -> AndroidUtilities.runOnUIThread(() -> attachSpeakerToBt(size))); + icon.start(); + } else if (this.type == Type.CAMERA) { + ignoreSetState = true; + attachNewButton(R.raw.speaker_to_bt, size, isSelected, newType); + } else if (this.type != Type.SPEAKER) { + attachSpeakerToBt(size); + } + break; + case BLUETOOTH: + if (this.type == Type.SPEAKER) { + ignoreSetState = isSelected == voIpButtonView.isSelectedState; + RLottieDrawable icon = isSelected ? voIpButtonView.selectedIcon : voIpButtonView.unSelectedIcon; + icon.setMasterParent(voIpButtonView); + icon.setOnAnimationEndListener(() -> AndroidUtilities.runOnUIThread(() -> attachBtToSpeaker(size))); + icon.start(); + } else if (this.type == Type.CAMERA) { + ignoreSetState = true; + attachNewButton(R.raw.bt_to_speaker, size, isSelected, newType); + } else if (this.type != Type.BLUETOOTH) { + attachBtToSpeaker(size); + } + break; + } + + if (!ignoreSetState) { + voIpButtonView.setSelectedState(isSelected, this.type != null && !fast, newType); + } + setText(newType, isSelected); + this.type = newType; + } + + private void attachSpeakerToBt(int size) { + voIpButtonView.unSelectedIcon = new RLottieDrawable(R.raw.speaker_to_bt, "" + R.raw.speaker_to_bt, size, size, true, null); + voIpButtonView.selectedIcon = new RLottieDrawable(R.raw.speaker_to_bt, "" + R.raw.speaker_to_bt, size, size, true, null); + voIpButtonView.selectedIcon.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + } + + private void attachBtToSpeaker(int size) { + voIpButtonView.unSelectedIcon = new RLottieDrawable(R.raw.bt_to_speaker, "" + R.raw.bt_to_speaker, size, size, true, null); + voIpButtonView.selectedIcon = new RLottieDrawable(R.raw.bt_to_speaker, "" + R.raw.bt_to_speaker, size, size, true, null); + voIpButtonView.selectedIcon.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + } + + public static class VoIpButtonView extends View { + private static final int ITEM_SIZE = 52; + + private RLottieDrawable unSelectedIcon; + private RLottieDrawable selectedIcon; + private RLottieDrawable singleIcon; + private final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint whiteCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint darkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path clipPath = new Path(); + private final int maxRadius = AndroidUtilities.dp(ITEM_SIZE / 2f); + private int unselectedRadius = maxRadius; + private int selectedRadius = 0; + private boolean isSelectedState = false; + private int singleIconBackgroundAlphaPercent = 0; + private OnBtnClickedListener onBtnClickedListener; + private ValueAnimator animator; + private final VoIPBackgroundProvider backgroundProvider; + + public void setSelectedState(boolean selectedState, boolean animate, Type type) { + if (animate) { + if (singleIcon != null) { + if (animator != null) { + animator.removeAllUpdateListeners(); + animator.cancel(); + } + animator = selectedState ? ValueAnimator.ofInt(20, 100) : ValueAnimator.ofInt(100, 20); + animator.addUpdateListener(animation -> { + singleIconBackgroundAlphaPercent = (int) animation.getAnimatedValue(); + invalidate(); + }); + animator.setDuration(200); + animator.start(); + if (type == Type.CAMERA) { + singleIcon.setCurrentFrame(0, false); + singleIcon.start(); + } + } else { + if (animator != null) { + animator.removeAllUpdateListeners(); + animator.cancel(); + } + animator = ValueAnimator.ofInt(0, maxRadius); + if (selectedState) { + unselectedRadius = maxRadius; + animator.addUpdateListener(animation -> { + selectedRadius = (int) animation.getAnimatedValue(); + invalidate(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + unselectedRadius = 0; //switched to selected state + invalidate(); + } + }); + animator.setDuration(200); + animator.start(); + selectedIcon.setCurrentFrame(0, false); + selectedIcon.start(); + } else { + selectedRadius = maxRadius; + animator.addUpdateListener(animation -> { + unselectedRadius = (int) animation.getAnimatedValue(); + invalidate(); + }); + animator.setDuration(200); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + selectedRadius = 0; //switched to NOT selected state + invalidate(); + } + }); + animator.start(); + } + } + } else { + if (selectedState) { + selectedRadius = maxRadius; + unselectedRadius = 0; + singleIconBackgroundAlphaPercent = 100; + if (type == Type.VIDEO || type == Type.MICRO) { + selectedIcon.setCurrentFrame(selectedIcon.getFramesCount() - 1, false); + } + } else { + selectedRadius = 0; + unselectedRadius = maxRadius; + singleIconBackgroundAlphaPercent = 20; + } + } + isSelectedState = selectedState; + invalidate(); + } + + public interface OnBtnClickedListener { + void onClicked(View view); + } + + public void setOnBtnClickedListener(OnBtnClickedListener onBtnClickedListener) { + this.onBtnClickedListener = onBtnClickedListener; + } + + public VoIpButtonView(@NonNull Context context, VoIPBackgroundProvider backgroundProvider) { + super(context); + this.backgroundProvider = backgroundProvider; + backgroundProvider.attach(this); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + whiteCirclePaint.setColor(Color.WHITE); + + maskPaint.setColor(Color.BLACK); + maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + + darkPaint.setColor(Color.BLACK); + darkPaint.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_ATOP)); + darkPaint.setAlpha(VoIPBackgroundProvider.DARK_LIGHT_DEFAULT_ALPHA); + } + + @Override + protected void onDraw(Canvas canvas) { + float cx = getWidth() / 2f; + float cy = getHeight() / 2f; + + float left = getX() + ((View) getParent()).getX(); + float top = getY() + ((View) ((View) getParent()).getParent()).getY(); + backgroundProvider.setLightTranslation(left, top); + + if (singleIcon != null) { + if (singleIconBackgroundAlphaPercent > 20) { + darkPaint.setAlpha((int) (VoIPBackgroundProvider.DARK_LIGHT_DEFAULT_ALPHA * singleIconBackgroundAlphaPercent / 100f)); + whiteCirclePaint.setAlpha((int) (255 * singleIconBackgroundAlphaPercent / 100f)); + canvas.drawCircle(cx, cy, maxRadius, whiteCirclePaint); + singleIcon.draw(canvas, maskPaint); + singleIcon.draw(canvas, darkPaint); //dimming icons + } else { + canvas.drawCircle(cx, cy, maxRadius, backgroundProvider.getLightPaint()); //add a light background + if(backgroundProvider.isReveal()) { + canvas.drawCircle(cx, cy, maxRadius, backgroundProvider.getRevealPaint()); + } + singleIcon.draw(canvas); + } + return; + } + if (selectedIcon == null || unSelectedIcon == null) return; + + boolean isUnSelected = unselectedRadius == maxRadius && selectedRadius == 0; + boolean isSelected = selectedRadius == maxRadius && unselectedRadius == 0; + + if (selectedRadius == maxRadius && unselectedRadius > 0 && unselectedRadius != maxRadius) { + //in the process of changing from selected to NOT selected. + canvas.drawCircle(cx, cy, selectedRadius, whiteCirclePaint); + canvas.drawCircle(cx, cy, unselectedRadius, maskPaint); + + selectedIcon.setAlpha(255); + selectedIcon.draw(canvas, maskPaint); + selectedIcon.setAlpha((int) (255 * VoIPBackgroundProvider.DARK_LIGHT_PERCENT)); + selectedIcon.draw(canvas); //dimming icons + + clipPath.reset(); + clipPath.addCircle(cx, cy, unselectedRadius, Path.Direction.CW); + canvas.clipPath(clipPath); + canvas.drawCircle(cx, cy, unselectedRadius, maskPaint); //remove all background + } + + if (isUnSelected || unselectedRadius > 0) { + //not selected or in the process of changing from selected to NOT selected + canvas.drawCircle(cx, cy, unselectedRadius, backgroundProvider.getLightPaint()); //add a light background + if (backgroundProvider.isReveal()) { + canvas.drawCircle(cx, cy, unselectedRadius, backgroundProvider.getRevealPaint()); + } + unSelectedIcon.draw(canvas); + } + + if (isSelected || (selectedRadius > 0 && unselectedRadius == maxRadius)) { + //selected and not in the process of changing or in the process of changing from NOT selected to selected. + clipPath.reset(); + clipPath.addCircle(cx, cy, selectedRadius, Path.Direction.CW); + canvas.clipPath(clipPath); + canvas.drawCircle(cx, cy, selectedRadius, whiteCirclePaint); //circular background + selectedIcon.setAlpha(255); + selectedIcon.draw(canvas, maskPaint); + selectedIcon.setAlpha((int) (255 * VoIPBackgroundProvider.DARK_LIGHT_PERCENT)); + selectedIcon.draw(canvas); //dimming icons + } + } + + private boolean isAnimating() { + boolean isUnSelected = unselectedRadius == maxRadius && selectedRadius == 0; + boolean isSelected = selectedRadius == maxRadius && unselectedRadius == 0; + return !isUnSelected && !isSelected; + } + + private float startX; + private float startY; + + @SuppressLint("ClickableViewAccessibility") + @Override + 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(); + 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(); + float endX = event.getX(); + float endY = event.getY(); + if (isClick(startX, endX, startY, endY) && !isAnimating()) { + if (onBtnClickedListener != null) onBtnClickedListener.onClicked(this); + } + 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(); + break; + } + return true; + } + + private boolean isClick(float startX, float endX, float startY, float endY) { + float differenceX = Math.abs(startX - endX); + float differenceY = Math.abs(startY - endY); + return !(differenceX > AndroidUtilities.dp(48) || differenceY > AndroidUtilities.dp(48)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipBlobDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipBlobDrawable.java new file mode 100644 index 000000000..ccfbc368c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoipBlobDrawable.java @@ -0,0 +1,42 @@ +package org.telegram.ui.Components.voip; + +import org.telegram.messenger.LiteMode; +import org.telegram.ui.Components.BlobDrawable; + +public class VoipBlobDrawable extends BlobDrawable { + + public VoipBlobDrawable(int n) { + super(n); + } + + public VoipBlobDrawable(int n, int liteFlag) { + super(n, liteFlag); + } + + protected void generateBlob(float[] radius, float[] angle, int i, float muteToStaticProgress) { + float angleDif = 360f / N * 0.05f; + float radDif = maxRadius - minRadius; + radius[i] = minRadius + ((Math.abs(((random.nextInt() % 100f) / 100f)) * radDif) * muteToStaticProgress); + angle[i] = 360f / N * i + (((random.nextInt() * muteToStaticProgress) % 100f) / 100f) * angleDif; + speed[i] = (float) (0.017 + 0.003 * (Math.abs(random.nextInt() % 100f) / 100f)); + } + + public void update(float amplitude, float speedScale, float muteToStaticProgress) { + if (!LiteMode.isEnabled(liteFlag)) { + return; + } + for (int i = 0; i < N; i++) { + progress[i] += (speed[i] * MIN_SPEED) + amplitude * speed[i] * MAX_SPEED * speedScale; + if (progress[i] >= 1f) { + progress[i] = 0; + radius[i] = radiusNext[i]; + angle[i] = angleNext[i]; + if (muteToStaticProgress < 1f) { + generateBlob(radiusNext, angleNext, i, muteToStaticProgress); + } else { + generateBlob(radiusNext, angleNext, i); + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 92ccd78ca..faafc5082 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -1069,7 +1069,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.storiesUpdated) { - listViewAdapter.setStories(getMessagesController().getStoriesController().getHiddenList(), true); + if (listViewAdapter != null) { + listViewAdapter.setStories(getMessagesController().getStoriesController().getHiddenList(), true); + } MessagesController.getInstance(currentAccount).getStoriesController().loadHiddenStories(); } else if (id == NotificationCenter.contactsDidLoad) { if (listViewAdapter != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java b/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java index 980426c61..9b4af2549 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java @@ -44,6 +44,9 @@ import java.util.ArrayList; @SuppressLint("ViewConstructor") public class DefaultThemesPreviewCell extends LinearLayout { + public final static int TYPE_CUSTOM_LIST = -1; + public final static int TYPE_CUSTOM_GRID = -2; // not implemented + private final RecyclerListView recyclerView; private LinearLayoutManager layoutManager = null; private final FlickerLoadingView progressView; @@ -70,8 +73,13 @@ public class DefaultThemesPreviewCell extends LinearLayout { addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - adapter = new ChatThemeBottomSheet.Adapter(parentFragment.getCurrentAccount(), null, currentType == ThemeActivity.THEME_TYPE_BASIC ? ThemeSmallPreviewView.TYPE_DEFAULT : ThemeSmallPreviewView.TYPE_GRID); - recyclerView = new RecyclerListView(getContext()); + adapter = new ChatThemeBottomSheet.Adapter(parentFragment.getCurrentAccount(), null, currentType == ThemeActivity.THEME_TYPE_BASIC || currentType == TYPE_CUSTOM_LIST ? ThemeSmallPreviewView.TYPE_DEFAULT : ThemeSmallPreviewView.TYPE_GRID); + recyclerView = new RecyclerListView(getContext()) { + @Override + public Integer getSelectorColor(int position) { + return 0; + } + }; recyclerView.setAdapter(adapter); recyclerView.setSelectorDrawableColor(0); recyclerView.setClipChildren(false); @@ -136,7 +144,7 @@ public class DefaultThemesPreviewCell extends LinearLayout { progressView.setViewType(FlickerLoadingView.CHAT_THEMES_TYPE); progressView.setVisibility(View.VISIBLE); - if (currentType == ThemeActivity.THEME_TYPE_BASIC) { + if (currentType == ThemeActivity.THEME_TYPE_BASIC || currentType == TYPE_CUSTOM_LIST) { frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 0, 8, 0, 8)); frameLayout.addView(recyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 0, 8, 0, 8)); } else { @@ -312,7 +320,7 @@ public class DefaultThemesPreviewCell extends LinearLayout { if (wasPortrait != null && wasPortrait == isPortrait) { return; } - if (currentType == ThemeActivity.THEME_TYPE_BASIC) { + if (currentType == ThemeActivity.THEME_TYPE_BASIC || currentType == TYPE_CUSTOM_LIST) { if (layoutManager == null) { recyclerView.setLayoutManager(layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); } @@ -342,7 +350,7 @@ public class DefaultThemesPreviewCell extends LinearLayout { } public void updateDayNightMode() { - if (currentType == ThemeActivity.THEME_TYPE_BASIC) { + if (currentType == ThemeActivity.THEME_TYPE_BASIC || currentType == TYPE_CUSTOM_LIST) { themeIndex = !Theme.isCurrentThemeDay() ? 2 : 0; } else { if (Theme.getActiveTheme().getKey().equals("Blue")) { @@ -440,13 +448,18 @@ public class DefaultThemesPreviewCell extends LinearLayout { } public void updateColors() { - if (currentType == ThemeActivity.THEME_TYPE_BASIC) { - darkThemeDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4), PorterDuff.Mode.SRC_IN)); - - Theme.setSelectorDrawableColor(dayNightCell.getBackground(), Theme.getColor(Theme.key_listSelector), true); - browseThemesCell.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); - dayNightCell.setColors(-1, Theme.key_windowBackgroundWhiteBlueText4); - browseThemesCell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); + if (currentType == ThemeActivity.THEME_TYPE_BASIC || currentType == TYPE_CUSTOM_LIST) { + if (darkThemeDrawable != null) { + darkThemeDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4), PorterDuff.Mode.SRC_IN)); + } + if (dayNightCell != null) { + Theme.setSelectorDrawableColor(dayNightCell.getBackground(), Theme.getColor(Theme.key_listSelector), true); + dayNightCell.setColors(-1, Theme.key_windowBackgroundWhiteBlueText4); + } + if (browseThemesCell != null) { + browseThemesCell.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); + browseThemesCell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 4a2efd73c..dc946e519 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -45,6 +45,8 @@ import android.os.Build; import android.os.Bundle; import android.text.TextPaint; import android.text.TextUtils; +import android.transition.ChangeBounds; +import android.transition.TransitionManager; import android.util.LongSparseArray; import android.util.Property; import android.util.StateSet; @@ -189,6 +191,7 @@ import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PacmanAnimation; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.Premium.boosts.UserSelectorBottomSheet; import org.telegram.ui.Components.ProxyDrawable; import org.telegram.ui.Components.PullForegroundDrawable; import org.telegram.ui.Components.RLottieDrawable; @@ -1292,7 +1295,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. filterTabsView != null && !filterTabsView.isEditing() && !searching && !rightSlidingDialogContainer.hasFragment() && - !parentLayout.checkTransitionAnimation() && !parentLayout.isInPreviewMode() && !parentLayout.isPreviewOpenAnimationInProgress() && !parentLayout.getDrawerLayoutContainer().isDrawerOpened() && + !parentLayout.checkTransitionAnimation() && !parentLayout.isInPreviewMode() && !parentLayout.isPreviewOpenAnimationInProgress() && !(parentLayout.getDrawerLayoutContainer() != null && parentLayout.getDrawerLayoutContainer().isDrawerOpened()) && ( ev == null || startedTracking || @@ -1313,7 +1316,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. startedTracking = true; startedTrackingPointerId = ev.getPointerId(0); startedTrackingX = (int) ev.getX(); - parentLayout.getDrawerLayoutContainer().setAllowOpenDrawerBySwipe(false); + if (parentLayout.getDrawerLayoutContainer() != null) { + parentLayout.getDrawerLayoutContainer().setAllowOpenDrawerBySwipe(false); + } if (animatingForward) { if (startedTrackingX < viewPages[0].getMeasuredWidth() + viewPages[0].getTranslationX()) { additionalOffset = viewPages[0].getTranslationX(); @@ -3236,7 +3241,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override protected void onDefaultTabMoved() { - if (!getMessagesController().premiumLocked) { + if (!getMessagesController().premiumFeaturesBlocked()) { try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) { @@ -4712,7 +4717,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } @Override - public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { + public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { } @@ -5402,14 +5407,21 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } public boolean isPremiumRestoreHintVisible() { - if (!MessagesController.getInstance(currentAccount).premiumLocked && folderId == 0) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && folderId == 0) { return MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_RESTORE") && !getUserConfig().isPremium(); } return false; } + public boolean isPremiumChristmasHintVisible() { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && folderId == 0) { + return MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_CHRISTMAS"); + } + return false; + } + public boolean isPremiumHintVisible() { - if (!MessagesController.getInstance(currentAccount).premiumLocked && folderId == 0) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && folderId == 0) { if (MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE") && getUserConfig().isPremium() || MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_ANNUAL") && !getUserConfig().isPremium()) { if (UserConfig.getInstance(currentAccount).isPremium() ? !BuildVars.useInvoiceBilling() && MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(true) != null : MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false) != null) { isPremiumHintUpgrade = MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE"); @@ -5497,8 +5509,8 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } }; - if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - popupLayout.setExpireDateHint(((TLRPC.TL_emojiStatusUntil) user.emoji_status).until); + if (user != null && DialogObject.getEmojiStatusUntil(user.emoji_status) > 0) { + popupLayout.setExpireDateHint(DialogObject.getEmojiStatusUntil(user.emoji_status)); } popupLayout.setSelected(statusDrawable.getDrawable() instanceof AnimatedEmojiDrawable ? ((AnimatedEmojiDrawable) statusDrawable.getDrawable()).getDocumentId() : null); popupLayout.setSaveState(1); @@ -5629,6 +5641,31 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } authHintCell.set(DialogsActivity.this, currentAccount); updateAuthHintCellVisibility(true); + } else if (isPremiumChristmasHintVisible()) { + dialogsHintCellVisible = true; + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> UserSelectorBottomSheet.open()); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + LocaleController.getString("BoostingPremiumChristmasTitle", R.string.BoostingPremiumChristmasTitle), + Theme.key_windowBackgroundWhiteValueText, + AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD, + null + ), + LocaleController.formatString("BoostingPremiumChristmasSubTitle", R.string.BoostingPremiumChristmasSubTitle) + ); + dialogsHintCell.setChristmasStyle(v -> { + MessagesController.getInstance(currentAccount).removeSuggestion(0, "PREMIUM_CHRISTMAS"); + ChangeBounds transition = new ChangeBounds(); + transition.setDuration(200); + TransitionManager.beginDelayedTransition((ViewGroup) dialogsHintCell.getParent(), transition); + updateDialogsHint(); + BulletinFactory.of(this) + .createSimpleBulletin(R.raw.chats_infotip, LocaleController.getString("BoostingPremiumChristmasToast", R.string.BoostingPremiumChristmasToast), 4) + .setDuration(Bulletin.DURATION_PROLONG) + .show(); + }); + updateAuthHintCellVisibility(false); } else if (isPremiumRestoreHintVisible()) { dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); @@ -6082,7 +6119,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. break; } } - boolean visible = !getUserConfig().isPremium() && !getMessagesController().premiumLocked && visibleByDownload && visibleByPosition && DISPLAY_SPEEDOMETER_IN_DOWNLOADS_SEARCH; + boolean visible = !getUserConfig().isPremium() && !getMessagesController().premiumFeaturesBlocked() && visibleByDownload && visibleByPosition && DISPLAY_SPEEDOMETER_IN_DOWNLOADS_SEARCH; boolean wasVisible = speedItem.getTag() != null; if (visible != wasVisible) { @@ -6211,7 +6248,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } else if (onlySelect || folderId != 0) { finishFragment(); - } else if (parentLayout != null) { + } else if (parentLayout != null && parentLayout.getDrawerLayoutContainer() != null) { parentLayout.getDrawerLayoutContainer().openDrawer(false); } } else if (id == 1) { @@ -7385,6 +7422,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. dialogsHintCell.setVisibility(View.INVISIBLE); } else { dialogsHintCell.setVisibility(View.VISIBLE); + ViewParent dialogsHintCellParent = dialogsHintCell.getParent(); + if (dialogsHintCellParent != null) { + dialogsHintCellParent.requestLayout(); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java index 5043cd7bd..b49e62909 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java @@ -787,7 +787,7 @@ public class EmojiAnimationsOverlay implements NotificationCenter.NotificationCe if (chatActivity == null) { return; } - if (MessagesController.getInstance(currentAccount).premiumLocked || chatActivity.getParentActivity() == null) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() || chatActivity.getParentActivity() == null) { return; } StickerSetBulletinLayout layout = new StickerSetBulletinLayout(contentLayout.getContext(), null, StickerSetBulletinLayout.TYPE_EMPTY, messageObject.getDocument(), chatActivity.getResourceProvider()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index c8ac956a0..0d4206c3f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -212,7 +212,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } final boolean currentFullValue = getContextValue() || getChatValue(); if (currentFullValue != prevFullValue) { - int start = 1 + (!getMessagesController().premiumLocked ? 1 : 0); + int start = 1 + (!getMessagesController().premiumFeaturesBlocked() ? 1 : 0); TextCheckCell last = null; for (int i = 0; i < listView.getChildCount(); ++i) { View child = listView.getChildAt(i); @@ -239,7 +239,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumLocked ? 1 : 0)); + position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumFeaturesBlocked() ? 1 : 0)); } LocaleController.LocaleInfo localeInfo; if (search) { @@ -304,7 +304,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumLocked ? 1 : 0)); + position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumFeaturesBlocked() ? 1 : 0)); } LocaleController.LocaleInfo localeInfo; if (search) { @@ -541,7 +541,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification if (!unofficialLanguages.isEmpty()) { count += unofficialLanguages.size() + 1; } - return 4 + (getMessagesController().premiumLocked ? 0 : 1) + (getChatValue() || getContextValue() ? 1 : 0) + 1 + count; + return 4 + (getMessagesController().premiumFeaturesBlocked() ? 0 : 1) + (getChatValue() || getContextValue() ? 1 : 0) + 1 + count; } } @@ -594,7 +594,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification switch (holder.getItemViewType()) { case VIEW_TYPE_LANGUAGE: { if (!search) { - position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumLocked ? 1 : 0)); + position -= (7 - (!(getChatValue() || getContextValue()) ? 1 : 0) - (getMessagesController().premiumFeaturesBlocked() ? 1 : 0)); } TextRadioCell textSettingsCell = (TextRadioCell) holder.itemView; textSettingsCell.updateRTL(); @@ -692,7 +692,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification case VIEW_TYPE_INFO: { TextInfoPrivacyCell infoCell = (TextInfoPrivacyCell) holder.itemView; infoCell.updateRTL(); - if (position == (!getMessagesController().premiumLocked && (getContextValue() || getChatValue()) ? 4 : 3)) { + if (position == (!getMessagesController().premiumFeaturesBlocked() && (getContextValue() || getChatValue()) ? 4 : 3)) { infoCell.setText(LocaleController.getString("TranslateMessagesInfo1", R.string.TranslateMessagesInfo1)); infoCell.setBackground(Theme.getThemedDrawableByKey(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); infoCell.setTopPadding(11); @@ -720,7 +720,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification } else { if (i-- == 0) return VIEW_TYPE_HEADER; if (i-- == 0) return VIEW_TYPE_SWITCH; - if (!getMessagesController().premiumLocked) { + if (!getMessagesController().premiumFeaturesBlocked()) { if (i-- == 0) return VIEW_TYPE_SWITCH; } if (getChatValue() || getContextValue()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 6cf844c3e..d6c220e66 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -167,6 +167,7 @@ import org.telegram.ui.Components.PipRoundVideoView; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.boosts.BoostPagerBottomSheet; import org.telegram.ui.Components.Premium.boosts.GiftInfoBottomSheet; +import org.telegram.ui.Components.Premium.boosts.UserSelectorBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RecyclerListView; @@ -257,7 +258,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private List overlayPasscodeViews = new ArrayList<>(); private TermsOfServiceView termsOfServiceView; private BlockingUpdateView blockingUpdateView; - public Dialog visibleDialog; + public final ArrayList visibleDialogs = new ArrayList<>(); private Dialog proxyErrorDialog; private RecyclerListView sideMenu; private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; @@ -265,6 +266,15 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private FrameLayout sideMenuContainer; private View rippleAbove; private IUpdateLayout updateLayout; + public Dialog getVisibleDialog() { + for (int i = visibleDialogs.size() - 1; i >= 0; --i) { + Dialog dialog = visibleDialogs.get(i); + if (dialog.isShowing()) { + return dialog; + } + } + return null; + } private Dialog localeDialog; private boolean loadingLocaleDialog; @@ -950,12 +960,8 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati BotWebViewSheet webViewSheet = new BotWebViewSheet(this, getLastFragment().getResourceProvider()); webViewSheet.setParentActivity(this); webViewSheet.requestWebView(currentAccount, attachMenuBot.bot_id, attachMenuBot.bot_id, attachMenuBot.short_name, null, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, null, null, false, startApp, null, BotWebViewSheet.FLAG_FROM_SIDE_MENU); - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; - } webViewSheet.show(); - visibleDialog = webViewSheet; + visibleDialogs.add(webViewSheet); } @Override @@ -1213,9 +1219,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } ((DrawerProfileCell) child).setUser(user, drawerLayoutAdapter.isAccountsShown()); } else if (child instanceof DrawerActionCell && drawerLayoutAdapter.getId(sideMenu.getChildAdapterPosition(child)) == 15) { - boolean hasStatus = - user.emoji_status instanceof TLRPC.TL_emojiStatus || - user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000); + boolean hasStatus = user != null && DialogObject.getEmojiStatusDocumentId(user.emoji_status) != 0; ((DrawerActionCell) child).updateTextAndIcon( hasStatus ? LocaleController.getString("ChangeEmojiStatus", R.string.ChangeEmojiStatus) : @@ -1233,8 +1237,8 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } } }; - if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - popupLayout.setExpireDateHint(((TLRPC.TL_emojiStatusUntil) user.emoji_status).until); + if (user != null) { + popupLayout.setExpireDateHint(DialogObject.getEmojiStatusUntil(user.emoji_status)); } popupLayout.setSelected(scrimDrawable != null && scrimDrawable.getDrawable() instanceof AnimatedEmojiDrawable ? ((AnimatedEmojiDrawable) scrimDrawable.getDrawable()).getDocumentId() : null); popupLayout.setSaveState(2); @@ -1660,6 +1664,9 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (GiftInfoBottomSheet.handleIntent(intent, progress)) { return true; } + if (UserSelectorBottomSheet.handleIntent(intent, progress)) { + return true; + } if (AndroidUtilities.handleProxyIntent(this, intent)) { return true; } @@ -3851,7 +3858,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, botAttachable); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, botAttachable, true); }, null); } else if (attachBot.request_write_access || forceNotInternalForApps) { AtomicBoolean allowWrite = new AtomicBoolean(true); @@ -3869,15 +3876,15 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati } }), ConnectionsManager.RequestFlagInvokeAfter | ConnectionsManager.RequestFlagFailOnServerErrors); - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false, false); }); } else { - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false, false); } } })); } else { - processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false); + processWebAppBot(intentAccount, username, group, sticker, emoji, botUser, botChat, botChannel, botChatAdminParams, message, contactToken, folderSlug, hasUrl, messageId, channelId, threadId, commentId, game, auth, lang, unsupportedUrl, code, loginToken, wallPaper, inputInvoiceSlug, theme, voicechat, livestream, state, videoTimestamp, setAsAttachBot, attachMenuBotToOpen, attachMenuBotChoose, botAppMaybe, botAppStartParam, progress, forceNotInternalForApps, storyId, isBoost, user, dismissLoading, false, false); } return; } @@ -4855,7 +4862,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati final int storyId, final boolean isBoost, TLRPC.User user, - Runnable dismissLoading, boolean botAttachable) { + Runnable dismissLoading, boolean botAttachable, boolean ignoreInactive) { TLRPC.TL_messages_getBotApp getBotApp = new TLRPC.TL_messages_getBotApp(); TLRPC.TL_inputBotAppShortName app = new TLRPC.TL_inputBotAppShortName(); @@ -4879,18 +4886,16 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati BotWebViewSheet sheet = new BotWebViewSheet(LaunchActivity.this, lastFragment.getResourceProvider()); sheet.setParentActivity(LaunchActivity.this); sheet.requestWebView(intentAccount, user.id, user.id, null, null, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP, 0, false, lastFragment, botApp.app, allowWrite.get(), botAppStartParam, user); - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; - } sheet.show(); - visibleDialog = sheet; + visibleDialogs.add(sheet); if (botApp.inactive || forceNotInternalForApps) { sheet.showJustAddedBulletin(); } }; - if (botApp.inactive && botAttachable) { + if (ignoreInactive) { + loadBotSheet.run(); + } else if (botApp.inactive && botAttachable) { WebAppDisclaimerAlert.show(this, (allowSendMessage) -> { loadBotSheet.run(); }, null); @@ -5024,10 +5029,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (lastFragment != null) { lastFragment.dismissCurrentDialog(); } - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; + for (int i = 0; i < visibleDialogs.size(); ++i) { + Dialog dialog = visibleDialogs.get(i); + if (dialog.isShowing()) { + visibleDialogs.get(i).dismiss(); + } } + visibleDialogs.clear(); presentFragment(dialogsActivity); } else if (lastFragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) lastFragment; @@ -5058,10 +5066,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (lastFragment != null) { lastFragment.dismissCurrentDialog(); } - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; + for (int i = 0; i < visibleDialogs.size(); ++i) { + Dialog dialog = visibleDialogs.get(i); + if (dialog.isShowing()) { + visibleDialogs.get(i).dismiss(); + } } + visibleDialogs.clear(); presentFragment(dialogsActivity); } else if (lastFragment instanceof ChatActivity) { ((ChatActivity) lastFragment).openAttachBotLayout(user.id, setAsAttachBot, true); @@ -5249,19 +5260,11 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public Dialog showAlertDialog(AlertDialog.Builder builder) { try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; - } - } catch (Exception e) { - FileLog.e(e); - } - try { - visibleDialog = builder.show(); - visibleDialog.setCanceledOnTouchOutside(true); - visibleDialog.setOnDismissListener(dialog -> { - if (visibleDialog != null) { - if (visibleDialog == localeDialog) { + AlertDialog dialog = builder.show(); + dialog.setCanceledOnTouchOutside(true); + dialog.setOnDismissListener(d -> { + if (dialog != null) { + if (dialog == localeDialog) { BaseFragment fragment = actionBarLayout == null ? null : actionBarLayout.getLastFragment(); try { String shorname = LocaleController.getInstance().getCurrentLocaleInfo().shortName; @@ -5280,7 +5283,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati FileLog.e(e); } localeDialog = null; - } else if (visibleDialog == proxyErrorDialog) { + } else if (dialog == proxyErrorDialog) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); editor.putBoolean("proxy_enabled", false); @@ -5291,9 +5294,10 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati proxyErrorDialog = null; } } - visibleDialog = null; + visibleDialogs.remove(dialog); }); - return visibleDialog; + visibleDialogs.add(dialog); + return dialog; } catch (Exception e) { FileLog.e(e); } @@ -5865,10 +5869,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati editorView.destroy(); } try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; + for (int i = 0; i < visibleDialogs.size(); ++i) { + Dialog dialog = visibleDialogs.get(i); + if (dialog.isShowing()) { + visibleDialogs.get(i).dismiss(); + } } + visibleDialogs.clear(); } catch (Exception e) { FileLog.e(e); } @@ -6835,10 +6842,13 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati localeDialog = null; drawerLayoutContainer.closeDrawer(true); presentFragment(new LanguageSelectActivity()); - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; + for (int i = 0; i < visibleDialogs.size(); ++i) { + Dialog dialog = visibleDialogs.get(i); + if (dialog.isShowing()) { + visibleDialogs.get(i).dismiss(); + } } + visibleDialogs.clear(); }); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50)); builder.setView(linearLayout); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LauncherIconController.java b/TMessagesProj/src/main/java/org/telegram/ui/LauncherIconController.java index 6451e336e..49bf82153 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LauncherIconController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LauncherIconController.java @@ -39,7 +39,7 @@ public class LauncherIconController { AQUA("AquaIcon", R.drawable.icon_4_background_sa, R.mipmap.icon_foreground_sa, R.string.AppIconAqua), PREMIUM("PremiumIcon", R.drawable.icon_3_background_sa, R.mipmap.icon_3_foreground_sa, R.string.AppIconPremium, true), TURBO("TurboIcon", R.drawable.icon_5_background_sa, R.mipmap.icon_5_foreground_sa, R.string.AppIconTurbo, true), - NOX("NoxIcon", R.drawable.icon_2_background_sa, R.mipmap.icon_foreground_sa, R.string.AppIconNox, true); + NOX("NoxIcon", R.mipmap.icon_2_background_sa, R.mipmap.icon_foreground_sa, R.string.AppIconNox, true); public final String key; public final int background; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LiteModeSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LiteModeSettingsActivity.java index 1764383f9..2dca64a3a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LiteModeSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LiteModeSettingsActivity.java @@ -65,6 +65,7 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SeekBarAccessibilityDelegate; import org.telegram.ui.Components.SeekBarView; import org.telegram.ui.Components.Switch; +import org.telegram.ui.Components.ThanosEffect; import java.util.ArrayList; @@ -257,6 +258,9 @@ public class LiteModeSettingsActivity extends BaseFragment { items.add(Item.asCheckbox(LocaleController.getString("LiteOptionsBlur"), LiteMode.FLAG_CHAT_BLUR)); } items.add(Item.asCheckbox(LocaleController.getString("LiteOptionsScale"), LiteMode.FLAG_CHAT_SCALE)); + if (ThanosEffect.supports()) { + items.add(Item.asCheckbox(LocaleController.getString("LiteOptionsThanos"), LiteMode.FLAG_CHAT_THANOS)); + } } items.add(Item.asSwitch(R.drawable.msg2_call_earpiece, LocaleController.getString("LiteOptionsCalls"), LiteMode.FLAG_CALLS_ANIMATIONS)); items.add(Item.asSwitch(R.drawable.msg2_videocall, LocaleController.getString("LiteOptionsAutoplayVideo"), LiteMode.FLAG_AUTOPLAY_VIDEOS)); @@ -626,6 +630,9 @@ public class LiteModeSettingsActivity extends BaseFragment { if (SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_AVERAGE && (flags & LiteMode.FLAG_CHAT_BLUR) > 0) { count--; } + if (!ThanosEffect.supports() && (flags & LiteMode.FLAG_CHAT_THANOS) > 0) { + count--; + } return count; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java index ffd77d907..f098e8653 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -123,7 +123,6 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati private RLottieImageView imageView; private LinearLayout progressLayout; - private int nextRate; private int publicChats; private boolean endReached; @@ -659,31 +658,38 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati req.msg_id = messageObject.getId(); req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); } - if (!messages.isEmpty()) { - TLRPC.Message message = messages.get(messages.size() - 1).messageOwner; - req.offset_id = message.id; - req.offset_peer = getMessagesController().getInputPeer(MessageObject.getDialogId(message)); - req.offset_rate = nextRate; - } else { - req.offset_peer = new TLRPC.TL_inputPeerEmpty(); - } + req.offset = nextOffset == null ? "" : nextOffset; int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + TLRPC.TL_stats_publicForwards res = (TLRPC.TL_stats_publicForwards) response; if ((res.flags & 1) != 0) { - nextRate = res.next_rate; + nextOffset = res.next_offset; + } else { + nextOffset = null; } if (res.count != 0) { publicChats = res.count; } else if (publicChats == 0) { - publicChats = res.messages.size(); + publicChats = res.forwards.size(); } - endReached = !(res instanceof TLRPC.TL_messages_messagesSlice); + endReached = nextOffset == null; getMessagesController().putChats(res.chats, false); getMessagesController().putUsers(res.users, false); - for (int i = 0; i < res.messages.size(); i++) { - messages.add(new MessageObject(currentAccount, res.messages.get(i), false, true)); + + for (TLRPC.PublicForward forward : res.forwards) { + if (forward instanceof TL_stories.TL_publicForwardStory) { + TL_stories.TL_publicForwardStory forwardStory = (TL_stories.TL_publicForwardStory) forward; + forwardStory.story.dialogId = DialogObject.getPeerDialogId(forwardStory.peer); + forwardStory.story.messageId = forwardStory.story.id; + MessageObject msg = new MessageObject(currentAccount, forwardStory.story); + msg.generateThumbs(false); + messages.add(msg); + } else if (forward instanceof TLRPC.TL_publicForwardMessage) { + TLRPC.TL_publicForwardMessage forwardMessage = (TLRPC.TL_publicForwardMessage) forward; + messages.add(new MessageObject(currentAccount, forwardMessage.message, false, true)); + } } + if (emptyView != null) { emptyView.showTextView(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MultiContactsSelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/MultiContactsSelectorBottomSheet.java new file mode 100644 index 000000000..9bcf57872 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/MultiContactsSelectorBottomSheet.java @@ -0,0 +1,497 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ReplacementSpan; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearSmoothScrollerCustom; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BottomSheetWithRecyclerListView; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.boosts.BoostRepository; +import org.telegram.ui.Components.Premium.boosts.adapters.SelectorAdapter; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorBtnCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorHeaderCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorSearchCell; +import org.telegram.ui.Components.Premium.boosts.cells.selector.SelectorUserCell; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class MultiContactsSelectorBottomSheet extends BottomSheetWithRecyclerListView { + private static MultiContactsSelectorBottomSheet instance; + + public interface SelectorListener { + void onUserSelected(List ids); + } + + public static void open(int maxCount, SelectorListener selectorListener) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null) { + return; + } + if (instance != null) { + return; + } + MultiContactsSelectorBottomSheet sheet = new MultiContactsSelectorBottomSheet(fragment, true, maxCount, selectorListener); + sheet.show(); + instance = sheet; + } + + private static final int BOTTOM_HEIGHT_DP = 60; + + private final ButtonWithCounterView actionButton; + private final SelectorSearchCell searchField; + private final View sectionCell; + private final SelectorHeaderCell headerView; + private final SelectorBtnCell buttonContainer; + + private final ArrayList oldItems = new ArrayList<>(); + private final ArrayList items = new ArrayList<>(); + private final HashSet selectedIds = new HashSet<>(); + private final List contacts = new ArrayList<>(); + private final List hints = new ArrayList<>(); + private final List foundedUsers = new ArrayList<>(); + private final Map> contactsMap = new HashMap<>(); + private final List contactsLetters = new ArrayList<>(); + private final HashMap allSelectedObjects = new LinkedHashMap<>(); + private String query; + private SelectorAdapter selectorAdapter; + private int listPaddingTop = AndroidUtilities.dp(56 + 64); + private int lastRequestId; + private float recipientsBtnExtraSpace; + private ReplacementSpan recipientsBtnSpaceSpan; + private int maxCount; + private SelectorListener selectorListener; + + private final Runnable remoteSearchRunnable = new Runnable() { + @Override + public void run() { + final String finalQuery = query; + if (finalQuery != null) { + loadData(finalQuery); + } + } + }; + + private void loadData(String query) { + lastRequestId = BoostRepository.searchContacts(lastRequestId, query, arg -> { + foundedUsers.clear(); + foundedUsers.addAll(arg); + updateList(true, true); + }); + } + + private void createRecipientsBtnSpaceSpan() { + recipientsBtnSpaceSpan = new ReplacementSpan() { + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return (int) recipientsBtnExtraSpace; + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + + } + }; + } + + public MultiContactsSelectorBottomSheet(BaseFragment fragment, boolean needFocus, int maxCount, SelectorListener selectorListener) { + super(fragment, needFocus, false, false, fragment.getResourceProvider()); + this.maxCount = maxCount; + this.selectorListener = selectorListener; + headerView = new SelectorHeaderCell(getContext(), resourcesProvider) { + @Override + protected int getHeaderHeight() { + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + return dp(48); + } else { + return dp(54); + } + } + }; + headerView.setOnCloseClickListener(this::dismiss); + headerView.setText(getTitle()); + headerView.setCloseImageVisible(false); + headerView.backDrawable.setRotation(0f, false); + + createRecipientsBtnSpaceSpan(); + + searchField = new SelectorSearchCell(getContext(), resourcesProvider, null) { + private boolean isKeyboardVisible; + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + listPaddingTop = getMeasuredHeight() + dp(64); + selectorAdapter.notifyChangedLast(); + if (isKeyboardVisible != isKeyboardVisible()) { + isKeyboardVisible = isKeyboardVisible(); + if (isKeyboardVisible) { + scrollToTop(true); + } + } + } + }; + searchField.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + searchField.setOnSearchTextChange(this::onSearch); + searchField.setHintText(LocaleController.getString("Search", R.string.Search), false); + + sectionCell = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + canvas.drawColor(getThemedColor(Theme.key_graySection)); + } + }; + + containerView.addView(headerView, 0, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + containerView.addView(searchField, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + containerView.addView(sectionCell, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, 1, Gravity.TOP | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + + buttonContainer = new SelectorBtnCell(getContext(), resourcesProvider, null); + buttonContainer.setClickable(true); + buttonContainer.setOrientation(LinearLayout.VERTICAL); + buttonContainer.setPadding(dp(10), dp(10), dp(10), dp(10)); + buttonContainer.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + actionButton = new ButtonWithCounterView(getContext(), resourcesProvider) { + @Override + protected float calculateCounterWidth(float width, float percent) { + boolean needUpdateActionBtn = recipientsBtnExtraSpace == 0; + recipientsBtnExtraSpace = width; + if (needUpdateActionBtn) { + createRecipientsBtnSpaceSpan(); + updateActionButton(false); + } + return width; + } + }; + actionButton.setOnClickListener(v -> next()); + buttonContainer.addView(actionButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); + containerView.addView(buttonContainer, LayoutHelper.createFrameMarginPx(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, backgroundPaddingLeft, 0, backgroundPaddingLeft, 0)); + + selectorAdapter.setData(items, recyclerListView); + recyclerListView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, dp(BOTTOM_HEIGHT_DP)); + recyclerListView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + AndroidUtilities.hideKeyboard(searchField.getEditText()); + } + } + }); + recyclerListView.setOnItemClickListener((view, position, x, y) -> { + if (view instanceof SelectorUserCell) { + TLRPC.User user = ((SelectorUserCell) view).getUser(); + long id = user.id; + if (selectedIds.contains(id)) { + selectedIds.remove(id); + } else { + selectedIds.add(id); + allSelectedObjects.put(id, user); + } + if (selectedIds.size() == maxCount + 1) { + selectedIds.remove(id); + showMaximumUsersToast(); + return; + } + searchField.updateSpans(true, selectedIds, () -> { + updateList(true, false); + }, null); + updateList(true, false); + clearSearchAfterSelect(); + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + recyclerListView.setItemAnimator(itemAnimator); + recyclerListView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); + if (position == items.size()) { + outRect.bottom = listPaddingTop; + } + } + }); + + searchField.setText(""); + searchField.spansContainer.removeAllSpans(false); + searchField.updateSpans(false, selectedIds, () -> { + updateList(true, false); + }, null); + headerView.setText(getTitle()); + updateActionButton(false); + + contacts.addAll(ContactsController.getInstance(currentAccount).contacts); + contactsMap.putAll(ContactsController.getInstance(currentAccount).usersSectionsDict); + contactsLetters.addAll(ContactsController.getInstance(currentAccount).sortedUsersSectionsArray); + hints.addAll(MediaDataController.getInstance(currentAccount).hints); + updateList(false, true); + fixNavigationBar(); + } + + @Override + protected void onPreDraw(Canvas canvas, int top, float progressToFullView) { + float minTop = AndroidUtilities.statusBarHeight + (headerView.getMeasuredHeight() - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(40)) / 2f; + float fromY = Math.max(top, minTop) + AndroidUtilities.dp(8); + headerView.setTranslationY(fromY); + searchField.setTranslationY(headerView.getTranslationY() + headerView.getMeasuredHeight()); + sectionCell.setTranslationY(searchField.getTranslationY() + searchField.getMeasuredHeight()); + recyclerListView.setTranslationY(headerView.getMeasuredHeight() + searchField.getMeasuredHeight() + sectionCell.getMeasuredHeight() - AndroidUtilities.dp(8)); + } + + private void next() { + if (selectedIds.size() == 0 || selectorListener == null) { + return; + } + List selectedUsers = new ArrayList<>(); + for (TLRPC.User object : allSelectedObjects.values()) { + if (selectedIds.contains(object.id)) { + selectedUsers.add(object.id); + } + } + selectorListener.onUserSelected(selectedUsers); + dismiss(); + } + + public void scrollToTop(boolean animate) { + if (animate) { + LinearSmoothScrollerCustom linearSmoothScroller = new LinearSmoothScrollerCustom(getContext(), LinearSmoothScrollerCustom.POSITION_TOP, .6f); + linearSmoothScroller.setTargetPosition(1); + linearSmoothScroller.setOffset(AndroidUtilities.dp(36)); + recyclerListView.getLayoutManager().startSmoothScroll(linearSmoothScroller); + } else { + recyclerListView.scrollToPosition(0); + } + } + + @Override + public void dismissInternal() { + super.dismissInternal(); + instance = null; + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + } + + private void showMaximumUsersToast() { + String text = LocaleController.formatPluralString("BotMultiContactsSelectorLimit", maxCount); + BulletinFactory.of(container, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, text).show(true); + try { + container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + } + } + + private void updateList(boolean animated, boolean notify) { + updateItems(animated, notify); + updateCheckboxes(animated); + updateActionButton(animated); + } + + private void updateCheckboxes(boolean animated) { + int visibleItemsFrom = -1; + int visibleItemsTo = 0; + for (int i = 0; i < recyclerListView.getChildCount(); ++i) { + View child = recyclerListView.getChildAt(i); + if (child instanceof SelectorUserCell) { + int position = recyclerListView.getChildAdapterPosition(child); + if (position <= 0) { + continue; + } + if (visibleItemsFrom == -1) { + visibleItemsFrom = position; + } + visibleItemsTo = position; + SelectorAdapter.Item item = items.get(position - 1); + SelectorUserCell cell = (SelectorUserCell) child; + cell.setChecked(item.checked, animated); + if (item.chat != null) { + cell.setCheckboxAlpha(selectorAdapter.getParticipantsCount(item.chat) > 200 ? .3f : 1f, animated); + } else { + cell.setCheckboxAlpha(1f, animated); + } + } + } + if (animated) { + selectorAdapter.notifyItemRangeChanged(0, visibleItemsFrom); + selectorAdapter.notifyItemRangeChanged(visibleItemsTo, selectorAdapter.getItemCount() - visibleItemsTo); + } + } + + private void updateActionButton(boolean animated) { + actionButton.setShowZero(false); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + if (selectedIds.size() == 0) { + stringBuilder.append("d").setSpan(recipientsBtnSpaceSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.append(LocaleController.getString("ChooseUsers", R.string.ChooseUsers)); + } else { + stringBuilder.append(LocaleController.getString("GiftPremiumProceedBtn", R.string.GiftPremiumProceedBtn)); + } + actionButton.setCount(selectedIds.size(), true); + actionButton.setText(stringBuilder, animated, false); + actionButton.setEnabled(true); + } + + private void onSearch(String text) { + this.query = text; + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + AndroidUtilities.runOnUIThread(remoteSearchRunnable, 350); + } + + private void clearSearchAfterSelect() { + if (isSearching()) { + query = null; + searchField.setText(""); + AndroidUtilities.cancelRunOnUIThread(remoteSearchRunnable); + updateItems(true, true); + } + } + + private void updateSectionCell(boolean animated) { + if (selectedIds == null) { + return; + } + if (selectedIds.size() > 0) { + selectorAdapter.setTopSectionClickListener(v -> { + selectedIds.clear(); + searchField.spansContainer.removeAllSpans(true); + updateList(true, false); + }); + } else { + selectorAdapter.setTopSectionClickListener(null); + } + } + + private boolean isSearching() { + return !TextUtils.isEmpty(query); + } + + @SuppressLint("NotifyDataSetChanged") + public void updateItems(boolean animated, boolean notify) { + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + + int h = 0; + if (isSearching()) { + for (TLRPC.User foundedUser : foundedUsers) { + h += dp(56); + items.add(SelectorAdapter.Item.asUser(foundedUser, selectedIds.contains(foundedUser.id))); + } + } else { + if (!hints.isEmpty()) { + List userItems = new ArrayList<>(); + for (TLRPC.TL_topPeer hint : hints) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(hint.peer.user_id); + if (user.self || user.bot || UserObject.isService(user.id) || UserObject.isDeleted(user)) { + continue; + } + h += dp(56); + userItems.add(SelectorAdapter.Item.asUser(user, selectedIds.contains(user.id))); + } + if (!userItems.isEmpty()) { + h += dp(32); + items.add(SelectorAdapter.Item.asTopSection(LocaleController.getString("GiftPremiumFrequentContacts", R.string.GiftPremiumFrequentContacts))); + items.addAll(userItems); + } + } + for (String contactLetter : contactsLetters) { + List userItems = new ArrayList<>(); + for (TLRPC.TL_contact contact : contactsMap.get(contactLetter)) { + long myUid = UserConfig.getInstance(currentAccount).getClientUserId(); + if (contact.user_id == myUid) { + continue; + } + h += dp(56); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(contact.user_id); + userItems.add(SelectorAdapter.Item.asUser(user, selectedIds.contains(user.id))); + } + + if (!userItems.isEmpty()) { + h += dp(32); + items.add(SelectorAdapter.Item.asLetter(contactLetter.toUpperCase())); + items.addAll(userItems); + } + } + } + + if (items.isEmpty()) { + items.add(SelectorAdapter.Item.asNoUsers()); + h += dp(150); + } + int minHeight = (int) (AndroidUtilities.displaySize.y * 0.6f); + items.add(SelectorAdapter.Item.asPad(Math.max(0, minHeight - h))); + + updateSectionCell(animated); + + if (notify && selectorAdapter != null) { + if (animated) { + selectorAdapter.setItems(oldItems, items); + } else { + selectorAdapter.notifyDataSetChanged(); + } + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateItems(false, true); + } + + @Override + protected CharSequence getTitle() { + return LocaleController.getString("ChooseUsers", R.string.ChooseUsers); + } + + @Override + protected RecyclerListView.SelectionAdapter createAdapter() { + selectorAdapter = new SelectorAdapter(getContext(), resourcesProvider); + selectorAdapter.setGreenSelector(true); + return selectorAdapter; + } + + @Override + public void dismiss() { + AndroidUtilities.hideKeyboard(searchField.getEditText()); + super.dismiss(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 930f861f8..ccc48d02b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -253,6 +253,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen private boolean loadingPasswordInfo; private PaymentFormActivity passwordFragment; + private String overrideSmartGlocalConnectionUrl; private boolean need_card_country; private boolean need_card_postcode; private boolean need_card_name; @@ -1764,7 +1765,7 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen }); if (a == FIELD_SAVEDPASSWORD) { bottomCell[0] = new TextInfoPrivacyCell(context, resourcesProvider); - bottomCell[0].setText(LocaleController.formatString("PaymentConfirmationMessage", R.string.PaymentConfirmationMessage, savedCredentialsCard.title)); + bottomCell[0].setText(LocaleController.formatString("PaymentConfirmationMessage", R.string.PaymentConfirmationMessage, savedCredentialsCard == null ? "" : savedCredentialsCard.title)); bottomCell[0].setBackgroundDrawable(Theme.getThemedDrawableByKey(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); linearLayout2.addView(bottomCell[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -3775,8 +3776,23 @@ public class PaymentFormActivity extends BaseFragment implements NotificationCen cardObject.put("security_code", "" + card.getCVC()); jsonObject.put("card", cardObject); + String overrideSmartGlocalConnectionUrl = null; + if (paymentForm.native_params != null) { + try { + JSONObject jsonObject2 = new JSONObject(paymentForm.native_params.data); + overrideSmartGlocalConnectionUrl = jsonObject2.getString("tokenize_url"); + if (overrideSmartGlocalConnectionUrl != null && ( + !overrideSmartGlocalConnectionUrl.startsWith("https://") || + overrideSmartGlocalConnectionUrl.endsWith(".smart-glocal.com/cds/v1/tokenize/card") + )) { + overrideSmartGlocalConnectionUrl = null; + } + } catch (Exception e) {} + } URL connectionUrl; - if (paymentForm.invoice.test) { + if (overrideSmartGlocalConnectionUrl != null) { + connectionUrl = new URL(overrideSmartGlocalConnectionUrl); + } else if (paymentForm.invoice.test) { connectionUrl = new URL("https://tgb-playground.smart-glocal.com/cds/v1/tokenize/card"); } else { connectionUrl = new URL("https://tgb.smart-glocal.com/cds/v1/tokenize/card"); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java index 01868fc12..bdbb25a60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java @@ -2,7 +2,6 @@ package org.telegram.ui; import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; -import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -29,8 +28,11 @@ import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ReplacementSpan; import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; @@ -48,11 +50,15 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.common.io.CharSource; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ChatThemeController; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -88,9 +94,11 @@ import org.telegram.ui.Components.FilledTabsView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SimpleThemeDescription; +import org.telegram.ui.Components.SpannableStringLight; import org.telegram.ui.Components.Text; import org.telegram.ui.Components.ViewPagerFixed; import org.telegram.ui.Stories.StoriesUtilities; @@ -221,22 +229,25 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente view = cell; break; case VIEW_TYPE_COLOR_PICKER: - PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(getContext(), type, currentAccount); + PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(getContext(), type, currentAccount, resourceProvider); colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); - colorPicker.setSelected(selectedColor); + colorPicker.setSelected(selectedColor, false); colorPicker.setOnColorClick(colorId -> { selectedColor = colorId; - colorPicker.setSelected(colorId); + colorPicker.setSelected(colorId, true); updateMessages(); if (setReplyIconCell != null) { setReplyIconCell.invalidate(); } if (type == PAGE_PROFILE && colorBar != null) { - colorBar.setColor(selectedColor, true); + colorBar.setColor(currentAccount, selectedColor, true); } if (profilePreview != null) { profilePreview.setColor(selectedColor, true); } + if (profilePage != null && profilePage.profilePreview != null && namePage != null) { + profilePage.profilePreview.overrideAvatarColor(namePage.selectedColor); + } checkResetColorButton(); }); view = colorPicker; @@ -341,7 +352,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente selectedColor = -1; selectedEmoji = 0; if (peerColorPicker != null) { - peerColorPicker.setSelected(selectedColor); + peerColorPicker.setSelected(selectedColor, true); } updateMessages(); if (type == PAGE_PROFILE) { @@ -351,12 +362,15 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente setReplyIconCell.update(true); } if (type == PAGE_PROFILE && colorBar != null) { - colorBar.setColor(selectedColor, true); + colorBar.setColor(currentAccount, selectedColor, true); } if (profilePreview != null) { profilePreview.setColor(selectedColor, true); profilePreview.setEmoji(selectedEmoji, true); } + if (profilePage != null && profilePage.profilePreview != null && namePage != null) { + profilePage.profilePreview.overrideAvatarColor(namePage.selectedColor); + } checkResetColorButton(); } }); @@ -392,7 +406,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente listView.setItemAnimator(itemAnimator); if (type == PAGE_PROFILE) { - profilePreview = new ProfilePreview(getContext()); + profilePreview = new ProfilePreview(getContext(), currentAccount, dialogId, resourceProvider); profilePreview.setColor(selectedColor, false); profilePreview.setEmoji(selectedEmoji, false); addView(profilePreview, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); @@ -490,7 +504,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } else { textView.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileIcon : R.string.UserProfileIcon)); } - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 48, 0)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 20, 0)); imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); } @@ -513,10 +527,10 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente public void updateImageBounds() { imageDrawable.setBounds( - getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), - (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, - getWidth() - dp(21), - (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 + LocaleController.isRTL ? dp(21) : getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), + (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, + LocaleController.isRTL ? dp(21) + imageDrawable.getIntrinsicWidth() : getWidth() - dp(21), + (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 ); } @@ -636,7 +650,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente selectAnimatedEmojiDialog = null; } }; - popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); + popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); popup[0].dimBehind(); } @@ -681,11 +695,6 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente if (peerColorPicker != null) { msg.overrideLinkColor = peerColorPicker.getColorId(); } - if (profilePage != null && profilePage.selectedColor >= 0 && getMessagesController().profilePeerColors != null) { - msg.overrideProfilePeerColor = getMessagesController().profilePeerColors.getColor(profilePage.selectedColor); - } else { - msg.overrideProfilePeerColor = null; - } msg.overrideLinkEmoji = selectedEmoji; cells[i].setAvatar(msg); cells[i].invalidate(); @@ -698,7 +707,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente public void updateColors() { listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); if (type == PAGE_PROFILE && colorBar != null) { - colorBar.setColor(selectedColor, true); + colorBar.setColor(currentAccount, selectedColor, true); } if (button != null) { button.updateColors(); @@ -774,19 +783,17 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente currentColors.put(i, defaultColors[i]); } } - if (themeColors != null) { - for (int i = 0; i < themeColors.size(); ++i) { - currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); - } + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } + Theme.ThemeAccent accent = themeInfo.getAccent(false); + if (accent != null) { + accent.fillAccentColors(themeColors, currentColors); } if (namePage != null && namePage.messagesCellPreview != null) { - if (Theme.isCurrentThemeDark() == isDark) { - namePage.messagesCellPreview.setOverrideBackground(null); - } else { - Theme.BackgroundDrawableSettings bg = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink[0], 0, true); - namePage.messagesCellPreview.setOverrideBackground(bg.themedWallpaper != null ? bg.themedWallpaper : bg.wallpaper); - } + Theme.BackgroundDrawableSettings bg = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink[0], 0, true); + namePage.messagesCellPreview.setOverrideBackground(bg.themedWallpaper != null ? bg.themedWallpaper : bg.wallpaper); } } @@ -906,9 +913,33 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente }; frameLayout.setFitsSystemWindows(true); - colorBar = new ColoredActionBar(context); + colorBar = new ColoredActionBar(context, resourceProvider) { + @Override + protected void onUpdateColor() { + updateLightStatusBar(); + updateActionBarButtonsColor(); + if (tabsView != null) { + tabsView.setBackgroundColor(getTabsViewBackgroundColor()); + } + } + + private int lastBtnColor = 0; + public void updateActionBarButtonsColor() { + final int btnColor = getActionBarButtonColor(); + if (lastBtnColor != btnColor) { + if (backButton != null) { + lastBtnColor = btnColor; + backButton.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); + } + if (dayNightItem != null) { + lastBtnColor = btnColor; + dayNightItem.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); + } + } + } + }; if (profilePage != null) { - colorBar.setColor(profilePage.selectedColor, false); + colorBar.setColor(currentAccount, profilePage.selectedColor, false); } frameLayout.addView(colorBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); @@ -922,7 +953,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente viewPager.setAdapter(new ViewPagerFixed.Adapter() { @Override public int getItemCount() { - return isChannel ? 1 : 2; + return 2; } @Override @@ -961,20 +992,22 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente actionBarContainer.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.CENTER)); } else { titleView = new SimpleTextView(context); - titleView.setText(LocaleController.getString(R.string.ChannelColorTitle)); + titleView.setText(LocaleController.getString(R.string.ChannelColorTitle2)); titleView.setEllipsizeByGradient(true); titleView.setTextSize(20); titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); actionBarContainer.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT, 72, 0, 72, 0)); } - if (startAtProfile && !isChannel) { + + if (startAtProfile) { viewPager.setPosition(1); if (tabsView != null) { tabsView.setSelected(1); } if (colorBar != null) { colorBar.setProgressToGradient(1f); + updateLightStatusBar(); } } @@ -1031,39 +1064,13 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente return namePage.hasUnsavedChanged() || profilePage.hasUnsavedChanged(); } - private void showBoostLimit(boolean error) { - getMessagesController().getBoostsController().getBoostsStats(dialogId, boostsStatus -> { - if (error || boostsStatus.level < getMessagesController().channelColorLevelMin) { - getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { - if (getContext() == null) { - return; - } - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_COLOR, currentAccount, getResourceProvider()); - limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); - - limitReachedBottomSheet.setBoostsStats(boostsStatus, true); - limitReachedBottomSheet.setDialogId(dialogId); - limitReachedBottomSheet.showStatisticButtonInLink(() -> { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); - }); - showDialog(limitReachedBottomSheet); - loading = false; - AndroidUtilities.runOnUIThread(() -> getCurrentPage().button.setLoading(false), 300); - }); - } else { - apply(); - } - }); + private void setLoading(boolean loading) { + if (namePage != null && namePage.button != null) { + namePage.button.setLoading(loading); + } + if (profilePage != null && profilePage.button != null) { + profilePage.button.setLoading(loading); + } } @Override @@ -1106,15 +1113,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente return; } if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (namePage != null && chat != null && namePage.selectedColor == ChatObject.getColorId(chat) && namePage.selectedEmoji == ChatObject.getEmojiId(chat)) { - finishFragment(); - return; - } - loading = true; - getCurrentPage().button.setLoading(true); - showBoostLimit(false); - return; + finishFragment(); } else { if (!getUserConfig().isPremium()) { showDialog(new PremiumFeatureBottomSheet(PeerColorActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_NAME_COLOR, true)); @@ -1135,46 +1134,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat == null) { - return; - } - if (namePage.selectedColor == ChatObject.getColorId(chat) && namePage.selectedEmoji == ChatObject.getEmojiId(chat)) { - getCurrentPage().button.setLoading(loading = false); - finishFragment(); - return; - } - TLRPC.TL_channels_updateColor req = new TLRPC.TL_channels_updateColor(); - req.channel = getMessagesController().getInputChannel(-dialogId); - if (req.channel == null) { - return; - } - chat.flags2 |= 64; - if (chat.color == null) { - chat.color = new TLRPC.TL_peerColor(); - } - chat.flags2 |= 128; - req.color = chat.color.color = namePage.selectedColor; - if (namePage.selectedEmoji != 0) { - chat.color.background_emoji_id = namePage.selectedEmoji; - - req.flags |= 1; - req.background_emoji_id = namePage.selectedEmoji; - } else { - chat.color.background_emoji_id = 0; - } - getCurrentPage().button.setLoading(loading = true); - getMessagesController().putChat(chat, false); - getUserConfig().saveConfig(true); - getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { - applying = false; - if (err != null && "BOOSTS_REQUIRED".equals(err.text)) { - showBoostLimit(true); - } else { - finishFragment(); - showBulletin(); - } - })); + finishFragment(); } else { final TLRPC.User me = getUserConfig().getCurrentUser(); if (me.color == null) { @@ -1225,6 +1185,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } getMessagesController().putUser(me, false); getUserConfig().saveConfig(true); + finishFragment(); + showBulletin(); } applying = true; getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_EMOJI_STATUS); @@ -1320,6 +1282,67 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } + public static class LevelLock extends Drawable { + + private final Theme.ResourcesProvider resourcesProvider; + private final Text text; + private final float lockScale = .875f; + private final Drawable lock; + private final PremiumGradient.PremiumGradientTools gradientTools; + + public LevelLock(Context context, int lvl, Theme.ResourcesProvider resourcesProvider) { + this(context, false, lvl, resourcesProvider); + } + + public LevelLock(Context context, boolean plus, int lvl, Theme.ResourcesProvider resourcesProvider) { + this.resourcesProvider = resourcesProvider; + text = new Text(LocaleController.formatPluralString(plus ? "BoostLevelPlus" : "BoostLevel", lvl), 12, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + lock = context.getResources().getDrawable(R.drawable.mini_switch_lock).mutate(); + lock.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, -1, -1, -1, resourcesProvider); + } + + @Override + public void draw(@NonNull Canvas canvas) { + int left = getBounds().left; + int cy = getBounds().centerY(); + + AndroidUtilities.rectTmp.set(left, cy - getIntrinsicHeight() / 2f, left + getIntrinsicWidth(), cy + getIntrinsicHeight() / 2f); + gradientTools.gradientMatrix(AndroidUtilities.rectTmp); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(10), dp(10), gradientTools.paint); + + lock.setBounds( + left + dp(3.33f), + (int) (cy - lock.getIntrinsicHeight() * lockScale / 2f), + (int) (left + dp(3.33f) + lock.getIntrinsicWidth() * lockScale), + (int) (cy + lock.getIntrinsicHeight() * lockScale / 2f) + ); + lock.draw(canvas); + + text.draw(canvas, left + dp(3.66f) + lock.getIntrinsicWidth() * lockScale, cy, Color.WHITE, 1f); + } + + @Override + public void setAlpha(int alpha) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return (int) (dp(3.66f + 6) + lock.getIntrinsicWidth() * lockScale + text.getWidth()); + } + + @Override + public int getIntrinsicHeight() { + return dp(18.33f); + } + } + public static class ChangeNameColorCell extends View { private final int currentAccount; private final boolean isChannel; @@ -1327,6 +1350,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private final Drawable drawable; private final Text buttonText; + private LevelLock lock; private final Paint userTextBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Text userText; @@ -1336,16 +1360,51 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private PeerColorDrawable color1Drawable; private PeerColorDrawable color2Drawable; - public ChangeNameColorCell(int currentAccount, boolean isChannel, Context context, Theme.ResourcesProvider resourcesProvider) { + public ChangeNameColorCell(int currentAccount, long dialogId, Context context, Theme.ResourcesProvider resourcesProvider) { super(context); this.currentAccount = currentAccount; - this.isChannel = isChannel; + this.isChannel = dialogId < 0; this.resourcesProvider = resourcesProvider; drawable = context.getResources().getDrawable(R.drawable.msg_palette).mutate(); drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), PorterDuff.Mode.SRC_IN)); - buttonText = new Text(LocaleController.getString(isChannel ? R.string.ChangeChannelNameColor : R.string.ChangeUserNameColor), 16); + CharSequence button = LocaleController.getString(isChannel ? R.string.ChangeChannelNameColor2 : R.string.ChangeUserNameColor); + if (isChannel && MessagesController.getInstance(currentAccount).getMainSettings().getInt("boostingappearance", 0) < 3) { + MessagesController mc = MessagesController.getInstance(currentAccount); + int minlvl = Integer.MAX_VALUE, maxlvl = 0; + if (mc.peerColors != null) { + minlvl = Math.min(minlvl, mc.peerColors.maxLevel()); + maxlvl = Math.max(maxlvl, mc.peerColors.maxLevel()); + minlvl = Math.min(minlvl, mc.peerColors.minLevel()); + maxlvl = Math.max(maxlvl, mc.peerColors.minLevel()); + } + minlvl = Math.min(minlvl, mc.channelBgIconLevelMin); + maxlvl = Math.min(maxlvl, mc.channelBgIconLevelMin); + if (mc.profilePeerColors != null) { + minlvl = Math.min(minlvl, mc.profilePeerColors.maxLevel()); + maxlvl = Math.max(maxlvl, mc.profilePeerColors.maxLevel()); + minlvl = Math.min(minlvl, mc.profilePeerColors.minLevel()); + maxlvl = Math.max(maxlvl, mc.profilePeerColors.minLevel()); + } + minlvl = Math.min(minlvl, mc.channelProfileIconLevelMin); + maxlvl = Math.max(maxlvl, mc.channelProfileIconLevelMin); + minlvl = Math.min(minlvl, mc.channelEmojiStatusLevelMin); + maxlvl = Math.max(maxlvl, mc.channelEmojiStatusLevelMin); + minlvl = Math.min(minlvl, mc.channelWallpaperLevelMin); + maxlvl = Math.max(maxlvl, mc.channelWallpaperLevelMin); + minlvl = Math.min(minlvl, mc.channelCustomWallpaperLevelMin); + maxlvl = Math.max(maxlvl, mc.channelCustomWallpaperLevelMin); + TLRPC.Chat chat = mc.getChat(-dialogId); + int currentLevel = chat == null ? 0 : chat.level; + if (currentLevel < maxlvl) { + lock = new LevelLock(context, true, Math.max(currentLevel, minlvl), resourcesProvider); + } + } + if (isChannel && lock == null) { + button = TextCell.applyNewSpan(button); + } + buttonText = new Text(button, 16); updateColors(); } @@ -1385,7 +1444,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); - color1Drawable = color2Drawable = null; + color1Drawable = PeerColorDrawable.from(currentAccount, colorId).setRadius(dp(11)); + color2Drawable = ChatObject.getProfileColorId(chat) >= 0 ? PeerColorDrawable.fromProfile(currentAccount, ChatObject.getProfileColorId(chat)).setRadius(dp(11)) : null; } public void set(TLRPC.User user) { @@ -1442,13 +1502,18 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente getMeasuredHeight() / 2 + drawable.getIntrinsicHeight() / 2 ); drawable.draw(canvas); - buttonText - .ellipsize(getMeasuredWidth() - dp(64 + 7 + 100)) - .draw(canvas, LocaleController.isRTL ? getMeasuredWidth() - buttonText.getWidth() - dp(64 + 7) : dp(64 + 7), getMeasuredHeight() / 2f); + buttonText.ellipsize(getMeasuredWidth() - dp(64 + 7 + 100) - (lock != null ? lock.getIntrinsicWidth() + dp(8) : 0)); + float textX = LocaleController.isRTL ? getMeasuredWidth() - buttonText.getWidth() - dp(64 + 7) : dp(64 + 7); + buttonText.draw(canvas, textX, getMeasuredHeight() / 2f); + if (lock != null) { + int x = (int) (textX + buttonText.getWidth() + dp(6)); + lock.setBounds(x, 0, x, getHeight()); + lock.draw(canvas); + } if (color1Drawable != null && color2Drawable != null) { - int x = getMeasuredWidth() - dp(16); + int x = LocaleController.isRTL ? dp(24 + 16 + 18) : getMeasuredWidth() - dp(24); color2Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); color2Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); color2Drawable.draw(canvas); @@ -1459,7 +1524,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente color1Drawable.draw(canvas); } else if (userText != null) { - final int maxWidth = (int) (getMeasuredWidth() - dp(64 + 7 + 15 + 9 + 9 + 12) - Math.min(buttonText.getWidth(), getMeasuredWidth() - dp(64 + 100))); + final int maxWidth = (int) (getMeasuredWidth() - dp(64 + 7 + 15 + 9 + 9 + 12) - Math.min(buttonText.getWidth() + (lock == null ? 0 : lock.getIntrinsicWidth() + dp(6 + 6)), getMeasuredWidth() - dp(64 + 100))); final int w = (int) Math.min(userText.getWidth(), maxWidth); AndroidUtilities.rectTmp.set( @@ -1485,7 +1550,8 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } - public class PeerColorGrid extends View { + public static class PeerColorGrid extends View { + private final Theme.ResourcesProvider resourcesProvider; private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); { backgroundPaint.setStyle(Paint.Style.STROKE); } @@ -1517,21 +1583,21 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente if (color == null) { return; } - final boolean dark = isDark; + final boolean dark = resourcesProvider == null ? Theme.isCurrentThemeDark() : resourcesProvider.isDark(); if (type == PAGE_NAME) { if (dark && color.hasColor2() && !color.hasColor3()) { - paint1.setColor(color.getColor2(dark)); - paint2.setColor(color.getColor1(dark)); + paint1.setColor(color.getColor(1, resourcesProvider)); + paint2.setColor(color.getColor(0, resourcesProvider)); } else { - paint1.setColor(color.getColor1(dark)); - paint2.setColor(color.getColor2(dark)); + paint1.setColor(color.getColor(0, resourcesProvider)); + paint2.setColor(color.getColor(1, resourcesProvider)); } - paint3.setColor(color.getColor3(dark)); + paint3.setColor(color.getColor(2, resourcesProvider)); hasColor2 = color.hasColor2(dark); hasColor3 = color.hasColor3(dark); } else { - paint1.setColor(color.getColor1(dark)); - paint2.setColor(color.hasColor6(dark) ? color.getColor2(dark) : color.getColor1(dark)); + paint1.setColor(color.getColor(0, resourcesProvider)); + paint2.setColor(color.hasColor6(dark) ? color.getColor(1, resourcesProvider) : color.getColor(0, resourcesProvider)); hasColor2 = color.hasColor6(dark); hasColor3 = false; } @@ -1595,7 +1661,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente if (selectT > 0) { backgroundPaint.setStrokeWidth(dpf2(2)); - backgroundPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhite)); + backgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); canvas.drawCircle( bounds.centerX(), bounds.centerY(), Math.min(bounds.height() / 2f, bounds.width() / 2f) + backgroundPaint.getStrokeWidth() * AndroidUtilities.lerp(.5f, -2f, selectT), @@ -1621,10 +1687,11 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private ColorButton[] buttons; - public PeerColorGrid(Context context, int type, int currentAccount) { + public PeerColorGrid(Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(context); this.type = type; this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; } public void updateColors() { @@ -1634,9 +1701,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente for (int i = 0; i < buttons.length; ++i) { if (i < 7 && type == PAGE_NAME) { buttons[i].id = order[i]; - buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]], resourceProvider)); + buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]], resourcesProvider)); } else { - final int id = i - (type == PAGE_NAME ? 7 : 0); + final int id = i; if (peerColors != null && id >= 0 && id < peerColors.colors.size()) { buttons[i].id = peerColors.colors.get(id).id; buttons[i].set(peerColors.colors.get(id)); @@ -1653,7 +1720,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente final MessagesController mc = MessagesController.getInstance(currentAccount); final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; - final int colorsCount = 7 + (peerColors == null ? 0 : peerColors.colors.size()); + final int colorsCount = peerColors == null ? 0 : peerColors.colors.size(); final int columns = type == PAGE_NAME ? 7 : 8; final float iconSize = Math.min(dp(38 + 16), width / (columns + (columns + 1) * .28947f)); @@ -1669,15 +1736,9 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente buttons = new ColorButton[colorsCount]; for (int i = 0; i < colorsCount; ++i) { buttons[i] = new ColorButton(); - if (i < 7 && type == PAGE_NAME) { - buttons[i].id = order[i]; - buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]])); - } else { - final int id = i - (type == PAGE_NAME ? 7 : 0); - if (peerColors != null && id >= 0 && id < peerColors.colors.size()) { - buttons[i].id = peerColors.colors.get(id).id; - buttons[i].set(peerColors.colors.get(id)); - } + if (peerColors != null && i >= 0 && i < peerColors.colors.size()) { + buttons[i].id = peerColors.colors.get(i).id; + buttons[i].set(peerColors.colors.get(i)); } } } @@ -1703,6 +1764,11 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private boolean needDivider = true; + public void setDivider(boolean needDivider) { + this.needDivider = needDivider; + invalidate(); + } @Override protected void dispatchDraw(Canvas canvas) { @@ -1711,16 +1777,18 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente buttons[i].draw(canvas); } } - dividerPaint.setColor(getThemedColor(Theme.key_divider)); - canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), dividerPaint); + if (needDivider) { + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), dividerPaint); + } } private int selectedColorId = 0; - public void setSelected(int colorId) { + public void setSelected(int colorId, boolean animated) { selectedColorId = colorId; if (buttons != null) { for (int i = 0; i < buttons.length; ++i) { - buttons[i].setSelected(buttons[i].id == colorId, true); + buttons[i].setSelected(buttons[i].id == colorId, animated); } } } @@ -1785,6 +1853,37 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } + public static class PeerColorSpan extends ReplacementSpan { + private int size = dp(21); + public PeerColorDrawable drawable; + + public PeerColorSpan(boolean profile, int currentAccount, int colorId) { + drawable = profile ? PeerColorDrawable.fromProfile(currentAccount, colorId) : PeerColorDrawable.from(currentAccount, colorId); + } + + public PeerColorSpan setSize(int sz) { + if (drawable != null) { + drawable.setRadius(sz / 2f); + size = sz; + } + return this; + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return dp(3) + size + dp(3); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + if (drawable != null) { + int cy = (top + bottom) / 2; + drawable.setBounds((int) (x + dp(3)), cy - size, (int) (x + dp(5) + size), cy + size); + drawable.draw(canvas); + } + } + } + public static class PeerColorDrawable extends Drawable { public static PeerColorDrawable from(int currentAccount, int colorId) { @@ -1894,37 +1993,39 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } - private class ColoredActionBar extends View { + public static class ColoredActionBar extends View { private int defaultColor; - public ColoredActionBar(Context context) { + private final Theme.ResourcesProvider resourcesProvider; + + public ColoredActionBar(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); - defaultColor = getThemedColor(Theme.key_actionBarDefault); - setColor(-1, false); + this.resourcesProvider = resourcesProvider; + defaultColor = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); + setColor(-1, -1, false); } - public void setColor(int colorId, boolean animated) { + public void setColor(int currentAccount, int colorId, boolean animated) { isDefault = false; - if (colorId < 0) { + if (colorId < 0 || currentAccount < 0) { isDefault = true; - color1 = color2 = getThemedColor(Theme.key_actionBarDefault); + color1 = color2 = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); } else { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); if (peerColor != null) { + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); color1 = peerColor.getBgColor1(isDark); color2 = peerColor.getBgColor2(isDark); } else { isDefault = true; - color1 = color2 = getThemedColor(Theme.key_actionBarDefault); + color1 = color2 = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); } } if (!animated) { color1Animated.set(color1, true); color2Animated.set(color2, true); } - updateLightStatusBar(); - updateActionBarButtonsColor(); invalidate(); } @@ -1932,9 +2033,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente public void setProgressToGradient(float progress) { if (Math.abs(progressToGradient - progress) > 0.001f) { progressToGradient = progress; - updateTabsViewBackground(); - updateActionBarButtonsColor(); - updateLightStatusBar(); + onUpdateColor(); invalidate(); } } @@ -1948,6 +2047,10 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private LinearGradient backgroundGradient; private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + protected void onUpdateColor() { + + } + @Override protected void dispatchDraw(Canvas canvas) { final int color1 = color1Animated.set(this.color1); @@ -1955,8 +2058,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente if (backgroundGradient == null || backgroundGradientColor1 != color1 || backgroundGradientColor2 != color2 || backgroundGradientHeight != getHeight()) { backgroundGradient = new LinearGradient(0, 0, 0, backgroundGradientHeight = getHeight(), new int[] { backgroundGradientColor2 = color2, backgroundGradientColor1 = color1 }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); backgroundPaint.setShader(backgroundGradient); - updateTabsViewBackground(); - updateLightStatusBar(); + onUpdateColor(); } if (progressToGradient < 1) { canvas.drawColor(defaultColor); @@ -1967,47 +2069,35 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } + protected boolean ignoreMeasure; + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.statusBarHeight + dp(144), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, ignoreMeasure ? heightMeasureSpec : MeasureSpec.makeMeasureSpec(AndroidUtilities.statusBarHeight + dp(144), MeasureSpec.EXACTLY)); } public void updateColors() { - defaultColor = getThemedColor(Theme.key_actionBarDefault); - updateTabsViewBackground(); - updateActionBarButtonsColor(); - updateLightStatusBar(); + defaultColor = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); + onUpdateColor(); invalidate(); } - - private int lastBtnColor = 0; - public void updateActionBarButtonsColor() { - final int btnColor = ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), isDefault ? getThemedColor(Theme.key_actionBarDefaultIcon) : Color.WHITE, progressToGradient); - if (lastBtnColor != btnColor) { - if (backButton != null) { - lastBtnColor = btnColor; - backButton.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); - } - if (dayNightItem != null) { - lastBtnColor = btnColor; - dayNightItem.setColorFilter(new PorterDuffColorFilter(btnColor, PorterDuff.Mode.SRC_IN)); - } - } - } public int getColor() { - return ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefault), ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), progressToGradient); + return ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider), ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), progressToGradient); } - private void updateTabsViewBackground() { - if (tabsView == null) return; - tabsView.setBackgroundColor( + public int getActionBarButtonColor() { + return ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultIcon, resourcesProvider), isDefault ? Theme.getColor(Theme.key_actionBarDefaultIcon, resourcesProvider) : Color.WHITE, progressToGradient); + } + + public int getTabsViewBackgroundColor() { + return ( ColorUtils.blendARGB( - AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .721f ? - getThemedColor(Theme.key_actionBarDefaultIcon) : - Theme.adaptHSV(getThemedColor(Theme.key_actionBarDefault), +.08f, -.08f), + AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider)) > .721f ? + Theme.getColor(Theme.key_actionBarDefaultIcon, resourcesProvider) : + Theme.adaptHSV(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider), +.08f, -.08f), AndroidUtilities.computePerceivedBrightness(ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f)) > .721f ? - getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon) : + Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon, resourcesProvider) : Theme.adaptHSV(ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), +.08f, -.08f), progressToGradient ) @@ -2015,20 +2105,47 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } } - private class ProfilePreview extends FrameLayout { + public static class ProfilePreview extends FrameLayout { + + private final Theme.ResourcesProvider resourcesProvider; + private final int currentAccount; + private final long dialogId; + private final boolean isChannel; private final ImageReceiver imageReceiver = new ImageReceiver(this); private final AvatarDrawable avatarDrawable = new AvatarDrawable(); private final SimpleTextView titleView, subtitleView; + private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable statusEmoji; + private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(20), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); private final StoriesUtilities.StoryGradientTools storyGradient = new StoriesUtilities.StoryGradientTools(this, false); - public ProfilePreview(Context context) { + public ProfilePreview(Context context, int currentAccount, long dialogId, Theme.ResourcesProvider resourcesProvider) { super(context); - titleView = new SimpleTextView(context); + this.currentAccount = currentAccount; + this.dialogId = dialogId; + this.resourcesProvider = resourcesProvider; + this.isChannel = dialogId < 0; + + titleView = new SimpleTextView(context) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + statusEmoji.attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + statusEmoji.detach(); + } + }; + statusEmoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(titleView, true, dp(24)); + titleView.setDrawablePadding(dp(8)); + titleView.setRightDrawable(statusEmoji); titleView.setTextColor(0xFFFFFFFF); titleView.setTextSize(20); titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); @@ -2092,18 +2209,26 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente setWillNotDraw(false); } - public void updateAvatarDrawable(MessagesController.PeerColor profilePeerColor) { - if (isChannel) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - if (chat != null) { - avatarDrawable.setInfo(chat.id, chat.title, null, null, ChatObject.getColorId(chat), profilePeerColor); + public void overrideAvatarColor(int colorId) { + final int color1, color2; + if (colorId >= 14) { + MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); + MessagesController.PeerColors peerColors = messagesController != null ? messagesController.peerColors : null; + MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; + if (peerColor != null) { + final int peerColorValue = peerColor.getColor1(); + color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getPeerColorIndex(peerColorValue)]); + color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getPeerColorIndex(peerColorValue)]); + } else { + color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(colorId)]); + color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(colorId)]); } } else { - TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); - if (user != null) { - avatarDrawable.setInfo(user.id, user.first_name, user.last_name, null, UserObject.getColorId(user), profilePeerColor); - } + color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(colorId)]); + color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(colorId)]); } + avatarDrawable.setColor(color1, color2); + invalidate(); } @Override @@ -2120,12 +2245,18 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente imageReceiver.onDetachedFromWindow(); } + private int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } + private int lastColorId = -1; public void setColor(int colorId, boolean animated) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId = colorId); + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); if (peerColor != null) { emoji.setColor(adaptProfileEmojiColor(peerColor.getBgColor1(isDark))); + statusEmoji.setColor(ColorUtils.blendARGB(peerColor.getColor(1, resourcesProvider), peerColor.hasColor6(isDark) ? peerColor.getColor(4, resourcesProvider) : peerColor.getColor(2, resourcesProvider), .5f)); final int accentColor = ColorUtils.blendARGB(peerColor.getStoryColor1(isDark), peerColor.getStoryColor2(isDark), .5f); if (!Theme.hasHue(getThemedColor(Theme.key_actionBarDefault))) { subtitleView.setTextColor(accentColor); @@ -2134,17 +2265,18 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } titleView.setTextColor(Color.WHITE); } else { + final int emojiColor; if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { - emoji.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider)); + emoji.setColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText)); } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { - emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f)); + emoji.setColor(Theme.multAlpha(getThemedColor(Theme.key_actionBarDefaultTitle), .5f)); } else { - emoji.setColor(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider))); + emoji.setColor(adaptProfileEmojiColor(getThemedColor(Theme.key_actionBarDefault))); } - subtitleView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultSubtitle, resourceProvider)); - titleView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider)); + statusEmoji.setColor(Theme.getColor(Theme.key_profile_verifiedBackground, resourcesProvider)); + subtitleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); } - updateAvatarDrawable(peerColor); storyGradient.setColorId(colorId, animated); invalidate(); @@ -2158,14 +2290,32 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente } MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId); + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); if (peerColor != null) { emoji.setColor(adaptProfileEmojiColor(peerColor.getBgColor1(isDark))); } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { - emoji.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider)); + emoji.setColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText)); } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { - emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f)); + emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle), .5f)); } else { - emoji.setColor(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider))); + emoji.setColor(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault))); + } + if (peerColor != null) { + statusEmoji.setColor(ColorUtils.blendARGB(peerColor.getColor(1, resourcesProvider), peerColor.hasColor6(isDark) ? peerColor.getColor(4, resourcesProvider) : peerColor.getColor(2, resourcesProvider), .5f)); + } else { + statusEmoji.setColor(Theme.getColor(Theme.key_profile_verifiedBackground, resourcesProvider)); + } + } + + public void setStatusEmoji(long docId, boolean animated) { + statusEmoji.set(docId, animated); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId); + final boolean isDark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); + if (peerColor != null) { + statusEmoji.setColor(ColorUtils.blendARGB(peerColor.getColor2(isDark), peerColor.hasColor6(isDark) ? peerColor.getColor5(isDark) : peerColor.getColor3(isDark), .5f)); + } else { + statusEmoji.setColor(Theme.getColor(Theme.key_profile_verifiedBackground, resourcesProvider)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 55b7da1ca..091747b1e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -5981,7 +5981,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } @Override - protected boolean ignoreTouches() { + protected boolean ignoreTouches(float x, float y) { return !keyboardShown && currentEditMode != EDIT_MODE_NONE; } @@ -6096,7 +6096,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (captionEdit.isCaptionOverLimit()) { AndroidUtilities.shakeViewSpring(captionEdit.limitTextView, shiftDp = -shiftDp); BotWebViewVibrationEffect.APP_ERROR.vibrate(); - if (!MessagesController.getInstance(currentAccount).premiumLocked && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > captionEdit.getCodePointCount()) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && MessagesController.getInstance(currentAccount).captionLengthLimitPremium > captionEdit.getCodePointCount()) { showCaptionLimitBulletin(containerView); } return; @@ -10734,6 +10734,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat updateMinMax(scale); padImageForHorizontalInsets = true; containerView.invalidate(); + + if (placeProvider == null || !placeProvider.closeKeyboard()) { + makeFocusable(); + } } }); imageMoveAnimation.start(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index 9ec379ef4..6e2123e68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -395,7 +395,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC } @Override - public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { + public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index ad26d33ac..8448234d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -984,7 +984,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification @Override public boolean onFragmentCreate() { - if (getMessagesController().premiumLocked) { + if (getMessagesController().premiumFeaturesBlocked()) { return false; } NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.billingProductDetailsUpdated); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index b0a23d6fd..405d743e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -647,7 +647,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio callsRow = rowCount++; groupsRow = rowCount++; groupsDetailRow = -1; - if (!getMessagesController().premiumLocked || getUserConfig().isPremium()) { + if (!getMessagesController().premiumFeaturesBlocked() || getUserConfig().isPremium()) { voicesRow = rowCount++; } else { voicesRow = -1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index a311fca7c..7e8006925 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -214,6 +214,7 @@ import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; import org.telegram.ui.Components.Premium.ProfilePremiumCell; +import org.telegram.ui.Components.Premium.boosts.UserSelectorBottomSheet; import org.telegram.ui.Components.ProfileGalleryView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; @@ -271,6 +272,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private SearchAdapter searchAdapter; private SimpleTextView[] nameTextView = new SimpleTextView[2]; private String nameTextViewRightDrawableContentDescription = null; + private String nameTextViewRightDrawable2ContentDescription = null; private SimpleTextView[] onlineTextView = new SimpleTextView[4]; private AudioPlayerAlert.ClippingTextViewSwitcher mediaCounterTextView; private RLottieImageView writeButton; @@ -290,6 +292,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private StickerEmptyView emptyView; private boolean sharedMediaLayoutAttached; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; + private boolean preloadedChannelEmojiStatuses; private View blurredView; @@ -529,6 +532,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int addToGroupButtonRow; private int addToGroupInfoRow; private int premiumRow; + private int premiumGiftingRow; private int premiumSectionsRow; private int settingsTimerRow; @@ -3611,6 +3615,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. onWriteButtonClick(); } else if (position == premiumRow) { presentFragment(new PremiumPreviewFragment("settings")); + } else if (position == premiumGiftingRow) { + UserSelectorBottomSheet.open(); } else { processOnClickOrPress(position, view, x, y); } @@ -3655,7 +3661,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. BuildVars.DEBUG_VERSION ? (SharedConfig.useSurfaceInStories ? "back to TextureView in stories" : "use SurfaceView in stories") : null, BuildVars.DEBUG_PRIVATE_VERSION ? (SharedConfig.photoViewerBlur ? "do not blur in photoviewer" : "blur in photoviewer") : null, !SharedConfig.payByInvoice ? "Enable Invoice Payment" : "Disable Invoice Payment", - BuildVars.DEBUG_PRIVATE_VERSION ? "Update Attach Bots" : null + BuildVars.DEBUG_PRIVATE_VERSION ? "Update Attach Bots" : null, + BuildVars.DEBUG_PRIVATE_VERSION ? ((SharedConfig.forceLessData ? "Disable using less data" : "Use less data on stories") + (ApplicationLoader.isConnectionSlow() ? " (connection is already slow)" : "")) : null }; builder.setItems(items, (dialog, which) -> { @@ -3675,13 +3682,21 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. sharedPreferences.edit().putBoolean("logsEnabled", BuildVars.LOGS_ENABLED).commit(); updateRowsIds(); listAdapter.notifyDataSetChanged(); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("app start time = " + ApplicationLoader.startTime); + try { + FileLog.d("buildVersion = " + ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0).versionCode); + } catch (Exception e) { + FileLog.e(e); + } + } } else if (which == 5) { SharedConfig.toggleInappCamera(); } else if (which == 6) { 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").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").commit(); MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; @@ -3701,6 +3716,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); RestrictedLanguagesSelectActivity.cleanup(); PersistColorPalette.getInstance(currentAccount).cleanup(); + getMessagesController().getMainSettings().edit().remove("peerColors").remove("profilePeerColors").remove("boostingappearance").commit(); } else if (which == 7) { VoIPHelper.showCallDebugSettings(getParentActivity()); } else if (which == 8) { @@ -3889,6 +3905,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SharedConfig.togglePaymentByInvoice(); } else if (which == 26) { getMediaDataController().loadAttachMenuBots(false, true); + } else if (which == 27) { + SharedConfig.setForceLessData(!SharedConfig.forceLessData); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -4187,7 +4205,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (avatarBig != null) { return; } - if (isTopic && !getMessagesController().premiumLocked) { + if (isTopic && !getMessagesController().premiumFeaturesBlocked()) { ArrayList topics = getMessagesController().getTopicsController().getTopics(chatId); if (topics != null) { TLRPC.TL_forumTopic currentTopic = null; @@ -4311,8 +4329,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); - if (isFocusable() && nameTextViewRightDrawableContentDescription != null) { - info.setText(getText() + ", " + nameTextViewRightDrawableContentDescription); + if (isFocusable() && (nameTextViewRightDrawableContentDescription != null || nameTextViewRightDrawable2ContentDescription != null)) { + StringBuilder s = new StringBuilder(getText()); + if (nameTextViewRightDrawable2ContentDescription != null) { + if (s.length() > 0) s.append(", "); + s.append(nameTextViewRightDrawable2ContentDescription); + } + if (nameTextViewRightDrawableContentDescription != null) { + if (s.length() > 0) s.append(", "); + s.append(nameTextViewRightDrawableContentDescription); + } + info.setText(s); } } }; @@ -4397,7 +4424,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. protected TextView createTextView() { TextView textView = new TextView(context); textView.setTextColor(getThemedColor(Theme.key_player_actionBarSubtitle)); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, AndroidUtilities.dp(14)); textView.setSingleLine(true); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setGravity(Gravity.LEFT); @@ -4405,7 +4432,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }; mediaCounterTextView.setAlpha(0.0f); - avatarContainer2.addView(mediaCounterTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 8, 0)); + avatarContainer2.addView(mediaCounterTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118.33f, -2, 8, 0)); storyView = new ProfileStoriesView(context, currentAccount, getDialogId(), avatarContainer, avatarImage, resourcesProvider) { @Override protected void onTap(StoryViewer.PlaceProvider provider) { @@ -5039,32 +5066,57 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. xoff = MathUtils.clamp(ecenter - popupWidth / 2, 0, AndroidUtilities.displaySize.x - popupWidth); ecenter -= xoff; boolean hasEmoji = emojiStatusDrawable[1] != null && emojiStatusDrawable[1].getDrawable() instanceof AnimatedEmojiDrawable; - SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, Math.max(0, ecenter), SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS, true, resourcesProvider, topMarginDp) { + SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, Math.max(0, ecenter), currentChat == null ? SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS : SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS_CHANNEL, true, resourcesProvider, topMarginDp) { @Override protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); - if (documentId == null) { - req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); - } else if (until != null) { - req.emoji_status = new TLRPC.TL_emojiStatusUntil(); - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + TLObject request; + if (currentChat == null) { + TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + if (documentId == null) { + req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + req.emoji_status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + } else { + req.emoji_status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; + } + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user != null) { + user.emoji_status = req.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatusUntilUpdate(user.id, user.emoji_status); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); + } + request = req; } else { - req.emoji_status = new TLRPC.TL_emojiStatus(); - ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user != null) { - user.emoji_status = req.emoji_status; - MessagesController.getInstance(currentAccount).updateEmojiStatusUntilUpdate(user.id, user.emoji_status); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); + TLRPC.TL_channels_updateEmojiStatus req = new TLRPC.TL_channels_updateEmojiStatus(); + req.channel = MessagesController.getInputChannel(currentChat); + if (documentId == null) { + req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + req.emoji_status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + } else { + req.emoji_status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; + } + if (currentChat != null) { + currentChat.emoji_status = req.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatusUntilUpdate(-currentChat.id, currentChat.emoji_status); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_EMOJI_STATUS); + } + request = req; } for (int a = 0; a < 2; ++a) { if (emojiStatusDrawable[a] != null) { - if (documentId == null) { + if (documentId == null && currentChat == null) { emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(a), true); - } else { + } else if (documentId != null) { emojiStatusDrawable[a].set(documentId, true); + } else { + emojiStatusDrawable[a].set((Drawable) null, true); } } } @@ -5073,11 +5125,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } updateEmojiStatusDrawableColor(); updateEmojiStatusEffectPosition(); - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (!(res instanceof TLRPC.TL_boolTrue)) { - // TODO: reject - } - }); + ConnectionsManager.getInstance(currentAccount).sendRequest(request, null); if (popup[0] != null) { selectAnimatedEmojiDialog = null; popup[0].dismiss(); @@ -5085,8 +5133,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }; TLRPC.User user = getMessagesController().getUser(userId); - if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - popupLayout.setExpireDateHint(((TLRPC.TL_emojiStatusUntil) user.emoji_status).until); + if (user != null) { + popupLayout.setExpireDateHint(DialogObject.getEmojiStatusUntil(user.emoji_status)); } popupLayout.setSelected(emojiStatusDrawable[1] != null && emojiStatusDrawable[1].getDrawable() instanceof AnimatedEmojiDrawable ? ((AnimatedEmojiDrawable) emojiStatusDrawable[1].getDrawable()).getDocumentId() : null); popupLayout.setSaveState(3); @@ -5838,7 +5886,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. verifiedDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } if (verifiedDrawable[1] != null) { - color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedBackground)); + color1 = peerColor != null ? Theme.adaptHSV(ColorUtils.blendARGB(peerColor.getColor2(), peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor5() : peerColor.getColor3(), .4f), +.1f, Theme.isCurrentThemeDark() ? -.1f : -.08f) : getThemedColor(Theme.key_profile_verifiedBackground); color2 = getThemedColor(Theme.key_player_actionBarTitle); verifiedDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } @@ -5849,7 +5897,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. verifiedCheckDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } if (verifiedCheckDrawable[1] != null) { - color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedCheck)); + color1 = peerColor != null ? Color.WHITE : applyPeerColor(getThemedColor(Theme.key_profile_verifiedCheck)); color2 = getThemedColor(Theme.key_windowBackgroundWhite); verifiedCheckDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } @@ -6723,7 +6771,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } else if (chatId != 0) { - if ((mask & MessagesController.UPDATE_MASK_CHAT) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { + if ((mask & MessagesController.UPDATE_MASK_CHAT) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0 || (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0) { if ((mask & MessagesController.UPDATE_MASK_CHAT) != 0) { updateListAnimated(true); } else { @@ -7691,6 +7739,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. notificationRow = -1; languageRow = -1; premiumRow = -1; + premiumGiftingRow = -1; premiumSectionsRow = -1; privacyRow = -1; dataRow = -1; @@ -7816,8 +7865,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. devicesRow = rowCount++; languageRow = rowCount++; devicesSectionRow = rowCount++; - if (!getMessagesController().premiumLocked) { + if (!getMessagesController().premiumFeaturesBlocked()) { premiumRow = rowCount++; + } + if (!getMessagesController().premiumPurchaseBlocked()) { + premiumGiftingRow = rowCount++; + } + if (premiumRow >= 0 || premiumGiftingRow >= 0) { premiumSectionsRow = rowCount++; } helpHeaderRow = rowCount++; @@ -8066,6 +8120,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (verifiedCrossfadeDrawable[a] == null) { verifiedDrawable[a] = Theme.profile_verifiedDrawable.getConstantState().newDrawable().mutate(); verifiedCheckDrawable[a] = Theme.profile_verifiedCheckDrawable.getConstantState().newDrawable().mutate(); + if (a == 1 && peerColor != null) { + int color = Theme.adaptHSV(ColorUtils.blendARGB(peerColor.getColor2(), peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor5() : peerColor.getColor3(), .4f), +.1f, Theme.isCurrentThemeDark() ? -.1f : -.08f); + verifiedDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color, getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f), PorterDuff.Mode.MULTIPLY); + color = Color.WHITE; + verifiedCheckDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color, getThemedColor(Theme.key_windowBackgroundWhite), mediaHeaderAnimationProgress, 1.0f), PorterDuff.Mode.MULTIPLY); + } verifiedCrossfadeDrawable[a] = new CrossfadeDrawable( new CombinedDrawable(verifiedDrawable[a], verifiedCheckDrawable[a]), ContextCompat.getDrawable(getParentActivity(), R.drawable.verified_profile) @@ -8276,55 +8336,61 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. onlineTextView[a].setText(newString2); } Drawable leftIcon = currentEncryptedChat != null ? getLockIconDrawable() : null; - Drawable rightIcon = null; boolean rightIconIsPremium = false, rightIconIsStatus = false; nameTextView[a].setRightDrawableOutside(a == 0); if (a == 0) { if (user.scam || user.fake) { - rightIcon = getScamDrawable(user.scam ? 0 : 1); - nameTextViewRightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); + nameTextView[a].setRightDrawable2(getScamDrawable(user.scam ? 0 : 1)); + nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.ScamMessage); } else if (user.verified) { - rightIcon = getVerifiedCrossfadeDrawable(a); - nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a)); + nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.AccDescrVerified); + } else if (getMessagesController().isDialogMuted(dialogId != 0 ? dialogId : userId, topicId)) { + nameTextView[a].setRightDrawable2(getThemedDrawable(Theme.key_drawable_muteIconDrawable)); + nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.NotificationsMuted); + } else { + nameTextView[a].setRightDrawable2(null); + nameTextViewRightDrawable2ContentDescription = null; + } + if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { rightIconIsStatus = true; rightIconIsPremium = false; - rightIcon = getEmojiStatusDrawable(user.emoji_status, false, false, a); - nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrPremium", R.string.AccDescrPremium); + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(user.emoji_status, false, false, a)); + nameTextViewRightDrawableContentDescription = LocaleController.getString(R.string.AccDescrPremium); } else if (getMessagesController().isPremiumUser(user)) { rightIconIsStatus = false; rightIconIsPremium = true; - rightIcon = getEmojiStatusDrawable(null, false, false, a); - nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrPremium", R.string.AccDescrPremium); - } else if (getMessagesController().isDialogMuted(dialogId != 0 ? dialogId : userId, topicId)) { - rightIcon = getThemedDrawable(Theme.key_drawable_muteIconDrawable); - nameTextViewRightDrawableContentDescription = LocaleController.getString("NotificationsMuted", R.string.NotificationsMuted); + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(null, false, false, a)); + nameTextViewRightDrawableContentDescription = LocaleController.getString( R.string.AccDescrPremium); } else { - rightIcon = null; + nameTextView[a].setRightDrawable(null); nameTextViewRightDrawableContentDescription = null; } } else if (a == 1) { if (user.scam || user.fake) { - rightIcon = getScamDrawable(user.scam ? 0 : 1); + nameTextView[a].setRightDrawable2(getScamDrawable(user.scam ? 0 : 1)); } else if (user.verified) { - rightIcon = getVerifiedCrossfadeDrawable(a); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a)); + } else { + nameTextView[a].setRightDrawable2(null); + } + if (user.emoji_status instanceof TLRPC.TL_emojiStatus || user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { rightIconIsStatus = true; rightIconIsPremium = false; - rightIcon = getEmojiStatusDrawable(user.emoji_status, true, true, a); + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(user.emoji_status, true, true, a)); } else if (getMessagesController().isPremiumUser(user)) { rightIconIsStatus = false; rightIconIsPremium = true; - rightIcon = getEmojiStatusDrawable(null, true, true, a); + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(null, true, true, a)); + } else { + nameTextView[a].setRightDrawable(null); } } nameTextView[a].setLeftDrawable(leftIcon); - nameTextView[a].setRightDrawable(rightIcon); if (a == 1 && (rightIconIsStatus || rightIconIsPremium)) { nameTextView[a].setRightDrawableOutside(true); } if (user.self && getMessagesController().isPremiumUser(user)) { - final SimpleTextView textView = nameTextView[a]; nameTextView[a].setRightDrawableOnClick(v -> { showStatusSelect(); }); @@ -8426,7 +8492,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. final int colorId = ChatObject.getProfileColorId(chat); MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; final MessagesController.PeerColor wasPeerColor = peerColor; - peerColor = null; + peerColor = peerColors == null ? null : peerColors.getColor(colorId); if (wasPeerColor != peerColor) { updatedPeerColor(); } @@ -8541,24 +8607,45 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } nameTextView[a].setLeftDrawable(null); nameTextView[a].setRightDrawableOutside(a == 0); + nameTextView[a].setRightDrawableOnClick(null); if (a != 0) { if (chat.scam || chat.fake) { - nameTextView[a].setRightDrawable(getScamDrawable(chat.scam ? 0 : 1)); + nameTextView[a].setRightDrawable2(getScamDrawable(chat.scam ? 0 : 1)); nameTextViewRightDrawableContentDescription = LocaleController.getString("ScamMessage", R.string.ScamMessage); } else if (chat.verified) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable(a)); + nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a)); nameTextViewRightDrawableContentDescription = LocaleController.getString("AccDescrVerified", R.string.AccDescrVerified); } else { - nameTextView[a].setRightDrawable(null); + nameTextView[a].setRightDrawable2(null); nameTextViewRightDrawableContentDescription = null; } + if (DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(chat.emoji_status, true, false, a)); + nameTextView[a].setRightDrawableOutside(true); + nameTextViewRightDrawableContentDescription = null; + if (ChatObject.canChangeChatInfo(chat)) { + nameTextView[a].setRightDrawableOnClick(v -> { + showStatusSelect(); + }); + if (preloadedChannelEmojiStatuses) { + preloadedChannelEmojiStatuses = true; + getMediaDataController().loadRestrictedStatusEmojis(); + } + } + } } else { if (chat.scam || chat.fake) { - nameTextView[a].setRightDrawable(getScamDrawable(chat.scam ? 0 : 1)); + nameTextView[a].setRightDrawable2(getScamDrawable(chat.scam ? 0 : 1)); } else if (chat.verified) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable(a)); + nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a)) ; } else if (getMessagesController().isDialogMuted(-chatId, topicId)) { - nameTextView[a].setRightDrawable(getThemedDrawable(Theme.key_drawable_muteIconDrawable)); + nameTextView[a].setRightDrawable2(getThemedDrawable(Theme.key_drawable_muteIconDrawable)); + } else { + nameTextView[a].setRightDrawable2(null); + } + if (DialogObject.getEmojiStatusDocumentId(chat.emoji_status) != 0) { + nameTextView[a].setRightDrawable(getEmojiStatusDrawable(chat.emoji_status, false, false, a)); + nameTextView[a].setRightDrawableOutside(true); } else { nameTextView[a].setRightDrawable(null); } @@ -8673,6 +8760,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. final int iconColor = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, avatarAnimationProgress), false); } + if (verifiedDrawable[1] != null) { + int color1 = peerColor != null ? Theme.adaptHSV(ColorUtils.blendARGB(peerColor.getColor2(), peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor5() : peerColor.getColor3(), .4f), +.1f, Theme.isCurrentThemeDark() ? -.1f : -.08f) : getThemedColor(Theme.key_profile_verifiedBackground); + int color2 = getThemedColor(Theme.key_player_actionBarTitle); + verifiedDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, mediaHeaderAnimationProgress, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (verifiedCheckDrawable[1] != null) { + int color1 = peerColor != null ? Color.WHITE : applyPeerColor(getThemedColor(Theme.key_profile_verifiedCheck)); + int color2 = getThemedColor(Theme.key_windowBackgroundWhite); + verifiedCheckDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, mediaHeaderAnimationProgress, 1.0f), PorterDuff.Mode.MULTIPLY); + } if (nameTextView[1] != null) { nameTextView[1].setTextColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_profile_title), Color.WHITE, currentExpandAnimatorValue)); } @@ -8800,7 +8897,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. otherItem.addSubItem(delete_contact, R.drawable.msg_delete, LocaleController.getString("DeleteContact", R.string.DeleteContact)); } if (!UserObject.isDeleted(user) && !isBot && currentEncryptedChat == null && !userBlocked && userId != 333000 && userId != 777000 && userId != 42777) { - if (!user.premium && !BuildVars.IS_BILLING_UNAVAILABLE && !user.self && userInfo != null && !getMessagesController().premiumLocked && !userInfo.premium_gifts.isEmpty()) { + if (!user.premium && !BuildVars.IS_BILLING_UNAVAILABLE && !user.self && userInfo != null && !getMessagesController().premiumFeaturesBlocked() && !userInfo.premium_gifts.isEmpty()) { otherItem.addSubItem(gift_premium, R.drawable.msg_gift_premium, LocaleController.getString(R.string.GiftPremium)); } otherItem.addSubItem(start_secret_chat, R.drawable.msg_secret, LocaleController.getString("StartEncryptedChat", R.string.StartEncryptedChat)); @@ -10149,7 +10246,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. textCell.setTextAndIcon(LocaleController.getString("AddToGroupOrChannel", R.string.AddToGroupOrChannel), R.drawable.msg_groups_create, false); textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); } else if (position == premiumRow) { - textCell.setTextAndIcon(LocaleController.getString("TelegramPremium", R.string.TelegramPremium), new AnimatedEmojiDrawable.WrapSizeDrawable(PremiumGradient.getInstance().premiumStarMenuDrawable, AndroidUtilities.dp(24), AndroidUtilities.dp(24)), false); + textCell.setTextAndIcon(LocaleController.getString("TelegramPremium", R.string.TelegramPremium), new AnimatedEmojiDrawable.WrapSizeDrawable(PremiumGradient.getInstance().premiumStarMenuDrawable, AndroidUtilities.dp(24), AndroidUtilities.dp(24)), true); + textCell.setImageLeft(23); + } else if (position == premiumGiftingRow) { + textCell.setTextAndIcon(TextCell.applyNewSpan(LocaleController.getString("GiftPremiumGifting", R.string.GiftPremiumGifting)), R.drawable.menu_gift, false); textCell.setImageLeft(23); } textCell.valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteValueText), false)); @@ -10356,7 +10456,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == questionRow || position == devicesRow || position == filtersRow || position == stickersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || - position == addToGroupButtonRow || position == premiumRow || position == liteModeRow; + position == addToGroupButtonRow || position == premiumRow || position == premiumGiftingRow || position == liteModeRow; } if (holder.itemView instanceof UserCell) { UserCell userCell = (UserCell) holder.itemView; @@ -10398,7 +10498,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. position == questionRow || position == devicesRow || position == filtersRow || position == stickersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == sendLastLogsRow || position == clearLogsRow || position == switchBackendRow || position == setAvatarRow || position == addToGroupButtonRow || - position == addToContactsRow || position == liteModeRow) { + position == addToContactsRow || position == liteModeRow || position == premiumGiftingRow) { return VIEW_TYPE_TEXT; } else if (position == notificationsDividerRow) { return VIEW_TYPE_DIVIDER; @@ -10834,7 +10934,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private boolean isPremiumFeatureAvailable(int feature) { - if (getMessagesController().premiumLocked && !getUserConfig().isPremium()) { + if (getMessagesController().premiumFeaturesBlocked() && !getUserConfig().isPremium()) { return false; } @@ -11635,6 +11735,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. put(++pointer, languageRow, sparseIntArray); put(++pointer, premiumRow, sparseIntArray); put(++pointer, premiumSectionsRow, sparseIntArray); + put(++pointer, premiumGiftingRow, sparseIntArray); put(++pointer, privacyRow, sparseIntArray); put(++pointer, dataRow, sparseIntArray); put(++pointer, liteModeRow, sparseIntArray); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index a05cf72cd..d91a3200a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -152,7 +152,6 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD return child != aspectRatioFrameLayout && super.drawChild(canvas, child, drawingTime); } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -1387,9 +1386,7 @@ public class SecretMediaViewer implements NotificationCenter.NotificationCenterD secretHint.setInnerPadding(12, 7, 11, 7); secretHint.setIconMargin(2); secretHint.setIconTranslate(0, 0); - RLottieDrawable icon = new RLottieDrawable(R.raw.fire_on, "" + R.raw.fire_on, dp(34), dp(34)); - icon.start(); - secretHint.setIcon(icon); + secretHint.setIcon(R.raw.fire_on); secretHint.show(); MessagesController.getGlobalMainSettings().edit().putInt("viewoncehint", MessagesController.getGlobalMainSettings().getInt("viewoncehint", 0) + 1).commit(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java new file mode 100644 index 000000000..31b0ec364 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretVoicePlayer.java @@ -0,0 +1,623 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.StateListAnimator; +import android.animation.ValueAnimator; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Insets; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.SurfaceTexture; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.view.WindowInsetsCompat; + +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.util.Log; + +import org.telegram.messenger.AndroidUtilities; +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.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.Theme; +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.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.VideoPlayer; +import org.telegram.ui.Stories.recorder.HintView2; +import org.telegram.ui.Stories.recorder.StoryRecorder; + +import java.io.File; + +public class SecretVoicePlayer extends Dialog { + + public final Context context; + +// WindowManager windowManager; +// private final WindowManager.LayoutParams windowLayoutParams; + private FrameLayout windowView; + private FrameLayout containerView; + + private ThanosEffect thanosEffect; + + private final Rect insets = new Rect(); + private Bitmap blurBitmap; + private BitmapShader blurBitmapShader; + private Paint blurBitmapPaint; + private Matrix blurMatrix; + + private boolean open; + private float openProgress; + private float openProgressLinear; + + private VideoPlayer player; + + private HintView2 hintView; + private TextView closeButton; + + public SecretVoicePlayer(Context context) { + super(context, R.style.TransparentDialog); + this.context = context; + + windowView = new FrameLayout(context) { + @Override + protected void dispatchDraw(Canvas canvas) { + if (openProgress > 0 && blurBitmapPaint != null) { + blurMatrix.reset(); + final float s = (float) getWidth() / blurBitmap.getWidth(); + blurMatrix.postScale(s, s); + blurBitmapShader.setLocalMatrix(blurMatrix); + + blurBitmapPaint.setAlpha((int) (0xFF * openProgress)); + canvas.drawRect(0, 0, getWidth(), getHeight(), blurBitmapPaint); + } + if (setCellInvisible && cell != null) { + cell.setVisibility(View.INVISIBLE); + setCellInvisible = false; + } + super.dispatchDraw(canvas); + } + + @Override + public boolean dispatchKeyEventPreIme(KeyEvent event) { + if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { + dismiss(); + return true; + } + return super.dispatchKeyEventPreIme(event); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + setupTranslation(); + } + }; + windowView.setOnClickListener(v -> { + if (closeAction == null) { + dismiss(); + } + }); + containerView = new FrameLayout(context) { + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == myCell || child == hintView) { + canvas.save(); + canvas.clipRect(0, AndroidUtilities.lerp(clipTop, 0, openProgress), getWidth(), AndroidUtilities.lerp(clipBottom, getHeight(), openProgress)); + boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } + return super.drawChild(canvas, child, drawingTime); + } + }; + windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + + if (Build.VERSION.SDK_INT >= 21) { + windowView.setFitsSystemWindows(true); + windowView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @NonNull + @Override + public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Insets r = insets.getInsets(WindowInsetsCompat.Type.displayCutout() | WindowInsetsCompat.Type.systemBars()); + SecretVoicePlayer.this.insets.set(r.left, r.top, r.right, r.bottom); + } else { + SecretVoicePlayer.this.insets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(), insets.getStableInsetRight(), insets.getStableInsetBottom()); + } + containerView.setPadding(SecretVoicePlayer.this.insets.left, SecretVoicePlayer.this.insets.top, SecretVoicePlayer.this.insets.right, SecretVoicePlayer.this.insets.bottom); + windowView.requestLayout(); + if (Build.VERSION.SDK_INT >= 30) { + return WindowInsets.CONSUMED; + } else { + return insets.consumeSystemWindowInsets(); + } + } + }); + } + + } + + private void prepareBlur(View withoutView) { + if (withoutView != null) { + withoutView.setVisibility(View.INVISIBLE); + } + AndroidUtilities.makeGlobalBlurBitmap(bitmap -> { + if (withoutView != null) { + withoutView.setVisibility(View.VISIBLE); + } + blurBitmap = bitmap; + + blurBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + blurBitmapPaint.setShader(blurBitmapShader = new BitmapShader(blurBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + ColorMatrix colorMatrix = new ColorMatrix(); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, Theme.isCurrentThemeDark() ? .05f : +.25f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, Theme.isCurrentThemeDark() ? -.02f : -.04f); + blurBitmapPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + blurMatrix = new Matrix(); + }, 14); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Window window = getWindow(); + window.setWindowAnimations(R.style.DialogNoAnimation); + setContentView(windowView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + WindowManager.LayoutParams params = window.getAttributes(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = ViewGroup.LayoutParams.MATCH_PARENT; + params.gravity = Gravity.FILL; + params.dimAmount = 0; + params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; + params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + if (Build.VERSION.SDK_INT >= 21) { + params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | + WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | + WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; + } + 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) { + params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + window.setAttributes(params); + + windowView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN); + 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 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; + 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); + } + updateTranslation(); + } else { + tx = ty = 0; + } + hasTranslation = true; + } + private void updateTranslation() { + if (thanosEffect != null) return; + myCell.setTranslationX(AndroidUtilities.lerp(tx, dtx, openProgress)); + myCell.setTranslationY(AndroidUtilities.lerp(ty, dty, openProgress)); + if (hintView != null) { + hintView.setTranslationX(AndroidUtilities.lerp(tx, dtx, openProgress)); + hintView.setTranslationY(AndroidUtilities.lerp(ty, dty, openProgress)); + } + } + + 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; + if (myCell != null) { + containerView.removeView(myCell); + myCell = null; + } + cell = messageCell; + messageObject = cell != null ? cell.getMessageObject() : null; + resourcesProvider = cell != null ? cell.getResourcesProvider() : null; + if (cell != null) { + + clipTop = messageCell.parentBoundsTop; + clipBottom = messageCell.parentBoundsBottom; + if (messageCell.getParent() instanceof View) { + View parent = (View) messageCell.getParent(); + clipTop += parent.getY(); + clipBottom += parent.getY(); + } + + myCell = new ChatMessageCell(getContext(), false, null, cell.getResourcesProvider()) { + @Override + public void setPressed(boolean pressed) {} + }; + myCell.setDelegate(new ChatMessageCell.ChatMessageCellDelegate() { + @Override + public boolean canPerformActions() { + return false; + } + }); + 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); + } + hasTranslation = false; + containerView.addView(myCell, new FrameLayout.LayoutParams(cell.getWidth(), cell.getHeight(), Gravity.CENTER)); + } + + MediaController.getInstance().pauseByRewind(); + + if (player != null) { + player.pause(); + player.releasePlayer(true); + player = null; + } + if (cell != null && cell.getMessageObject() != null) { + File file = FileLoader.getInstance(cell.getMessageObject().currentAccount).getPathToAttach(cell.getMessageObject().getDocument()); + if (file == null || !file.exists()) { + file = FileLoader.getInstance(cell.getMessageObject().currentAccount).getPathToMessage(cell.getMessageObject().messageOwner); + } + if ((file == null || !file.exists()) && (cell.getMessageObject().messageOwner.attachPath != null)) { + file = new File(cell.getMessageObject().messageOwner.attachPath); + } + if (file == null) { + return; + } + player = new VideoPlayer(); + player.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + @Override + public void onStateChanged(boolean playWhenReady, int playbackState) { + if (playbackState == ExoPlayer.STATE_ENDED) { + dismiss(); + } else { + AndroidUtilities.cancelRunOnUIThread(checkTimeRunnable); + AndroidUtilities.runOnUIThread(checkTimeRunnable, 16); + } + } + + @Override + public void onError(VideoPlayer player, Exception e) { + + } + + @Override + public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + + } + + @Override + public void onRenderedFirstFrame() { + + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + + } + + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + }); + 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; + } + }); + player.preparePlayer(Uri.fromFile(file), "other"); + player.play(); + } + + if (hintView != null) { + containerView.removeView(hintView); + hintView = null; + } + final boolean isOut = messageObject != null && messageObject.isOutOwner(); + if (messageObject != null && messageObject.getDialogId() != UserConfig.getInstance(messageObject.currentAccount).getClientUserId()) { + hintView = new HintView2(context, HintView2.DIRECTION_BOTTOM); + hintView.setMultilineText(true); + if (isOut) { + String name = ""; + long did = messageObject.getDialogId(); + if (did > 0) { + TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(did); + if (user != null) { + name = UserObject.getFirstName(user); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-did); + if (chat != null) { + name = chat.title; + } + } + hintView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.VoiceOnceOutHint, name))); + } else { + hintView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.VoiceOnceHint))); + } + hintView.setRounding(12); + hintView.setPadding(dp(!isOut && !cell.pinnedBottom ? 6 : 0), 0, 0, 0); + hintView.setJointPx(0, dp(34)); + 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)); + hintView.show(); + } + + if (closeButton != null) { + containerView.removeView(closeButton); + closeButton = null; + } + closeButton = new TextView(context); + closeButton.setTextColor(0xFFFFFFFF); + closeButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + if (Theme.isCurrentThemeDark()) { + closeButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(64, 0x20ffffff, 0x33ffffff)); + } else { + closeButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(64, 0x2e000000, 0x44000000)); + } + closeButton.setPadding(dp(12), dp(6), dp(12), dp(6)); + ScaleStateListAnimator.apply(closeButton); + closeButton.setText(LocaleController.getString(isOut ? R.string.VoiceOnceClose : R.string.VoiceOnceDeleteClose)); + closeButton.setOnClickListener(v -> { + dismiss(); + }); + containerView.addView(closeButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER, 0, 0, 0, 18)); + + if (!isOut && myCell != null && myCell.getMessageObject() != null && myCell.getMessageObject().messageOwner != null) { + myCell.getMessageObject().messageOwner.media_unread = false; + myCell.invalidate(); + } + } + + @Override + public void show() { + super.show(); + + prepareBlur(cell); + setCellInvisible = true; + animateOpenTo(open = true, null); + + if (this.openAction != null) { + AndroidUtilities.runOnUIThread(this.openAction); + this.openAction = null; + } + } + + private Runnable checkTimeRunnable = this::checkTime; + private void checkTime() { + if (player == null) { + return; + } + float progress = player.getCurrentPosition() / (float) player.getDuration(); + if (myCell != null) { + myCell.overrideDuration((player.getDuration() - player.getCurrentPosition()) / 1000L); + myCell.updatePlayingMessageProgress(); + SeekBarWaveform seekBarWaveform = myCell.getSeekBarWaveform(); + if (seekBarWaveform != null) { + seekBarWaveform.explodeAt(progress); + } + } + + if (player.isPlaying()) { + AndroidUtilities.cancelRunOnUIThread(checkTimeRunnable); + AndroidUtilities.runOnUIThread(checkTimeRunnable, 16); + } + } + + public boolean isShown() { + return !dismissing; + } + + private boolean dismissing = false; + + private AlertDialog backDialog; + @Override + public void onBackPressed() { + if (backDialog != null) { + backDialog.dismiss(); + backDialog = null; + return; + } + if (!dismissing && messageObject != null && !messageObject.isOutOwner()) { + backDialog = new AlertDialog.Builder(getContext(), resourcesProvider) + .setTitle(LocaleController.getString(R.string.VoiceOnceCloseTitle)) + .setMessage(LocaleController.getString(R.string.VoiceOnceCloseMessage)) + .setPositiveButton(LocaleController.getString(R.string.Continue), (di, w) -> { + if (backDialog != null) { + backDialog.dismiss(); + } + }) + .setNegativeButton(LocaleController.getString(R.string.Delete), (di, w) -> { + if (backDialog != null) { + backDialog.dismiss(); + backDialog = null; + } + dismiss(); + }) + .create(); + backDialog.show(); + TextView button = (TextView) backDialog.getButton(DialogInterface.BUTTON_NEGATIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + } + return; + } + super.onBackPressed(); + } + + @Override + public void dismiss() { + if (dismissing) return; + if (backDialog != null) { + backDialog.dismiss(); + backDialog = null; + } + dismissing = true; + if (hintView != null) { + hintView.hide(); + } + if (player != null) { + player.pause(); + player.releasePlayer(true); + player = null; + } + if (myCell != null && myCell.getSeekBarWaveform() != null) { + myCell.getSeekBarWaveform().setExplosionRate(openProgressLinear); + } + hasTranslation = false; + setupTranslation(); + animateOpenTo(open = false, () -> { + if (thanosEffect == null) { + AndroidUtilities.runOnUIThread(super::dismiss); + if (cell != null) { + cell.invalidate(); + cell.setVisibility(View.VISIBLE); + } + } + + MediaController.getInstance().tryResumePausedAudio(); + }); + windowView.invalidate(); + + if (this.closeAction != null) { + AndroidUtilities.runOnUIThread(this.closeAction); + this.closeAction = null; + + 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(); + } + }); + + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + getWindow().setAttributes(params); + } + } + + private ValueAnimator openAnimator; + private void animateOpenTo(boolean open, Runnable after) { + if (openAnimator != null) { + openAnimator.cancel(); + } + setupTranslation(); + openAnimator = ValueAnimator.ofFloat(openProgressLinear, 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); + windowView.invalidate(); + containerView.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))); + } + }); + openAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + openProgress = openProgressLinear = 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 (after != null) { + after.run(); + } + } + }); + openAnimator.setDuration(!open && closeAction == null ? 330 : 520); + openAnimator.start(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index dbd631ca0..b81c9b8d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -145,9 +145,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public static final int TYPE_CHAT_REACTIONS = 6; public final static int TYPE_SET_REPLY_ICON_BOTTOM = 7; public final static int TYPE_EXPANDABLE_REACTIONS = 8; + public final static int TYPE_EMOJI_STATUS_CHANNEL = 9; + public final static int TYPE_EMOJI_STATUS_CHANNEL_TOP = 10; public boolean isBottom() { - return type == TYPE_SET_REPLY_ICON; + return type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL_TOP; } private final int SPAN_COUNT_FOR_EMOJI = 8; @@ -432,7 +434,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati this.type = type; this.includeEmpty = includeEmpty; this.baseFragment = baseFragment; - this.includeHint = MessagesController.getGlobalMainSettings().getInt("emoji" + (type == TYPE_EMOJI_STATUS ? "status" : "reaction") + "usehint", 0) < 3; + this.includeHint = MessagesController.getGlobalMainSettings().getInt("emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint", 0) < 3; this.accentColor = accentColor; selectorPaint.setColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); @@ -445,7 +447,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati setFocusableInTouchMode(true); - if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { topMarginDp = topPaddingDp; setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4)); setOnTouchListener((v, e) -> { @@ -558,12 +560,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } - if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { contentView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); } contentView.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON_BOTTOM ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); + addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON_BOTTOM ? 6 + topMarginDp : 0, 0, isBottom() ? 6 + topMarginDp : 0)); if (bubbleX != null) { bubble2View = new View(context) { @@ -580,7 +582,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati addView(bubble2View, LayoutHelper.createFrame(17, 9, (isBottom() ? Gravity.BOTTOM : Gravity.TOP) | Gravity.LEFT, bubbleX / AndroidUtilities.density + (bubbleRight ? -25 : 10), isBottom() ? 0 : 5 + topMarginDp, 0, isBottom() ? 5 + topMarginDp + 9 : 0)); } - boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_AVATAR_CONSTRUCTOR && shouldDrawBackground; + boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_EMOJI_STATUS_CHANNEL && type != TYPE_EMOJI_STATUS_CHANNEL_TOP && shouldDrawBackground; for (int i = 0; i < 2; i++) { EmojiTabsStrip emojiTabs = new EmojiTabsStrip(context, resourcesProvider, true, false, true, type, showSettings ? () -> { search(null, false, false); @@ -684,7 +686,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS || type == TYPE_CHAT_REACTIONS, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_REACTIONS || type == TYPE_CHAT_REACTIONS, 1f, true); invalidateParent(); } @@ -818,7 +820,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati TextView emptyViewText = new TextView(context); if (type == TYPE_AVATAR_CONSTRUCTOR) { emptyViewText.setText(LocaleController.getString("NoEmojiOrStickersFound", R.string.NoEmojiOrStickersFound)); - } else if (type == TYPE_EMOJI_STATUS) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { emptyViewText.setText(LocaleController.getString("NoEmojiFound", R.string.NoEmojiFound)); } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { emptyViewText.setText(LocaleController.getString("NoReactionsFound", R.string.NoReactionsFound)); @@ -919,7 +921,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati invalidateParent(); return true; } - if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && type == TYPE_EMOJI_STATUS) { + if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP)) { SelectStatusDurationDialog dialog = selectStatusDateDialog = new SelectStatusDurationDialog(context, dismiss, SelectAnimatedEmojiDialog.this, (ImageViewEmoji) view, resourcesProvider) { @Override protected boolean getOutBounds(Rect rect) { @@ -1097,6 +1099,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } public void setExpireDateHint(int date) { + if (date <= 0) return; includeHint = true; hintExpireDate = date; updateRows(true, false); @@ -1227,7 +1230,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private Drawable getPremiumStar() { if (premiumStar == null) { - if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_REPLY_ICON_BOTTOM) { premiumStar = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_filled_blocked).mutate(); } else { premiumStar = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_settings_premium).mutate(); @@ -2222,7 +2225,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); if (type == TYPE_TOPIC_ICON) { textView.setText(LocaleController.getString("SelectTopicIconHint", R.string.SelectTopicIconHint)); - } else if (type == TYPE_EMOJI_STATUS) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { textView.setText(LocaleController.getString("EmojiLongtapHint", R.string.EmojiLongtapHint)); } else { textView.setText(LocaleController.getString("ReactionsLongtapHint", R.string.ReactionsLongtapHint)); @@ -3113,7 +3116,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public void onEmojiClick(View view, AnimatedEmojiSpan span) { incrementHintUse(); - if (span == null || type == TYPE_EMOJI_STATUS && selectedDocumentIds.contains(span.documentId)) { + if (span == null || (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) && selectedDocumentIds.contains(span.documentId)) { onEmojiSelected(view, null, null, null); } else { TLRPC.TL_emojiStatus status = new TLRPC.TL_emojiStatus(); @@ -3121,10 +3124,10 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati TLRPC.Document document = span.document == null ? AnimatedEmojiDrawable.findDocument(currentAccount, span.documentId) : span.document; if (view instanceof ImageViewEmoji) { - if (type == TYPE_EMOJI_STATUS) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { MediaDataController.getInstance(currentAccount).pushRecentEmojiStatus(status); } - if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION) { animateEmojiSelect((ImageViewEmoji) view, () -> { onEmojiSelected(view, span.documentId, document, null); }); @@ -3141,7 +3144,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (type == TYPE_SET_DEFAULT_REACTION) { return; } - final String key = "emoji" + (type == TYPE_EMOJI_STATUS ? "status" : "reaction") + "usehint"; + final String key = "emoji" + (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP ? "status" : "reaction") + "usehint"; final int value = MessagesController.getGlobalMainSettings().getInt(key, 0); if (value <= 3) { MessagesController.getGlobalMainSettings().edit().putInt(key, value + 1).apply(); @@ -3163,13 +3166,21 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_EMOJIPACKS); if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_CHAT_REACTIONS) { MediaDataController.getInstance(account).checkReactions(); + } else if (type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + if (MessagesController.getInstance(account).getMainSettings().getBoolean("resetemojipacks", true)) { + MediaDataController.getInstance(account).loadStickers(MediaDataController.TYPE_EMOJIPACKS, false, false); + MessagesController.getInstance(account).getMainSettings().edit().putBoolean("resetemojipacks", false).commit(); + } + MediaDataController.getInstance(account).fetchEmojiStatuses(2, false); + MediaDataController.getInstance(account).loadRestrictedStatusEmojis(); + MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses(), false); } else if (type == TYPE_EMOJI_STATUS) { MediaDataController.getInstance(account).fetchEmojiStatuses(0, true); MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); } else if (type == TYPE_TOPIC_ICON) { MediaDataController.getInstance(account).checkDefaultTopicIcons(); } else if (type == TYPE_AVATAR_CONSTRUCTOR) { - MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); + MediaDataController.getInstance(account).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_IMAGE); } } @@ -3233,7 +3244,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati stickerSets.clear(); recentStickers.clear(); - if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS) { + if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS && type != TYPE_EMOJI_STATUS_CHANNEL && type != TYPE_EMOJI_STATUS_CHANNEL_TOP) { searchRow = totalCount++; rowHashCodes.add(9L); } else { @@ -3329,6 +3340,14 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati rowHashCodes.add(6L); } + HashSet restricted = null; + if (type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { + TLRPC.TL_emojiList emojiList = MediaDataController.getInstance(currentAccount).restrictedStatusEmojis; + if (emojiList != null) { + restricted = new HashSet<>(); + restricted.addAll(emojiList.document_id); + } + } if (recentReactionsToSet != null) { topReactionsStartRow = totalCount; ArrayList tmp = new ArrayList<>(recentReactionsToSet); @@ -3373,9 +3392,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati totalCount += recentReactions.size(); recentReactionsEndRow = totalCount; } - } else if (type == TYPE_EMOJI_STATUS) { + } else if (type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP) { ArrayList recentEmojiStatuses = MediaDataController.getInstance(currentAccount).getRecentEmojiStatuses(); - TLRPC.TL_messages_stickerSet defaultSet = MediaDataController.getInstance(currentAccount).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), true); + TLRPC.TL_messages_stickerSet defaultSet = MediaDataController.getInstance(currentAccount).getStickerSet(type == TYPE_EMOJI_STATUS ? new TLRPC.TL_inputStickerSetEmojiDefaultStatuses() : new TLRPC.TL_inputStickerSetEmojiChannelDefaultStatuses(), true); if (defaultSet == null) { defaultSetLoading = true; } else { @@ -3383,7 +3402,12 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati totalCount++; rowHashCodes.add(2L); } - ArrayList defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultEmojiStatuses(); + ArrayList defaultEmojiStatuses; + if (type == TYPE_EMOJI_STATUS) { + defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultEmojiStatuses(); + } else { + defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultChannelEmojiStatuses(); + } final int maxrecentlen = SPAN_COUNT_FOR_EMOJI * (RECENT_MAX_LINES + 8); if (defaultSet.documents != null && !defaultSet.documents.isEmpty()) { for (int i = 0; i < Math.min(SPAN_COUNT_FOR_EMOJI - 1, defaultSet.documents.size()); ++i) { @@ -3393,7 +3417,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } } - if (recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { + if (type == TYPE_EMOJI_STATUS && recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : recentEmojiStatuses) { Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); if (did == null) { @@ -3466,6 +3490,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && !MessageObject.isTextColorSet(set)) { continue; } + if ((type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_CHANNEL) && !set.set.channel_emoji_status) { + continue; + } if ((set.set.emojis || showStickers) && !installedEmojiSets.contains(set.set.id)) { positionToSection.put(totalCount, packs.size()); sectionToPosition.put(packs.size(), totalCount); @@ -3478,7 +3505,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati pack.expanded = true; pack.free = !MessageObject.isPremiumEmojiPack(set); pack.set = set.set; - pack.documents = set.documents; + pack.documents = filter(set.documents, restricted); pack.index = packs.size(); packs.add(pack); totalCount += pack.documents.size(); @@ -3525,6 +3552,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && (documents.isEmpty() || !MessageObject.isTextColorEmoji(documents.get(0)))) { continue; } + if ((type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_CHANNEL) && !set.channel_emoji_status) { + continue; + } positionToSection.put(totalCount, packs.size()); sectionToPosition.put(packs.size(), totalCount); @@ -3536,7 +3566,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati pack.featured = true; pack.free = !isPremiumPack; pack.set = set; - pack.documents = documents; + pack.documents = filter(documents, restricted); pack.index = packs.size(); pack.expanded = expandedEmojiSets.contains(pack.set.id); @@ -3713,7 +3743,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati if (type == TYPE_TOPIC_ICON || type == TYPE_AVATAR_CONSTRUCTOR) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } - return type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; + return type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; } public class EmojiListView extends RecyclerListView { @@ -4018,7 +4048,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati ImageReceiver imageReceiver; if (imageView.empty) { Drawable drawable = getPremiumStar(); - float scale = type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM ? 1.3f : 1f; + float scale = type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_SET_REPLY_ICON_BOTTOM ? 1.3f : 1f; if (imageView.pressedProgress != 0 || imageView.selected) { scale *= 0.8f + 0.2f * (1f - (imageView.selected ? .7f : imageView.pressedProgress)); } @@ -4181,7 +4211,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati Drawable drawable = null; if (imageView.empty) { drawable = getPremiumStar(); - if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_CHANNEL || type == TYPE_SET_REPLY_ICON_BOTTOM) { AndroidUtilities.rectTmp2.inset((int) (-AndroidUtilities.rectTmp2.width() * .15f), (int) (-AndroidUtilities.rectTmp2.height() * .15f)); } drawable.setBounds(AndroidUtilities.rectTmp2); @@ -4460,7 +4490,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } }); - if (isFirstOpen && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM) { + if (isFirstOpen && type != TYPE_SET_REPLY_ICON && type != TYPE_EMOJI_STATUS_CHANNEL_TOP && type != TYPE_SET_REPLY_ICON_BOTTOM) { isFirstOpen = false; AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).setUiDbCallback(() -> { HwEmojis.enableHw(); @@ -5770,4 +5800,16 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati this.title = title; } } + + private ArrayList filter(ArrayList documents, HashSet restricted) { + if (restricted == null) return documents; + for (int i = 0; i < documents.size(); ++i) { + TLRPC.Document d = documents.get(i); + if (d == null || restricted.contains(d.id)) { + documents.remove(i); + i--; + } + } + return documents; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index d548f11b6..37fd08fdc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java @@ -471,7 +471,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } if (!hasOverlayText) { - titleView.setText(currentTitle, animated); + titleView.setText(currentTitle, animated && !LocaleController.isRTL); } miniItems.clear(); @@ -911,12 +911,12 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter textToSet = spannableString; } } - titleView.setText(textToSet, true); + titleView.setText(textToSet, !LocaleController.isRTL); } } else { hasOverlayText = false; overlayTextId = 0; - titleView.setText(currentTitle, true); + titleView.setText(currentTitle, !LocaleController.isRTL); } if (hasEllipsizedText) { ellipsizeSpanAnimator.addView(titleView); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java index 32d8b23fa..073ff7987 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java @@ -5,6 +5,7 @@ import static org.telegram.messenger.SharedConfig.getDevicePerformanceClass; import android.annotation.SuppressLint; import android.content.Context; +import android.util.Log; import android.view.TextureView; import android.view.View; import android.widget.FrameLayout; 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 50b7e2100..1aa07b023 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -35,7 +35,6 @@ 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; @@ -319,7 +318,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private AnimatedFloat linesAlpha = new AnimatedFloat(this); private float prevToHideProgress; public long videoDuration; - private boolean allowShare, allowShareLink; + private boolean allowShare, allowRepost, allowShareLink; public boolean forceUpdateOffsets; private HintView mediaBanTooltip; @@ -421,7 +420,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica this.resourcesProvider = resourcesProvider; setClipChildren(false); - storyAreasView = new StoryMediaAreasView(context, resourcesProvider) { + storyAreasView = new StoryMediaAreasView(context, storyContainer, resourcesProvider) { @Override protected void onHintVisible(boolean hintVisible) { if (delegate != null) { @@ -449,15 +448,20 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica v.playAnimation(); emojiAnimationsOverlay.showAnimationForWidget(v); } + + @Override + protected Bitmap getPlayingBitmap() { + return PeerStoriesView.this.getPlayingBitmap(); + } }; storyContainer = new HwFrameLayout(context) { - AnimatedFloat progressToAudio = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); - AnimatedFloat progressToFullBlackoutA = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); - CellFlickerDrawable loadingDrawable = new CellFlickerDrawable(32, 102, 240); - AnimatedFloat loadingDrawableAlpha2 = new AnimatedFloat(this); - AnimatedFloat loadingDrawableAlpha = new AnimatedFloat(this); + final AnimatedFloat progressToAudio = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); + final AnimatedFloat progressToFullBlackoutA = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); + final CellFlickerDrawable loadingDrawable = new CellFlickerDrawable(32, 102, 240); + final AnimatedFloat loadingDrawableAlpha2 = new AnimatedFloat(this); + final AnimatedFloat loadingDrawableAlpha = new AnimatedFloat(this); { loadingDrawableAlpha2.setDuration(500); loadingDrawableAlpha.setDuration(100); @@ -472,7 +476,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica headerView.backupImageView.getImageReceiver().setVisible(true, true); } if (!unsupported) { - if (playerSharedScope.renderView != null) { + if (playerSharedScope.renderView != null || storyAreasView != null && (storyAreasView.hasSelectedForScale() || storyAreasView.parentHighlightScaleAlpha.isInProgress())) { invalidate(); } canvas.save(); @@ -896,6 +900,17 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @Override public void onReplyClick(Reply reply) { if (reply == null) return; + if (reply.isRepostMessage && reply.peerId != null && reply.messageId != null) { + Bundle args = new Bundle(); + if (reply.peerId >= 0) { + args.putLong("user_id", reply.peerId); + } else { + args.putLong("chat_id", -reply.peerId); + } + args.putInt("message_id", reply.messageId); + storyViewer.presentFragment(new ChatActivity(args)); + return; + } if (reply.peerId == null || reply.storyId == null) { BulletinFactory.of(storyContainer, resourcesProvider) .createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.StoryHidAccount)) @@ -1222,7 +1237,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica time = playerSharedScope.player.currentPosition; } StoryEntry entry = MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().getForEdit(currentStory.storyItem.dialogId, currentStory.storyItem); - if (entry == null || entry.file == null || !entry.file.exists()) { + if (entry == null || entry.isRepostMessage || entry.file == null || !entry.file.exists()) { entry = StoryEntry.fromStoryItem(currentStory.getPath(), currentStory.storyItem); entry.editStoryPeerId = dialogId; } @@ -1326,7 +1341,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } - if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !isChannel) { createStealthModeItem(popupLayout); } @@ -1445,7 +1460,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica popupMenu.dismiss(); } }); - } else if (!MessagesController.getInstance(currentAccount).premiumLocked) { + } else if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { Drawable lockIcon = ContextCompat.getDrawable(context, R.drawable.msg_gallery_locked2); lockIcon.setColorFilter(new PorterDuffColorFilter(ColorUtils.blendARGB(Color.WHITE, Color.BLACK, 0.5f), PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable( @@ -1474,7 +1489,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !isChannel) { createStealthModeItem(popupLayout); } if (allowShareLink) { @@ -2208,13 +2223,13 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } @Override - public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { + public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { checkInstantCameraView(); if (instantCameraView != null) { if (state == 0) { instantCameraView.showCamera(); } else if (state == 1 || state == 3 || state == 4) { - instantCameraView.send(state, notify, scheduleDate); + instantCameraView.send(state, notify, scheduleDate, ttl); } else if (state == 2 || state == 5) { instantCameraView.cancel(state == 2); } @@ -2612,6 +2627,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica shareAlert = null; } + @Override + protected void onShareStory(View cell) { + tryToOpenRepostStory(); + } + @Override protected void onSend(LongSparseArray dids, int count, TLRPC.TL_forumTopic topic) { super.onSend(dids, count, topic); @@ -2619,9 +2639,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (bulletinFactory != null) { if (dids.size() == 1) { long did = dids.keyAt(0); - if (did == Long.MAX_VALUE) { - tryToOpenRepostStory(); - } else if (did == UserConfig.getInstance(currentAccount).clientUserId) { + if (did == UserConfig.getInstance(currentAccount).clientUserId) { bulletinFactory.createSimpleBulletin(R.raw.saved_messages, AndroidUtilities.replaceTags(LocaleController.formatString("StorySharedToSavedMessages", R.string.StorySharedToSavedMessages)), Bulletin.DURATION_PROLONG).hideAfterBottomSheet(false).show(); } else if (did < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); @@ -2837,10 +2855,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica isSelf = false; isChannel = true; - //TODO uncomment if server support views for channels -// if (storiesController.canEditStories(dialogId)) { -// userCanSeeViews = true; -// } + if (storiesController.canEditStories(dialogId) || BuildVars.DEBUG_PRIVATE_VERSION) { + userCanSeeViews = true; + } TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); avatarDrawable.setInfo(currentAccount, chat); headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable); @@ -3480,7 +3497,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } currentStory.set(uploadingStory); storyAreasView.set(null, StoryMediaAreasView.getMediaAreasFor(uploadingStory.entry), emojiAnimationsOverlay); - allowShare = allowShareLink = false; + allowShare = allowRepost = allowShareLink = false; } else { isUploading = false; isEditing = false; @@ -3503,9 +3520,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica currentStory.set(editingStory); storyAreasView.set(null, StoryMediaAreasView.getMediaAreasFor(editingStory.entry), emojiAnimationsOverlay); currentStory.editingSourceItem = storyItem; - allowShare = allowShareLink = false; + allowShare = allowRepost = allowShareLink = false; } else { - boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.document); + boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.getDocument()); Drawable thumbDrawable = null; storyItem.dialogId = dialogId; imageReceiver.setCrossfadeWithOldImage(wasEditing); @@ -3518,7 +3535,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } if (isVideo) { if (storyItem.media != null) { - thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.document.thumbs); + thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.getDocument().thumbs); } if (storyItem.firstFramePath != null && ImageLoader.getInstance().isInMemCache(ImageLocation.getForPath(storyItem.firstFramePath).getKey(null, null, false) + "@" + filter, false)) { imageReceiver.setImage(null, null, ImageLocation.getForPath(storyItem.firstFramePath), filter, null, null, thumbDrawable, 0, null, null, 0); @@ -3542,11 +3559,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } storyItem.dialogId = dialogId; if (isVideo) { - TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.document.thumbs, 1000); + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.getDocument().thumbs, 1000); if (thumbDrawable == null) { - thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.document.thumbs); + thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.getDocument().thumbs); } - imageReceiver.setImage(null, null, ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, thumbDrawable, 0, null, storyItem, 0); + imageReceiver.setImage(null, null, ImageLocation.getForDocument(storyItem.media.getDocument()), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.getDocument()), filter, thumbDrawable, 0, null, storyItem, 0); } else { TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; if (photo != null && photo.sizes != null) { @@ -3572,6 +3589,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (allowShare) { allowShare = currentStory.allowScreenshots() && currentStory.storyItem.isPublic; } + allowRepost = allowShare; + if (allowRepost && isChannel) { + final TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + allowRepost = chat != null && ChatObject.isPublic(chat); + } if (allowShareLink) { if (isChannel) { final TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); @@ -3640,23 +3662,24 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else if (currentStory.storyItem != null) { if (currentStory.storyItem.date == -1) { headerView.setSubtitle(LocaleController.getString("CachedStory", R.string.CachedStory)); - } else if (currentStory.storyItem.fwd_from != null) { + } else if (currentStory.getReply() != null) { + StoryCaptionView.Reply reply = currentStory.getReply(); + SpannableStringBuilder ssb = new SpannableStringBuilder(); SpannableString repostIcon = new SpannableString("r"); repostIcon.setSpan(new ColoredImageSpan(R.drawable.mini_repost_story), 0, repostIcon.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append(repostIcon).append(" "); - if (currentStory.storyItem.fwd_from.from != null) { + if (reply.peerId != null) { AvatarSpan avatar = new AvatarSpan(headerView.subtitleView[0], currentAccount, 15); SpannableString avatarStr = new SpannableString("a"); avatarStr.setSpan(avatar, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append(avatarStr).append(" "); - long did = DialogObject.getPeerDialogId(currentStory.storyItem.fwd_from.from); - if (did > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); + if (reply.peerId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(reply.peerId); avatar.setUser(user); ssb.append(UserObject.getUserName(user)); } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-reply.peerId); avatar.setChat(chat); if (chat != null) { ssb.append(chat.title); @@ -3666,15 +3689,19 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica ssb.append(currentStory.storyItem.fwd_from.from_name); } headerView.setOnSubtitleClick(v -> { - if (currentStory.storyItem.fwd_from.from != null) { - long did = DialogObject.getPeerDialogId(currentStory.storyItem.fwd_from.from); + if (reply.peerId != null) { Bundle args = new Bundle(); - if (did >= 0) { - args.putLong("user_id", did); + if (reply.peerId >= 0) { + args.putLong("user_id", reply.peerId); } else { - args.putLong("chat_id", -did); + args.putLong("chat_id", -reply.peerId); + } + if (reply.isRepostMessage && reply.messageId != null) { + args.putInt("message_id", reply.messageId); + storyViewer.presentFragment(new ChatActivity(args)); + } else { + storyViewer.presentFragment(new ProfileActivity(args)); } - storyViewer.presentFragment(new ProfileActivity(args)); } else { BulletinFactory.of(storyContainer, resourcesProvider) .createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.StoryHidAccount)) @@ -3730,7 +3757,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica createReplyDisabledView(); unsupportedContainer.setVisibility(View.VISIBLE); replyDisabledTextView.setVisibility(View.VISIBLE); - allowShare = allowShareLink = false; + allowShare = allowRepost = allowShareLink = false; if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); } @@ -3774,7 +3801,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (isChannel) { shareButton.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); if (repostButtonContainer != null) { - repostButtonContainer.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + repostButtonContainer.setVisibility(allowRepost ? View.VISIBLE : View.GONE); } likeButtonContainer.setVisibility(isFailed ? View.GONE : View.VISIBLE); } else { @@ -3982,9 +4009,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica storyItem.dialogId = dialogId; setStoryImage(storyItem, imageReceiver, filter); - boolean isVideo = storyItem.media != null && storyItem.media.document != null && MessageObject.isVideoDocument(storyItem.media.document); + boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.getDocument()); if (isVideo) { - TLRPC.Document document = storyItem.media.document; + TLRPC.Document document = storyItem.media.getDocument(); if (storyItem.fileReference == 0) { storyItem.fileReference = FileLoader.getInstance(currentAccount).getFileReference(storyItem); } @@ -4032,7 +4059,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica setStoryImage(editingStory, imageReceiver, filter); return; } - boolean isVideo = storyItem.media != null && storyItem.media.document != null && MessageObject.isVideoDocument(storyItem.media.document); + boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.getDocument()); if (storyItem.attachPath != null) { if (storyItem.media == null) { @@ -4045,8 +4072,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } else { if (isVideo) { - TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.document.thumbs, 1000); - imageReceiver.setImage(ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, null, 0, null, storyItem, 0); + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.getDocument().thumbs, 1000); + imageReceiver.setImage(ImageLocation.getForDocument(storyItem.media.getDocument()), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.getDocument()), filter, null, null, null, 0, null, storyItem, 0); } else { TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; if (photo != null && photo.sizes != null) { @@ -4214,7 +4241,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else if (currentStory.storyItem != null) { currentStory.storyItem.dialogId = dialogId; try { - document = currentStory.storyItem.media.document; + document = currentStory.storyItem.media.getDocument(); if (currentStory.storyItem.fileReference == 0) { currentStory.storyItem.fileReference = FileLoader.getInstance(currentAccount).getFileReference(currentStory.storyItem); } @@ -4275,9 +4302,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica this.delegate = delegate; } - public void createBlurredBitmap(Canvas canvas, Bitmap bitmap) { + public void drawPlayingBitmap(int w, int h, Canvas canvas) { if (playerSharedScope.renderView != null && playerSharedScope.surfaceView != null) { - Bitmap surfaceBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Bitmap surfaceBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { AndroidUtilities.getBitmapFromSurface(playerSharedScope.surfaceView, surfaceBitmap); } @@ -4285,16 +4312,26 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica canvas.drawBitmap(surfaceBitmap, 0, 0, null); } } else if (playerSharedScope.renderView != null && playerSharedScope.textureView != null) { - Bitmap textureBitmap = playerSharedScope.textureView.getBitmap(bitmap.getWidth(), bitmap.getHeight()); + Bitmap textureBitmap = playerSharedScope.textureView.getBitmap(w, h); if (textureBitmap != null) { canvas.drawBitmap(textureBitmap, 0, 0, null); } } else { canvas.save(); - canvas.scale(bitmap.getWidth() / (float) storyContainer.getMeasuredWidth(), bitmap.getHeight() / (float) storyContainer.getMeasuredHeight()); + canvas.scale(w / (float) storyContainer.getMeasuredWidth(), h / (float) storyContainer.getMeasuredHeight()); imageReceiver.draw(canvas); canvas.restore(); } + } + + public Bitmap getPlayingBitmap() { + Bitmap bitmap = Bitmap.createBitmap(storyContainer.getWidth(), storyContainer.getHeight(), Bitmap.Config.ARGB_8888); + drawPlayingBitmap(bitmap.getWidth(), bitmap.getHeight(), new Canvas(bitmap)); + return bitmap; + } + + public void createBlurredBitmap(Canvas canvas, Bitmap bitmap) { + drawPlayingBitmap(bitmap.getWidth(), bitmap.getHeight(), canvas); int color = AndroidUtilities.getDominantColor(bitmap); float brightness = AndroidUtilities.computePerceivedBrightness(color); if (brightness < 0.15f) { @@ -5093,8 +5130,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (uploadingStory != null) { return uploadingStory.isVideo; } - if (storyItem != null && storyItem.media != null && storyItem.media.document != null) { - return storyItem.media.document != null && MessageObject.isVideoDocument(storyItem.media.document); + if (storyItem != null && storyItem.media != null && storyItem.media.getDocument() != null) { + return MessageObject.isVideoDocument(storyItem.media.getDocument()); } if (storyItem != null && storyItem.media == null && storyItem.attachPath != null) { return storyItem.attachPath.toLowerCase().endsWith(".mp4"); @@ -5168,9 +5205,10 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (!isVideo) { return false; } - if (storyItem != null && storyItem.media != null && storyItem.media.document != null) { - for (int i = 0; i < storyItem.media.document.attributes.size(); i++) { - TLRPC.DocumentAttribute attribute = storyItem.media.document.attributes.get(i); + TLRPC.Document document; + if (storyItem != null && storyItem.media != null && (document = storyItem.media.getDocument()) != null) { + for (int i = 0; i < document.attributes.size(); i++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(i); if (attribute instanceof TLRPC.TL_documentAttributeVideo && attribute.nosound) { return false; } @@ -5206,8 +5244,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica return new File(getLocalPath()); } if (storyItem != null) { - if (storyItem.media != null && storyItem.media.document != null) { - return FileLoader.getInstance(currentAccount).getPathToAttach(storyItem.media.document); + if (storyItem.media != null && storyItem.media.getDocument() != null) { + return FileLoader.getInstance(currentAccount).getPathToAttach(storyItem.media.getDocument()); } else if (storyItem.media != null && storyItem.media.photo != null) { TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.photo.sizes, Integer.MAX_VALUE); File file = FileLoader.getInstance(currentAccount).getPathToAttach(size, true); @@ -5520,7 +5558,18 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else { inputBackgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (140 * hideInterfaceAlpha * (1f - outT)))); } - if (forceUpdateOffsets || progressToReply != storyViewer.swipeToReplyProgress || progressToHideInterface.get() != prevToHideProgress || lastAnimatingKeyboardHeight != animatingKeyboardHeight || progressToKeyboardLocal != progressToKeyboard || progressToDismissLocal != progressToDismiss || progressToRecord != progressToRecording.get() || popupVisible || progressToStickerExpandedLocal != progressToStickerExpanded.get() || progressToText != progressToTextA.get()) { + if ( + forceUpdateOffsets || + progressToReply != storyViewer.swipeToReplyProgress || + progressToHideInterface.get() != prevToHideProgress || + lastAnimatingKeyboardHeight != animatingKeyboardHeight || + progressToKeyboardLocal != progressToKeyboard || + progressToDismissLocal != progressToDismiss || + progressToRecord != progressToRecording.get() || + popupVisible || + progressToStickerExpandedLocal != progressToStickerExpanded.get() || + progressToText != progressToTextA.get() + ) { forceUpdateOffsets = false; lastAnimatingKeyboardHeight = animatingKeyboardHeight; if (progressToHideInterface.get() != prevToHideProgress) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java index dcd21c654..e5995d34b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java @@ -11,8 +11,11 @@ import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -33,9 +36,11 @@ import com.google.android.exoplayer2.util.Consumer; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -51,6 +56,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.FixedHeightEmptyCell; import org.telegram.ui.Cells.ReactedUserHolderView; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; @@ -118,7 +124,6 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente SelfStoryViewsView.StoryItemInternal storyItem; ViewsModel currentModel; ViewsModel defaultModel; - ViewsModel filteredModel; private boolean isAttachedToWindow; RecyclerItemsEnterAnimator recyclerItemsEnterAnimator; StoryViewer storyViewer; @@ -136,7 +141,11 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente private boolean showServerErrorText; private long dialogId; - private boolean isStoryShownToUser(TL_stories.TL_storyView view) { + private boolean isStoryShownToUser(TL_stories.StoryView view) { + if (view == null) { + return true; + } + if (MessagesController.getInstance(currentAccount).getStoriesController().isBlocked(view)) { return false; } @@ -230,9 +239,38 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (position < 0 || position >= listAdapter.items.size()) { return; } - TL_stories.TL_storyView user = listAdapter.items.get(position).user; - if (user != null) { - storyViewer.presentFragment(ProfileActivity.of(user.user_id)); + Item item = listAdapter.items.get(position); + if (item.view instanceof TL_stories.TL_storyView) { + storyViewer.presentFragment(ProfileActivity.of(item.view.user_id)); + } else if (item.view instanceof TL_stories.TL_storyViewPublicRepost) { + if (storyViewer.fragment.getOrCreateOverlayStoryViewer().isShowing) { + return; + } + storyViewer.fragment.getOrCreateOverlayStoryViewer().open(getContext(), ((TL_stories.TL_storyViewPublicRepost) item.view).story, StoriesListPlaceProvider.of(recyclerListView)); + } else if (item.reaction instanceof TL_stories.TL_storyReaction) { + storyViewer.presentFragment(ProfileActivity.of(DialogObject.getPeerDialogId(item.reaction.peer_id))); + } else if (item.reaction instanceof TL_stories.TL_storyReactionPublicRepost) { + if (storyViewer.fragment.getOrCreateOverlayStoryViewer().isShowing) { + return; + } + storyViewer.fragment.getOrCreateOverlayStoryViewer().open(getContext(), ((TL_stories.TL_storyReactionPublicRepost) item.reaction).story, StoriesListPlaceProvider.of(recyclerListView)); + } else if (item.reaction instanceof TL_stories.TL_storyReactionPublicForward || item.view instanceof TL_stories.TL_storyViewPublicForward) { + TLRPC.Message message; + if (item.reaction instanceof TL_stories.TL_storyReactionPublicForward) { + message = item.reaction.message; + } else { + message = item.view.message; + } + Bundle args = new Bundle(); + long dialogId = DialogObject.getPeerDialogId(message.peer_id); + if (dialogId >= 0) { + args.putLong("user_id", dialogId); + } else { + args.putLong("chat_id", -dialogId); + } + args.putInt("message_id", message.id); + ChatActivity chatActivity = new ChatActivity(args); + storyViewer.presentFragment(chatActivity); } }); recyclerListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @@ -245,7 +283,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (storyViewer == null || storyViewer.containerView == null) { return false; } - TL_stories.TL_storyView viewUser = listAdapter.items.get(position).user; + TL_stories.StoryView viewUser = listAdapter.items.get(position).view; if (viewUser == null) { return false; } @@ -501,18 +539,25 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (serverItem.views != null) { showSearch = serverItem.views.views_count >= 15; showReactionsSort = serverItem.views.reactions_count >= (BuildVars.DEBUG_PRIVATE_VERSION ? 5 : 10); - showContactsFilter = serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; + showContactsFilter = serverItem.dialogId >= 0 && serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; } - defaultModel = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(serverItem.id); + SparseArray models = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(serverItem.dialogId); + defaultModel = models != null ? models.get(serverItem.id) : null; int totalCount = serverItem.views == null ? 0 : serverItem.views.views_count; - if (defaultModel == null || defaultModel.totalCount != totalCount) { + if (defaultModel == null || !defaultModel.isChannel && defaultModel.totalCount != totalCount) { if (defaultModel != null) { defaultModel.release(); } defaultModel = new ViewsModel(currentAccount, dialogId, serverItem, true); defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); defaultModel.loadNext(); - MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, defaultModel); + if (models != null) { + models.put(serverItem.id, defaultModel); + } else { + models = new SparseArray<>(); + models.put(serverItem.id, defaultModel); + MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.dialogId, models); + } } else { defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); } @@ -523,11 +568,11 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (currentModel != null && isAttachedToWindow) { currentModel.addListener(this); } - if ((currentModel.isExpiredViews && !UserConfig.getInstance(currentAccount).isPremium()) || (!currentModel.loading && !currentModel.hasNext && currentModel.views.isEmpty() && TextUtils.isEmpty(currentModel.state.searchQuery))) { + if ((currentModel != null && currentModel.isExpiredViews && !UserConfig.getInstance(currentAccount).isPremium()) || (!currentModel.loading && !currentModel.hasNext && currentModel.views.isEmpty() && currentModel.reactions.isEmpty() && TextUtils.isEmpty(currentModel.state.searchQuery))) { showSearch = false; showReactionsSort = false; showContactsFilter = false; - titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + titleView.setText(LocaleController.getString(currentModel.isChannel ? R.string.Reactions : R.string.Viewers)); searchField.setVisibility(View.GONE); headerView.setVisibility(View.GONE); TOP_PADDING = 46; @@ -535,29 +580,29 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente showSearch = false; showReactionsSort = false; showContactsFilter = false; - titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + titleView.setText(LocaleController.getString(currentModel.isChannel ? R.string.Reactions : R.string.Viewers)); searchField.setVisibility(View.GONE); headerView.setVisibility(View.GONE); TOP_PADDING = 46; } else { headerView.setVisibility(View.VISIBLE); if (currentModel.showReactionOnly) { - titleView.setText(LocaleController.formatPluralString("Likes", serverItem.views.reactions_count, serverItem.views.reactions_count)); + titleView.setText(LocaleController.getString(currentModel.isChannel ? R.string.Reactions : R.string.Viewers)); showSearch = false; showReactionsSort = false; showContactsFilter = false; } else { - if (currentModel.views.size() < 20 && currentModel.views.size() < serverItem.views.views_count && !currentModel.loading && !currentModel.hasNext) { + if (currentModel.getCount() < 20 && currentModel.getCount() < serverItem.views.views_count && !currentModel.loading && !currentModel.hasNext) { showSearch = false; showReactionsSort = false; showContactsFilter = false; showServerErrorText = true; } else { - showSearch = serverItem.views.views_count >= 15; + showSearch = !currentModel.isChannel && serverItem.views.views_count >= 15; showReactionsSort = serverItem.views.reactions_count >= (BuildVars.DEBUG_VERSION ? 5 : 10); - showContactsFilter = serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; + showContactsFilter = serverItem.dialogId >= 0 && serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; } - titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + titleView.setText(LocaleController.getString(currentModel.isChannel ? R.string.Reactions : R.string.Viewers)); } searchField.setVisibility(showSearch ? View.VISIBLE : View.GONE); TOP_PADDING = showSearch ? 96 : 46; @@ -587,7 +632,8 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (storyItem == null) { return; } - ViewsModel model = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(storyItem.id); + SparseArray models = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(storyItem.dialogId); + ViewsModel model = models == null ? null : models.get(storyItem.id); int totalCount = storyItem.views == null ? 0 : storyItem.views.views_count; if (model == null || model.totalCount != totalCount) { if (model != null) { @@ -595,7 +641,10 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente } model = new ViewsModel(currentAccount, dialogId, storyItem, true); model.loadNext(); - MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(storyItem.id, model); + if (models == null) { + MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(storyItem.dialogId, models = new SparseArray<>()); + } + models.put(storyItem.id, model); } } @@ -674,7 +723,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (position < 0 || position >= listAdapter.items.size()) { continue; } - ((ReactedUserHolderView) child).animateAlpha(isStoryShownToUser(listAdapter.items.get(position).user) ? 1 : .5f, true); + ((ReactedUserHolderView) child).animateAlpha(isStoryShownToUser(listAdapter.items.get(position).view) ? 1 : .5f, true); } } } @@ -836,7 +885,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente emptyView.title.setVisibility(View.GONE); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(AndroidUtilities.replaceTags(LocaleController.getString("ExpiredViewsStub", R.string.ExpiredViewsStub))); - if (!MessagesController.getInstance(currentAccount).premiumLocked) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { spannableStringBuilder.append("\n\n"); spannableStringBuilder.append(AndroidUtilities.replaceSingleTag(LocaleController.getString("ExpiredViewsStubPremiumDescription", R.string.ExpiredViewsStubPremiumDescription), SelfStoryViewsPage.this::showPremiumAlert)); emptyView.createButtonLayout(LocaleController.getString("LearnMore", R.string.LearnMore), SelfStoryViewsPage.this::showPremiumAlert); @@ -844,8 +893,13 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente emptyView.subtitle.setText(spannableStringBuilder); } else { emptyView.title.setVisibility(View.VISIBLE); - emptyView.title.setText(LocaleController.getString("NoViews", R.string.NoViews)); - emptyView.setSubtitle(LocaleController.getString("NoViewsStub", R.string.NoViewsStub)); + if (defaultModel.isChannel) { + emptyView.title.setText(LocaleController.getString(R.string.NoReactions)); + emptyView.setSubtitle(LocaleController.getString(R.string.NoReactionsStub)); + } else { + emptyView.title.setText(LocaleController.getString(R.string.NoViews)); + emptyView.setSubtitle(LocaleController.getString(R.string.NoViewsStub)); + } } emptyView.showProgress(false, false); view = emptyView; @@ -857,21 +911,78 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (holder.getItemViewType() == USER_ITEM) { + if (position < 0 || position >= items.size()) return; + final Item item = items.get(position); ReactedUserHolderView view = (ReactedUserHolderView) holder.itemView; - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(items.get(position).user.user_id); - boolean animated = defaultModel.animateDateForUsers.remove(items.get(position).user.user_id); - boolean like = false; - if (items.get(position).user.reaction != null) { - ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(items.get(position).user.reaction); - if (visibleReaction != null && visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")) { - like = true; + TLRPC.Peer peer = null; + if (item.view != null) { + if (item.view instanceof TL_stories.TL_storyViewPublicRepost) { + peer = item.view.peer_id; + } else if (item.view instanceof TL_stories.TL_storyViewPublicForward && item.view.message != null) { + peer = item.view.message.peer_id; + } else { + peer = new TLRPC.TL_peerUser(); + peer.user_id = item.view.user_id; + } + } else if (item.reaction != null) { + peer = item.reaction.peer_id; + if (item.reaction instanceof TL_stories.TL_storyReactionPublicForward && item.reaction.message != null) { + peer = item.reaction.message.peer_id; } } - view.setUserReaction(user, null, like ? null : items.get(position).user.reaction, like, items.get(position).user.date, true, animated); - int nextItemType = position < items.size() - 1 ? items.get(position + 1).viewType : -1; - view.drawDivider = nextItemType == USER_ITEM || nextItemType == SUBSCRIBE_TO_PREMIUM_TEXT_HINT || nextItemType == SERVER_CANT_RETURN_TEXT_HINT; - view.animateAlpha(isStoryShownToUser(items.get(position).user) ? 1f : .5f, false); + long did = DialogObject.getPeerDialogId(peer); + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (did >= 0) { + user = MessagesController.getInstance(currentAccount).getUser(did); + } else { + chat = MessagesController.getInstance(currentAccount).getChat(-did); + } + boolean animated = defaultModel.animateDateForUsers.remove(did); + + if (item.view != null) { + boolean like = false; + if (item.view.reaction != null) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(item.view.reaction); + if (visibleReaction != null && visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")) { + like = true; + } + } + if (item.view instanceof TL_stories.TL_storyViewPublicRepost) { + view.setUserReaction(user, null, null, like, 0, item.view.story, false, true, animated); + } else if (item.view instanceof TL_stories.TL_storyViewPublicForward) { + view.setUserReaction(user, null, null, like, item.view.message != null ? item.view.message.date : 0, storyItem == null ? null : storyItem.storyItem, true, true, animated); + } else { + view.setUserReaction(user, null, like ? null : item.view.reaction, like, item.view.date, null, false, true, animated); + } + int nextItemType = position < items.size() - 1 ? items.get(position + 1).viewType : -1; + view.drawDivider = nextItemType == USER_ITEM || nextItemType == SUBSCRIBE_TO_PREMIUM_TEXT_HINT || nextItemType == SERVER_CANT_RETURN_TEXT_HINT; + view.animateAlpha(isStoryShownToUser(item.view) ? 1f : .5f, false); + } else if (item.reaction != null) { + TL_stories.StoryReaction peerReaction = item.reaction; + + if (peerReaction instanceof TL_stories.TL_storyReaction) { + TL_stories.TL_storyReaction reaction = (TL_stories.TL_storyReaction) peerReaction; + boolean like = false; + if (reaction.reaction != null) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(reaction.reaction); + if (visibleReaction != null && visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")) { + like = true; + } + } + view.setUserReaction(user, chat, like ? null : reaction.reaction, like, reaction.date, null, false, true, animated); + } else if (peerReaction instanceof TL_stories.TL_storyReactionPublicRepost) { + TL_stories.TL_storyReactionPublicRepost repost = (TL_stories.TL_storyReactionPublicRepost) peerReaction; + view.setUserReaction(user, chat, null, false, 0, repost.story, false, true, animated); + } else if (peerReaction instanceof TL_stories.TL_storyReactionPublicForward) { + view.setUserReaction(user, chat, null, false, peerReaction.message != null ? peerReaction.message.date : 0, storyItem == null ? null : storyItem.storyItem, true, true, animated); + } + + int nextItemType = position < items.size() - 1 ? items.get(position + 1).viewType : -1; + view.drawDivider = nextItemType == USER_ITEM || nextItemType == SUBSCRIBE_TO_PREMIUM_TEXT_HINT || nextItemType == SERVER_CANT_RETURN_TEXT_HINT; + view.animateAlpha(1f, false); + } } } @@ -893,7 +1004,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente items.add(new Item(FLICKER_LOADING_ITEM_FULL)); } else { items.add(new Item(FIRST_PADDING_ITEM)); - if (model != null && model.views.isEmpty() && (model.isExpiredViews || (!model.loading && !model.hasNext))) { + if (model != null && model.getCount() <= 0 && (model.isExpiredViews || (!model.loading && !model.hasNext))) { if (!TextUtils.isEmpty(model.state.searchQuery)) { items.add(new Item(EMPTY_VIEW_SEARCH)); } else if (model.isExpiredViews) { @@ -907,19 +1018,25 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente } } else { if (model != null) { - for (int i = 0; i < model.views.size(); i++) { - items.add(new Item(USER_ITEM, model.views.get(i))); + if (model.isChannel) { + for (int i = 0; i < model.reactions.size(); i++) { + items.add(new Item(USER_ITEM, model.reactions.get(i))); + } + } else { + for (int i = 0; i < model.views.size(); i++) { + items.add(new Item(USER_ITEM, model.views.get(i))); + } } } if (model != null && (model.loading || model.hasNext)) { - if (model.views.isEmpty()) { + if (model.getCount() <= 0) { items.add(new Item(FLICKER_LOADING_ITEM_FULL)); } else { items.add(new Item(FLICKER_LOADING_ITEM)); } } else if (model != null && model.showReactionOnly) { items.add(new Item(SUBSCRIBE_TO_PREMIUM_TEXT_HINT)); - } else if (model != null && model.views.size() < model.totalCount && TextUtils.isEmpty(model.state.searchQuery) && !model.state.contactsOnly) { + } else if (model != null && model.getCount() < model.totalCount && TextUtils.isEmpty(model.state.searchQuery) && !model.state.contactsOnly) { items.add(new Item(SERVER_CANT_RETURN_TEXT_HINT)); } } @@ -939,17 +1056,27 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente sheet.show(); } - private class Item { + private static class Item { final int viewType; - TL_stories.TL_storyView user; + final TL_stories.StoryView view; + final TL_stories.StoryReaction reaction; private Item(int viewType) { this.viewType = viewType; + this.view = null; + this.reaction = null; } - private Item(int viewType, TL_stories.TL_storyView user) { + private Item(int viewType, TL_stories.StoryView view) { this.viewType = viewType; - this.user = user; + this.view = view; + this.reaction = null; + } + + private Item(int viewType, TL_stories.StoryReaction reaction) { + this.viewType = viewType; + this.view = null; + this.reaction = reaction; } } @@ -960,8 +1087,10 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente private long dialogId; int currentAccount; boolean loading; - ArrayList views = new ArrayList<>(); - ArrayList originalViews = new ArrayList<>(); + public final boolean isChannel; + ArrayList views = new ArrayList<>(); + ArrayList originalViews = new ArrayList<>(); + ArrayList reactions = new ArrayList<>(); boolean isExpiredViews; boolean showReactionOnly; boolean initial; @@ -971,12 +1100,17 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente HashSet animateDateForUsers = new HashSet<>(); boolean useLocalFilters; + public int getCount() { + return isChannel ? reactions.size() : views.size(); + } + ArrayList listeners = new ArrayList<>(); FiltersState state = new FiltersState(); public ViewsModel(int currentAccount, long dialogId, TL_stories.StoryItem storyItem, boolean isDefault) { this.currentAccount = currentAccount; this.storyItem = storyItem; + isChannel = dialogId < 0; this.dialogId = dialogId; this.totalCount = storyItem.views == null ? 0 : storyItem.views.views_count; if (totalCount < 200) { @@ -1008,100 +1142,186 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente if (loading || !hasNext || isExpiredViews) { return; } - TL_stories.TL_stories_getStoryViewsList req = new TL_stories.TL_stories_getStoryViewsList(); - req.id = storyItem.id; - req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); - if (useLocalFilters) { - req.q = ""; - req.just_contacts = false; - req.reactions_first = true; - } else { - req.q = state.searchQuery; - if (!TextUtils.isEmpty(req.q)) { + if (isChannel) { + TL_stories.TL_getStoryReactionsList req = new TL_stories.TL_getStoryReactionsList(); + req.forwards_first = state.sortByReactions; + req.id = storyItem.id; + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + req.limit = (initial || reactions.size() < 20) ? 20 : 100; + req.offset = offset; + if (req.offset == null) { + req.offset = ""; + } else { req.flags |= 2; } - req.just_contacts = state.contactsOnly; - req.reactions_first = state.sortByReactions; - } - req.limit = (initial || views.size() < 20) ? 20 : 100; - req.offset = offset; - if (req.offset == null) { - req.offset = ""; - } - loading = true; - int[] localReqId = new int[1]; - FileLog.d("SelfStoryViewsPage load next " + storyItem.id + " " + initial + " offset=" + req.offset + " q" + req.q + " " + req.just_contacts + " " + req.reactions_first); - localReqId[0] = reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (localReqId[0] != reqId) { - FileLog.d("SelfStoryViewsPage " + storyItem.id + " localId != reqId"); - return; - } - loading = false; - reqId = -1; - if (response != null) { - TL_stories.TL_stories_storyViewsList res = (TL_stories.TL_stories_storyViewsList) response; - MessagesController.getInstance(currentAccount).getStoriesController().applyStoryViewsBlocked(res); - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - if (initial) { - initial = false; - for (int i = 0; i < views.size(); i++) { - animateDateForUsers.add(views.get(i).user_id); + loading = true; + int[] localReqId = new int[1]; + FileLog.d("SelfStoryViewsPage reactions load next " + storyItem.id + " " + initial + " offset=" + req.offset/* + " q" + req.q + " " + req.just_contacts + " " + req.reactions_first*/); + localReqId[0] = reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (localReqId[0] != reqId) { + FileLog.d("SelfStoryViewsPage reactions " + storyItem.id + " localId != reqId"); + return; + } + loading = false; + reqId = -1; + if (response != null) { + TL_stories.TL_storyReactionsList res = (TL_stories.TL_storyReactionsList) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, false); + if (initial) { + initial = false; + for (int i = 0; i < reactions.size(); i++) { + animateDateForUsers.add(DialogObject.getPeerDialogId(reactions.get(i).peer_id)); + } + reactions.clear(); + originalViews.clear(); } - views.clear(); - originalViews.clear(); - } - if (useLocalFilters) { - originalViews.addAll(res.views); - applyLocalFilter(); - } else { - views.addAll(res.views); - } +// if (useLocalFilters) { +// originalReactions.addAll(res.reactions); +// applyLocalFilter(); +// } else { + reactions.addAll(res.reactions); +// } - if (!res.views.isEmpty()) { - hasNext = true; + if (!res.reactions.isEmpty()) { + hasNext = true; + } else { + hasNext = false; + } + offset = res.next_offset; + if (TextUtils.isEmpty(offset)) { + hasNext = false; + } + + if (storyItem.views == null) { + storyItem.views = new TL_stories.TL_storyViews(); + } + boolean counterUpdated = totalCount != res.count; + totalCount = res.count; + if (counterUpdated) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); + } } else { - hasNext = false; - } - offset = res.next_offset; - if (TextUtils.isEmpty(offset)) { + if (error != null && "MSG_ID_INVALID".equals(error.text)) { + totalCount = 0; + } hasNext = false; } - if (storyItem.views == null) { - storyItem.views = new TL_stories.TL_storyViews(); + FileLog.d("SelfStoryViewsPage reactions " + storyItem.id + " response totalItems " + reactions.size() + " has next " + hasNext); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onDataRecieved(this); } - boolean counterUpdated = false; - if (res.count > storyItem.views.views_count) { - storyItem.views.recent_viewers.clear(); - for (int i = 0; i < (Math.min(3, res.users.size())); i++) { - storyItem.views.recent_viewers.add(res.users.get(i).id); - } - storyItem.views.views_count = res.count; - counterUpdated = true; - } - if (storyItem.views.reactions_count != res.reactions_count) { - storyItem.views.reactions_count = res.reactions_count; - counterUpdated = true; - } - if (counterUpdated) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); + if (reactions.size() < 20 && hasNext) { + loadNext(); } + })); + } else { + TL_stories.TL_stories_getStoryViewsList req = new TL_stories.TL_stories_getStoryViewsList(); + req.id = storyItem.id; + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + if (useLocalFilters) { + req.q = ""; + req.just_contacts = false; + req.reactions_first = true; } else { - hasNext = false; + req.q = state.searchQuery; + if (!TextUtils.isEmpty(req.q)) { + req.flags |= 2; + } + req.just_contacts = state.contactsOnly; + req.reactions_first = state.sortByReactions; + } + req.limit = (initial || views.size() < 20) ? 20 : 100; + req.offset = offset; + if (req.offset == null) { + req.offset = ""; } - FileLog.d("SelfStoryViewsPage " + storyItem.id + " response totalItems " + views.size() + " has next " + hasNext); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onDataRecieved(this); - } - if (views.size() < 20 && hasNext) { - loadNext(); - } - })); + loading = true; + int[] localReqId = new int[1]; + FileLog.d("SelfStoryViewsPage load next " + storyItem.id + " " + initial + " offset=" + req.offset + " q" + req.q + " " + req.just_contacts + " " + req.reactions_first); + localReqId[0] = reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (localReqId[0] != reqId) { + FileLog.d("SelfStoryViewsPage " + storyItem.id + " localId != reqId"); + return; + } + loading = false; + reqId = -1; + if (response != null) { + TL_stories.StoryViewsList res = (TL_stories.StoryViewsList) response; + MessagesController.getInstance(currentAccount).getStoriesController().applyStoryViewsBlocked(res); + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(res.users, res.chats, true, false); + if (initial) { + initial = false; + for (int i = 0; i < views.size(); i++) { + animateDateForUsers.add(views.get(i).user_id); + } + views.clear(); + originalViews.clear(); + } + if (useLocalFilters) { + originalViews.addAll(res.views); + applyLocalFilter(); + } else { + views.addAll(res.views); + } + + if (!res.views.isEmpty()) { + hasNext = true; + } else { + hasNext = false; + } + offset = res.next_offset; + if (TextUtils.isEmpty(offset)) { + hasNext = false; + } + + if (storyItem.views == null) { + storyItem.views = new TL_stories.TL_storyViews(); + } + boolean counterUpdated = false; + if (res.count > storyItem.views.views_count) { + storyItem.views.recent_viewers.clear(); + for (int i = 0; i < (Math.min(3, res.users.size())); i++) { + storyItem.views.recent_viewers.add(res.users.get(i).id); + } + storyItem.views.views_count = res.count; + counterUpdated = true; + } + if (storyItem.views.reactions_count != res.reactions_count) { + storyItem.views.reactions_count = res.reactions_count; + counterUpdated = true; + } + if (counterUpdated) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); + } + } else { + if (error != null && "MSG_ID_INVALID".equals(error.text)) { + totalCount = 0; + } + hasNext = false; + } + + FileLog.d("SelfStoryViewsPage " + storyItem.id + " response totalItems " + views.size() + " has next " + hasNext); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onDataRecieved(this); + } + if (views.size() < 20 && hasNext) { + loadNext(); + } + })); + } } private void applyLocalFilter() { + if (isChannel) { + return; + } views.clear(); if (state.contactsOnly || !TextUtils.isEmpty(state.searchQuery)) { String search1 = null; @@ -1165,7 +1385,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente return; } this.state.set(localState); - if (useLocalFilters) { + if (!isChannel && useLocalFilters) { applyLocalFilter(); for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onDataRecieved(this); @@ -1173,6 +1393,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente } else { release(); views.clear(); + reactions.clear(); initial = true; loading = false; hasNext = true; @@ -1266,7 +1487,8 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente @Override protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { popupLayout.setBackgroundColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.18f)); - ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, state.sortByReactions ? R.drawable.menu_views_reactions2 : R.drawable.menu_views_reactions, LocaleController.getString("SortByReactions", R.string.SortByReactions), false, resourcesProvider); + final boolean isChannel = currentModel != null && currentModel.isChannel; + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, isChannel ? R.drawable.menu_views_reposts : (state.sortByReactions ? R.drawable.menu_views_reactions2 : R.drawable.menu_views_reactions), LocaleController.getString(isChannel ? R.string.SortByReposts : R.string.SortByReactions), false, resourcesProvider); if (!state.sortByReactions) { item.setAlpha(0.5f); } @@ -1308,7 +1530,7 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getContext(), resourcesProvider, Theme.key_actionBarDefaultSubmenuSeparator); gap.setTag(R.id.fit_width_tag, 1); popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); - ActionBarMenuItem.addText(popupLayout, LocaleController.getString("StoryViewsSortDescription", R.string.StoryViewsSortDescription), resourcesProvider); + ActionBarMenuItem.addText(popupLayout, LocaleController.getString(isChannel ? R.string.StoryReactionsSortDescription : R.string.StoryViewsSortDescription), resourcesProvider); } @Override @@ -1405,14 +1627,12 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente private void updateViewState(boolean animated) { headerView.setState(state.contactsOnly, animated); - if (headerView.lastSortType != state.sortByReactions) { - headerView.lastSortType = state.sortByReactions; - headerView.replacableDrawable.setIcon(state.sortByReactions ? R.drawable.menu_views_reactions3 : R.drawable.menu_views_recent3, animated); - } + headerView.lastSortType = state.sortByReactions; + headerView.replacableDrawable.setIcon(state.sortByReactions ? (currentModel != null && currentModel.isChannel ? R.drawable.menu_views_reposts3 : R.drawable.menu_views_reactions3) : R.drawable.menu_views_recent3, animated); } public static class FiltersState { - boolean sortByReactions = true; + boolean sortByReactions = true; // converts to sortByForwards when showing channel reactions boolean contactsOnly; String searchQuery; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java index 30dda1c2c..064d40da7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -118,7 +118,7 @@ public class StoriesController { private final DraftsController draftsController; - public SparseArray selfViewsModel = new SparseArray<>(); + public LongSparseArray> selfViewsModel = new LongSparseArray<>(); private String stateHidden; private boolean hasMoreHidden = true; private boolean firstLoad = true; @@ -558,12 +558,12 @@ public class StoriesController { if (!canPreloadStories) { return; } - boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.document); + boolean isVideo = storyItem.media != null && MessageObject.isVideoDocument(storyItem.media.getDocument()); storyItem.dialogId = dialogId; if (isVideo) { - TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.document.thumbs, 1000); - FileLoader.getInstance(currentAccount).loadFile(storyItem.media.document, storyItem, FileLoader.PRIORITY_LOW, 1); - FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForDocument(size, storyItem.media.document), storyItem, "jpg", FileLoader.PRIORITY_LOW, 1); + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(storyItem.media.getDocument().thumbs, 1000); + FileLoader.getInstance(currentAccount).loadFile(storyItem.media.getDocument(), storyItem, FileLoader.PRIORITY_LOW, 1); + FileLoader.getInstance(currentAccount).loadFile(ImageLocation.getForDocument(size, storyItem.media.getDocument()), storyItem, "jpg", FileLoader.PRIORITY_LOW, 1); } else { TLRPC.Photo photo = storyItem.media == null ? null : storyItem.media.photo; if (photo != null && photo.sizes != null) { @@ -2458,6 +2458,12 @@ public class StoriesController { loadChatIds.add(-did); } } + for (int j = 0; j < storyItem.media_areas.size(); ++j) { + if (storyItem.media_areas.get(j) instanceof TL_stories.TL_mediaAreaChannelPost) { + long channel_id = ((TL_stories.TL_mediaAreaChannelPost) storyItem.media_areas.get(j)).channel_id; + loadChatIds.add(channel_id); + } + } msg.generateThumbs(false); cacheResult.add(msg); data.reuse(); @@ -2734,6 +2740,8 @@ public class StoriesController { FileLog.d("StoriesList " + type + "{"+ dialogId +"} loaded {" + storyItemMessageIds(newMessageObjects) + "}"); MessagesController.getInstance(currentAccount).putUsers(stories.users, false); + MessagesController.getInstance(currentAccount).putChats(stories.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(stories.users, stories.chats, true, true); loading = false; totalCount = stories.count; @@ -3120,7 +3128,7 @@ public class StoriesController { })); } - public boolean isBlocked(TL_stories.TL_storyView storyView) { + public boolean isBlocked(TL_stories.StoryView storyView) { if (storyView == null) { return false; } @@ -3143,12 +3151,12 @@ public class StoriesController { return blocklist.contains(did); } - public void applyStoryViewsBlocked(TL_stories.TL_stories_storyViewsList res) { + public void applyStoryViewsBlocked(TL_stories.StoryViewsList res) { if (res == null || res.views == null) { return; } for (int i = 0; i < res.views.size(); ++i) { - TL_stories.TL_storyView view = res.views.get(i); + TL_stories.StoryView view = res.views.get(i); if (blockedOverride.containsKey(view.user_id)) { blockedOverride.put(view.user_id, view.blocked_my_stories_from); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java index f54614683..427693c0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java @@ -206,17 +206,31 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { } else if (child instanceof ReactedUserHolderView) { ReactedUserHolderView cell = (ReactedUserHolderView) child; if (cell.dialogId == dialogId) { - holder.view = cell.avatarView; - holder.params = cell.params; - holder.avatarImage = cell.avatarView.getImageReceiver(); - holder.clipParent = (View) cell.getParent(); - holder.alpha = cell.getAlpha() * cell.getAlphaInternal(); - if (holder.alpha < 1) { - holder.bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - holder.bgPaint.setColor(Theme.getColor(Theme.key_dialogBackground, cell.getResourcesProvider())); + final boolean hasStoryPreview = cell.storyPreviewView != null && cell.storyPreviewView.getImageReceiver() != null && cell.storyPreviewView.getImageReceiver().getImageDrawable() != null; + if (cell.storyId == storyId && hasStoryPreview) { + holder.view = cell.storyPreviewView; + holder.storyImage = cell.storyPreviewView.getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = cell.getAlpha() * cell.getAlphaInternal(); + if (holder.alpha < 1) { + holder.bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + holder.bgPaint.setColor(Theme.getColor(Theme.key_dialogBackground, cell.getResourcesProvider())); + } + updateClip(holder); + return true; + } else if (!hasStoryPreview) { + holder.view = cell.avatarView; + holder.params = cell.params; + holder.avatarImage = cell.avatarView.getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = cell.getAlpha() * cell.getAlphaInternal(); + if (holder.alpha < 1) { + holder.bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + holder.bgPaint.setColor(Theme.getColor(Theme.key_dialogBackground, cell.getResourcesProvider())); + } + updateClip(holder); + return true; } - updateClip(holder); - return true; } } else if (child instanceof ProfileSearchCell) { ProfileSearchCell cell = (ProfileSearchCell) child; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java index 555ededf8..936155b99 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -81,6 +81,13 @@ public class StoriesStorage { if (storyItem.fwd_from != null && storyItem.fwd_from.from != null) { MessagesStorage.addLoadPeerInfo(storyItem.fwd_from.from, usersToLoad, chatsToLoad); } + for (int j = 0; j < storyItem.media_areas.size(); ++j) { + if (storyItem.media_areas.get(j) instanceof TL_stories.TL_mediaAreaChannelPost) { + long channel_id = ((TL_stories.TL_mediaAreaChannelPost) storyItem.media_areas.get(j)).channel_id; + if (!chatsToLoad.contains(channel_id)) + chatsToLoad.add(channel_id); + } + } StoryCustomParamsHelper.readLocalParams(storyItem, customData); storyItems.add(storyItem); data.reuse(); 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 57b35053f..7852c3a55 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -77,6 +77,7 @@ import org.telegram.ui.Components.Text; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilersClickDetector; +import org.telegram.ui.Stories.recorder.StoryEntry; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -579,6 +580,9 @@ public class StoryCaptionView extends NestedScrollView { public Long peerId; public Integer storyId; + public Integer messageId; + public boolean isRepostMessage; + private boolean small = true; private final AnimatedFloat animatedSmall = new AnimatedFloat(0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); public final ButtonBounce bounce = new ButtonBounce(null); @@ -625,40 +629,84 @@ public class StoryCaptionView extends NestedScrollView { } public static Reply from(int currentAccount, TL_stories.StoryItem storyItem) { - if (storyItem == null || storyItem.fwd_from == null) { + if (storyItem == null) { return null; } - Reply reply = new Reply(); - reply.currentAccount = currentAccount; - if (storyItem.fwd_from.from != null) { - long did = reply.peerId = DialogObject.getPeerDialogId(storyItem.fwd_from.from); - if (did >= 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); - reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(UserObject.getUserName(user)); - } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); - reply.title = new SpannableStringBuilder(ChatObject.isChannelAndNotMegaGroup(chat) ? MessageObject.channelSpan() : MessageObject.groupSpan()).append(" ").append(chat != null ? chat.title : ""); + if (storyItem.fwd_from != null) { + Reply reply = new Reply(); + reply.currentAccount = currentAccount; + if (storyItem.fwd_from.from != null) { + long did = reply.peerId = DialogObject.getPeerDialogId(storyItem.fwd_from.from); + if (did >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(did); + reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-did); + reply.title = new SpannableStringBuilder(ChatObject.isChannelAndNotMegaGroup(chat) ? MessageObject.channelSpan() : MessageObject.groupSpan()).append(" ").append(chat != null ? chat.title : ""); + } + } else if (storyItem.fwd_from.from_name != null) { + reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(storyItem.fwd_from.from_name); } - } else if (storyItem.fwd_from.from_name != null) { - reply.title = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(storyItem.fwd_from.from_name); + reply.small = true; + if ((storyItem.fwd_from.flags & 4) != 0) { + reply.storyId = storyItem.fwd_from.story_id; + } + reply.load(); + return reply; } - reply.small = true; - if ((storyItem.fwd_from.flags & 4) != 0) { - reply.storyId = storyItem.fwd_from.story_id; + if (storyItem.media_areas != null) { + TL_stories.TL_mediaAreaChannelPost postArea = null; + for (int i = 0; i < storyItem.media_areas.size(); ++i) { + if (storyItem.media_areas.get(i) instanceof TL_stories.TL_mediaAreaChannelPost) { + postArea = (TL_stories.TL_mediaAreaChannelPost) storyItem.media_areas.get(i); + } + } + if (postArea != null) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(postArea.channel_id); + if (chat != null) { + Reply reply = new Reply(); + reply.peerId = -chat.id; + reply.isRepostMessage = true; + reply.currentAccount = currentAccount; + reply.small = true; + reply.messageId = postArea.msg_id; + reply.title = new SpannableStringBuilder(ChatObject.isChannelAndNotMegaGroup(chat) ? MessageObject.channelSpan() : MessageObject.groupSpan()).append(" ").append(chat.title); + return reply; + } + } } - reply.load(); - return reply; + return null; } public static Reply from(StoriesController.UploadingStory uploadingStory) { - if (uploadingStory == null || uploadingStory.entry == null || !uploadingStory.entry.isRepost) { + if (uploadingStory == null || uploadingStory.entry == null) { return null; } - Reply reply = new Reply(); - reply.title = uploadingStory.entry.repostPeerName; - reply.text = uploadingStory.entry.repostCaption; - reply.small = TextUtils.isEmpty(reply.text); - return reply; + if (uploadingStory.entry.isRepost) { + Reply reply = new Reply(); + reply.title = uploadingStory.entry.repostPeerName; + reply.text = uploadingStory.entry.repostCaption; + reply.small = TextUtils.isEmpty(reply.text); + return reply; + } + if (uploadingStory.entry.isRepostMessage && uploadingStory.entry.messageObjects != null && uploadingStory.entry.messageObjects.size() > 0) { + MessageObject messageObject = uploadingStory.entry.messageObjects.get(0); + final long dialogId = StoryEntry.getRepostDialogId(messageObject); + if (dialogId < 0) { + TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); + if (chat != null) { + Reply reply = new Reply(); + reply.peerId = dialogId; + reply.isRepostMessage = true; + reply.currentAccount = messageObject.currentAccount; + reply.small = true; + reply.messageId = StoryEntry.getRepostMessageId(messageObject); + reply.title = new SpannableStringBuilder(ChatObject.isChannelAndNotMegaGroup(chat) ? MessageObject.channelSpan() : MessageObject.groupSpan()).append(" ").append(chat.title); + return reply; + } + } + } + return null; } private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java index f99371302..cced3d0c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java @@ -3,17 +3,22 @@ package org.telegram.ui.Stories; import static org.telegram.messenger.AndroidUtilities.dp; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; +import android.os.Bundle; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.animation.LinearInterpolator; @@ -28,8 +33,10 @@ import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.EmojiAnimationsOverlay; @@ -41,6 +48,7 @@ import java.util.ArrayList; public class StoryMediaAreasView extends FrameLayout implements View.OnClickListener { + private AreaView lastSelectedArea = null; private AreaView selectedArea = null; private HintView2 hintView = null; @@ -50,11 +58,15 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList Matrix matrix = new Matrix(); float[] point = new float[2]; + private View parentView; private Theme.ResourcesProvider resourcesProvider; - public StoryMediaAreasView(Context context, Theme.ResourcesProvider resourcesProvider) { + public StoryMediaAreasView(Context context, View parentView, Theme.ResourcesProvider resourcesProvider) { super(context); + this.parentView = parentView; this.resourcesProvider = resourcesProvider; + parentHighlightAlpha = new AnimatedFloat(parentView, 0, 120, new LinearInterpolator()); + parentHighlightScaleAlpha = new AnimatedFloat(parentView, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); setClipChildren(false); addView(hintsContainer = new FrameLayout(context)); } @@ -105,6 +117,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList } } selectedArea = null; + parentHighlightScaleAlpha.set(0, true); invalidate(); onHintVisible(false); malicious = false; @@ -131,7 +144,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList } ScaleStateListAnimator.apply(areaView); } else { - areaView = new AreaView(getContext(), this, mediaArea); + areaView = new AreaView(getContext(), parentView, mediaArea); } areaView.setOnClickListener(this); addView(areaView); @@ -139,7 +152,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList totalArea += (mediaArea.coordinates.w / 100f * W) * (mediaArea.coordinates.h / 100f * H); } } - malicious = totalArea > W * H * .33f; + malicious = false; // totalArea > W * H * .33f; hintsContainer.bringToFront(); } @@ -185,6 +198,17 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList onHintVisible(false); }, 200); + if (selectedArea.mediaArea instanceof TL_stories.TL_mediaAreaChannelPost) { + Bundle args = new Bundle(); + args.putLong("chat_id", ((TL_stories.TL_mediaAreaChannelPost) selectedArea.mediaArea).channel_id); + args.putInt("message_id", ((TL_stories.TL_mediaAreaChannelPost) selectedArea.mediaArea).msg_id); + presentFragment(new ChatActivity(args)); + + selectedArea = null; + invalidate(); + return; + } + LocationActivity fragment = new LocationActivity(3) { @Override protected boolean disablePermissionCheck() { @@ -227,7 +251,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList return; } - selectedArea = (AreaView) v; + selectedArea = lastSelectedArea = (AreaView) v; invalidate(); if (hintView != null) { hintView.hide(); @@ -236,7 +260,12 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList boolean top = selectedArea.getTranslationY() < AndroidUtilities.dp(100); - SpannableStringBuilder text = new SpannableStringBuilder(LocaleController.getString("StoryViewLocation", R.string.StoryViewLocation)); + SpannableStringBuilder text = new SpannableStringBuilder(); + if (selectedArea.mediaArea instanceof TL_stories.TL_mediaAreaChannelPost) { + text.append(LocaleController.getString(R.string.StoryViewMessage)); + } else { + text.append(LocaleController.getString(R.string.StoryViewLocation)); + } SpannableString arrowRight = new SpannableString(">"); ColoredImageSpan imageSpan = new ColoredImageSpan(R.drawable.photos_arrow); imageSpan.translate(dp(2), dp(1)); @@ -261,7 +290,13 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList onHintVisible(false); } }); - if (top) { + if (selectedArea.mediaArea instanceof TL_stories.TL_mediaAreaChannelPost && ( + top ? + selectedArea.getTranslationY() + selectedArea.getMeasuredHeight() / 2f > getMeasuredHeight() - dp(120) : + selectedArea.getTranslationY() - selectedArea.getMeasuredHeight() / 2f - dp(50) < dp(120) + )) { + hintView.setTranslationY(selectedArea.getTranslationY() - selectedArea.getMeasuredHeight() / 3f); + } else if (top) { hintView.setTranslationY(selectedArea.getTranslationY() + selectedArea.getMeasuredHeight() / 2f); } else { hintView.setTranslationY(selectedArea.getTranslationY() - selectedArea.getMeasuredHeight() / 2f - dp(50)); @@ -336,13 +371,15 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList } + private final Rect rect = new Rect(); private final RectF rectF = new RectF(); private final Paint cutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); { cutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); cutPaint.setColor(0xffffffff); } - public final AnimatedFloat parentHighlightAlpha = new AnimatedFloat(this, 0, 120, new LinearInterpolator()); + public final AnimatedFloat parentHighlightAlpha; + public final AnimatedFloat parentHighlightScaleAlpha; @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { @@ -352,8 +389,13 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList return super.drawChild(canvas, child, drawingTime); } + private final Path clipPath = new Path(); + private final float[] radii = new float[8]; + private void drawHighlight(Canvas canvas) { - float parentAlpha = parentHighlightAlpha.set(selectedArea != null); + float parentAlpha = parentHighlightAlpha.set(selectedArea != null && selectedArea.supportsBounds && !selectedArea.scaleOnTap); + boolean scale = selectedArea != null && selectedArea.scaleOnTap; + float parentScale = parentHighlightScaleAlpha.set(scale); if (parentAlpha > 0) { canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); canvas.drawColor(Theme.multAlpha(0x18000000, parentAlpha)); @@ -361,7 +403,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList View child2 = getChildAt(i); if (child2 != hintsContainer) { AreaView areaView = (AreaView) child2; - float alpha = areaView.highlightAlpha.set(child2 == selectedArea); + float alpha = areaView.highlightAlpha.set(child2 == selectedArea && selectedArea.supportsBounds); if (alpha > 0) { canvas.save(); rectF.set(child2.getX(), child2.getY(), child2.getX() + child2.getMeasuredWidth(), child2.getY() + child2.getMeasuredHeight()); @@ -374,6 +416,49 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList } canvas.restore(); } + if ((scale || parentScale > 0) && lastSelectedArea != null) { + if (parentBitmap == null) { + parentBitmap = getPlayingBitmap(); + } + if (parentBitmap != null) { + canvas.drawColor(Theme.multAlpha(0x30000000, parentScale)); + canvas.save(); + clipPath.rewind(); + rectF.set(lastSelectedArea.getX(), lastSelectedArea.getY(), lastSelectedArea.getX() + lastSelectedArea.getMeasuredWidth(), lastSelectedArea.getY() + lastSelectedArea.getMeasuredHeight()); + final float s = AndroidUtilities.lerp(1.0f, 1.05f, parentScale); + canvas.scale(s, s, rectF.centerX(), rectF.centerY()); + canvas.rotate(lastSelectedArea.getRotation(), rectF.centerX(), rectF.centerY()); + radii[0] = radii[1] = dp(16); + radii[2] = radii[3] = dp(16); + radii[4] = radii[5] = dp(16); + radii[6] = radii[7] = dp(8); + clipPath.addRoundRect(rectF, radii, Path.Direction.CW); + canvas.clipPath(clipPath); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + rect.set(0, 0, parentBitmap.getWidth(), parentBitmap.getHeight()); + canvas.rotate(-lastSelectedArea.getRotation(), rectF.centerX(), rectF.centerY()); + canvas.drawBitmap(parentBitmap, rect, AndroidUtilities.rectTmp, null); + canvas.restore(); + } + } else if (parentBitmap != null) { + parentBitmap.recycle(); + parentBitmap = null; + } + invalidate(); + } + + private Bitmap parentBitmap; + protected Bitmap getPlayingBitmap() { + return null; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (parentBitmap != null) { + parentBitmap.recycle(); + parentBitmap = null; + } } private boolean shined = false; @@ -394,6 +479,10 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList return selectedArea != null; } + public boolean hasSelectedForScale() { + return selectedArea != null && (selectedArea.scaleOnTap || selectedArea.supportsBounds); + } + // returns true when widget that is drawn above the story (f.ex. reaction) is at these coordinates // used to detect that back gesture safety measure should not occur public boolean hasAreaAboveAt(float x, float y) { @@ -468,6 +557,9 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList public AreaView(Context context, View parent, TL_stories.MediaArea mediaArea) { super(context); this.mediaArea = mediaArea; + supportsBounds = mediaArea instanceof TL_stories.TL_mediaAreaGeoPoint || mediaArea instanceof TL_stories.TL_mediaAreaVenue; // || mediaArea instanceof TL_stories.TL_mediaAreaChannelPost; + supportsShining = mediaArea instanceof TL_stories.TL_mediaAreaGeoPoint || mediaArea instanceof TL_stories.TL_mediaAreaVenue; + scaleOnTap = false; // mediaArea instanceof TL_stories.TL_mediaAreaChannelPost; highlightAlpha = new AnimatedFloat(parent, 0, 120, new LinearInterpolator()); strokeGradientPaint.setStyle(Paint.Style.STROKE); } @@ -477,6 +569,9 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList private LinearGradient gradient, strokeGradient; private final Matrix gradientMatrix = new Matrix(); + private boolean supportsBounds = false; + private boolean supportsShining = false; + private boolean scaleOnTap; private boolean shining = false; private long startTime; @@ -484,7 +579,7 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (shining && gradient != null) { + if (supportsShining && shining && gradient != null) { float w = getMeasuredWidth() * .7f; float t = (System.currentTimeMillis() - startTime) / 600f; float tx = t * (getMeasuredWidth() + w) - w; @@ -516,11 +611,17 @@ public class StoryMediaAreasView extends FrameLayout implements View.OnClickList private final Runnable shineRunnable = this::shineInternal; public void shine() { + if (!supportsShining) { + return; + } AndroidUtilities.cancelRunOnUIThread(shineRunnable); AndroidUtilities.runOnUIThread(shineRunnable, 400L); } private void shineInternal() { + if (!supportsShining) { + return; + } shining = true; startTime = System.currentTimeMillis(); gradient = new LinearGradient(0, 0, 40, 0, new int[] { 0x00ffffff, 0x2dffffff, 0x2dffffff, 0x00ffffff }, new float[] { 0, .4f, .6f, 1f }, Shader.TileMode.CLAMP ); 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 c0ff28159..d1a9c3d8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -781,13 +781,6 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } } canvas.restore(); -// -// if (transitionViewHolder.avatarImage != null) { -// transitionViewHolder.avatarImage.setVisible(false, true); -// } -// if (transitionViewHolder.storyImage != null) { -// transitionViewHolder.storyImage.setVisible(false, true); -// } } if (runOpenAnimationAfterLayout) { @@ -2200,6 +2193,9 @@ public class StoryViewer implements NotificationCenter.NotificationCenterDelegat } AndroidUtilities.hideKeyboard(windowView); isClosed = true; + fullyVisible = false; + progressToOpen = 0; + progressToDismiss = 0; updatePlayingMode(); fromX = fromY = 0; if (transitionViewHolder.avatarImage != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java index c58074d03..4e5b85509 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java @@ -145,10 +145,14 @@ public class ButtonWithCounterView extends FrameLayout { } public void setText(CharSequence newText, boolean animated) { + setText(newText, animated, true); + } + + public void setText(CharSequence newText, boolean animated, boolean moveDown) { if (animated) { text.cancelAnimation(); } - text.setText(newText, animated); + text.setText(newText, animated, moveDown); setContentDescription(newText); invalidate(); } @@ -343,6 +347,10 @@ public class ButtonWithCounterView extends FrameLayout { private int globalAlpha = 255; private final int subTextAlpha = 200; + protected float calculateCounterWidth(float width, float percent) { + return width * percent; + } + @Override protected void onDraw(Canvas canvas) { rippleView.draw(canvas); @@ -370,7 +378,7 @@ public class ButtonWithCounterView extends FrameLayout { float countAlpha = countAlphaAnimated.set(this.countAlpha); float lightningWidth = withCounterIcon ? AndroidUtilities.dp(12) : 0; - float width = textWidth + lightningWidth + (dp(5.66f + 5 + 5) + countText.getCurrentWidth()) * countAlpha; + float width = textWidth + lightningWidth + calculateCounterWidth((dp(5.66f + 5 + 5) + countText.getCurrentWidth()), countAlpha); AndroidUtilities.rectTmp2.set( (int) ((getMeasuredWidth() - width - getWidth()) / 2f), (int) ((getMeasuredHeight() - text.getHeight()) / 2f - dp(1)), @@ -419,7 +427,8 @@ public class ButtonWithCounterView extends FrameLayout { canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, paint); } - AndroidUtilities.rectTmp2.offset(-dp(.3f), -dp(.4f)); + int countLength = countText.getText() != null ? countText.getText().length() : 0; + AndroidUtilities.rectTmp2.offset(-dp(countLength > 1 ? .3f : 0), -dp(.4f)); countText.setAlpha((int) (globalAlpha * (1f - loadingT) * countAlpha * (countFilled ? 1 : .5f))); countText.setBounds(AndroidUtilities.rectTmp2); canvas.save(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java index 684395903..3ccbc7134 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -279,7 +279,7 @@ public class CaptionContainerView extends FrameLayout { limitTextView.cancelAnimation(); limitTextView.setText(limitText); limitTextView.setTextColor(codePointCount >= limit ? 0xffEC7777 : 0xffffffff); - if (codePointCount > limit && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount < getCaptionPremiumLimit() && codePointCount > lastLength && (captionLimitToast() || MessagesController.getInstance(currentAccount).premiumLocked)) { + if (codePointCount > limit && !UserConfig.getInstance(currentAccount).isPremium() && codePointCount < getCaptionPremiumLimit() && codePointCount > lastLength && (captionLimitToast() || MessagesController.getInstance(currentAccount).premiumFeaturesBlocked())) { AndroidUtilities.shakeViewSpring(limitTextView, shiftDp = -shiftDp); BotWebViewVibrationEffect.APP_ERROR.vibrate(); } @@ -369,13 +369,13 @@ public class CaptionContainerView extends FrameLayout { public boolean ignoreTouches; - protected boolean ignoreTouches() { + protected boolean ignoreTouches(float x, float y) { return false; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (ignoreTouches || ignoreTouches() || !bounds.contains(ev.getX(), ev.getY()) && !keyboardShown) { + if (ignoreTouches || ev.getAction() == MotionEvent.ACTION_DOWN && ignoreTouches(ev.getX(), ev.getY()) || !bounds.contains(ev.getX(), ev.getY()) && !keyboardShown) { return false; } if (ev.getAction() == MotionEvent.ACTION_DOWN && !keyboardShown) { @@ -1236,7 +1236,7 @@ public class CaptionContainerView extends FrameLayout { public static class PeriodDrawable extends Drawable { - private final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public final AnimatedTextView.AnimatedTextDrawable textDrawable = new AnimatedTextView.AnimatedTextDrawable(true, false, false) { @Override @@ -1244,11 +1244,26 @@ public class CaptionContainerView extends FrameLayout { PeriodDrawable.this.invalidateSelf(); } }; + public final AnimatedTextView.AnimatedTextDrawable activeTextDrawable = new AnimatedTextView.AnimatedTextDrawable(true, false, false) { + @Override + public void invalidateSelf() { + PeriodDrawable.this.invalidateSelf(); + } + }; private boolean filled = false; private final AnimatedFloat fillT = new AnimatedFloat(this::invalidateSelf, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final Path activePath = new Path(); + private final int dashes; + public float diameterDp = 21; public PeriodDrawable() { + this(5); + } + + public PeriodDrawable(int dashes) { + this.dashes = dashes; + strokePaint.setStyle(Paint.Style.STROKE); strokePaint.setStrokeWidth(dpf2(1.66f)); strokePaint.setStrokeCap(Paint.Cap.ROUND); @@ -1258,33 +1273,74 @@ public class CaptionContainerView extends FrameLayout { textDrawable.setTextSize(dpf2(12)); textDrawable.setGravity(Gravity.CENTER); - updateColors(0xffffffff, 0xff1A9CFF); + activeTextDrawable.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + activeTextDrawable.setTypeface(AndroidUtilities.getTypeface("fonts/num.otf")); + activeTextDrawable.setTextSize(dpf2(12)); + activeTextDrawable.setGravity(Gravity.CENTER); + + updateColors(0xffffffff, 0xff1A9CFF, 0xffffffff); } - public void updateColors(int strokeColor, int fillColor) { + public void setTextSize(float dp) { + activeTextDrawable.setTextSize(dpf2(dp)); + textDrawable.setTextSize(dpf2(dp)); + } + + public float textOffsetX, textOffsetY; + + public void updateColors(int strokeColor, int fillColor, int activeTextColor) { strokePaint.setColor(strokeColor); textDrawable.setTextColor(strokeColor); + activeTextDrawable.setTextColor(activeTextColor); fillPaint.setColor(fillColor); } + private boolean clear; + public void setClear(boolean clear) { + if (this.clear != clear) { + this.clear = clear; + strokePaint.setXfermode(clear ? new PorterDuffXfermode(PorterDuff.Mode.CLEAR) : null); + textDrawable.getPaint().setXfermode(clear ? new PorterDuffXfermode(PorterDuff.Mode.CLEAR) : null); + } + } + + private float cx, cy; + public void setCenterXY(float x, float y) { + this.cx = x; + this.cy = y; + } + + @Override + public void setBounds(@NonNull Rect bounds) { + super.setBounds(bounds); + this.cx = getBounds().centerX(); + this.cy = getBounds().centerY(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + this.cx = getBounds().centerX(); + this.cy = getBounds().centerY(); + } + @Override public void draw(@NonNull Canvas canvas) { - final float cx = getBounds().centerY(); - final float cy = getBounds().centerY(); - - final float r = dpf2(21) / 2f; + draw(canvas, 1f); + } + public void draw(@NonNull Canvas canvas, float alpha) { + final float r = dpf2(diameterDp) / 2f; final float fillT = this.fillT.set(filled); if (fillT > 0) { - fillPaint.setAlpha((int) (0xFF * fillT)); + fillPaint.setAlpha((int) (0xFF * alpha * fillT)); canvas.drawCircle(cx, cy, dpf2(11.33f) * fillT, fillPaint); } - strokePaint.setAlpha((int) (0xFF * (1f - fillT))); + strokePaint.setAlpha((int) (0xFF * alpha * (1f - fillT))); AndroidUtilities.rectTmp.set(cx - r, cy - r, cx + r, cy + r); canvas.drawArc(AndroidUtilities.rectTmp, 90, 180, false, strokePaint); - final int dashes = 5; final int gaps = dashes + 1; final float dashWeight = 1f, gapWeight = 1.5f; final float dashSweep = dashWeight / (dashes * dashWeight + gaps * gapWeight) * 180; @@ -1296,7 +1352,7 @@ public class CaptionContainerView extends FrameLayout { } canvas.save(); - canvas.translate(0, -1); + canvas.translate(textOffsetX + 0, textOffsetY); AndroidUtilities.rectTmp2.set( (int) (cx - dp(20)), (int) (cy - dp(20)), @@ -1304,12 +1360,22 @@ public class CaptionContainerView extends FrameLayout { (int) (cy + dp(20)) ); textDrawable.setBounds(AndroidUtilities.rectTmp2); + textDrawable.setAlpha((int) (0xFF * alpha)); textDrawable.draw(canvas); + if (fillT > 0) { + activePath.rewind(); + activePath.addCircle(cx, cy + dp(1), dpf2(11.33f) * fillT, Path.Direction.CW); + canvas.clipPath(activePath); + activeTextDrawable.setBounds(AndroidUtilities.rectTmp2); + activeTextDrawable.setAlpha((int) (0xFF * alpha)); + activeTextDrawable.draw(canvas); + } canvas.restore(); } public void setValue(int num, boolean fill, boolean animated) { textDrawable.setText("" + num, animated); + activeTextDrawable.setText("" + num, animated); filled = fill; if (!animated) { fillT.set(filled, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java index 82dd9c7f1..4caa9ac4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java @@ -67,7 +67,6 @@ public class CaptionStory extends CaptionContainerView { private boolean periodVisible = true; public static final int[] periods = new int[] { 6 * 3600, 12 * 3600, 86400, 2 * 86400 }; - public static final int[] periodDrawables = new int[] { R.drawable.msg_story_6h, R.drawable.msg_story_12h, R.drawable.msg_story_24h, R.drawable.msg_story_48h }; private int periodIndex = 0; private Drawable flipButton; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index 876204da0..092b4e722 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java @@ -54,6 +54,7 @@ public class DraftsController { if (database == null) { return; } + ArrayList todelete = new ArrayList<>(); cursor = database.queryFinalized("SELECT id, data, type FROM story_drafts WHERE type = " + (failed ? "2" : "0 OR type = 1") + " ORDER BY date DESC"); while (cursor.next()) { long id = cursor.longValue(0); @@ -65,10 +66,19 @@ public class DraftsController { loadedDrafts.add(draft); } catch (Exception e) { FileLog.e(e); + todelete.add(id); } buffer.reuse(); } } + if (cursor != null) { + cursor.dispose(); + } + if (todelete.size() > 0) { + for (int i = 0; i < todelete.size(); ++i) { + database.executeFast("DELETE FROM story_drafts WHERE id = " + todelete.get(i)).stepThis().dispose(); + } + } } catch (Exception e) { FileLog.e(e); } finally { @@ -253,7 +263,7 @@ public class DraftsController { } public void append(StoryEntry entry) { - if (entry == null) { + if (entry == null || entry.isRepostMessage) { return; } prepare(entry); @@ -330,7 +340,7 @@ public class DraftsController { } public void saveForEdit(StoryEntry entry, long dialogId, TL_stories.StoryItem storyItem) { - if (entry == null || storyItem == null || storyItem.media == null) { + if (entry == null || entry.isRepostMessage || storyItem == null || storyItem.media == null) { return; } @@ -477,8 +487,6 @@ public class DraftsController { private int period; - private final ArrayList parts = new ArrayList<>(); - public boolean isEdit; public int editStoryId; public long editStoryPeerId; @@ -541,8 +549,6 @@ public class DraftsController { this.filterFilePath = entry.filterFile == null ? "" : entry.filterFile.toString(); this.filterState = entry.filterState; this.period = entry.period; - this.parts.clear(); - this.parts.addAll(entry.parts); this.isError = entry.isError; this.error = entry.error; @@ -629,12 +635,6 @@ public class DraftsController { } entry.filterState = filterState; entry.period = period; - entry.parts.clear(); - entry.parts.addAll(parts); - entry.partsMaxId = 0; - for (int i = 0; i < parts.size(); ++i) { - entry.partsMaxId = Math.max(entry.partsMaxId, parts.get(i).id); - } entry.isEdit = isEdit; entry.editStoryId = editStoryId; entry.editStoryPeerId = editStoryPeerId; @@ -732,10 +732,7 @@ public class DraftsController { } stream.writeInt32(period); stream.writeInt32(0x1cb5c415); - stream.writeInt32(parts.size()); - for (int i = 0; i < parts.size(); ++i) { - parts.get(i).serializeToStream(stream); - } + stream.writeInt32(0); stream.writeBool(isEdit); stream.writeInt32(editStoryId); stream.writeInt64(editStoryPeerId); @@ -881,7 +878,7 @@ public class DraftsController { if (mediaEntities == null) { mediaEntities = new ArrayList<>(); } - mediaEntities.add(new VideoEditedInfo.MediaEntity(stream, true)); + mediaEntities.add(new VideoEditedInfo.MediaEntity(stream, true, exception)); } magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -918,12 +915,6 @@ public class DraftsController { return; } count = stream.readInt32(exception); - parts.clear(); - for (int i = 0; i < count; ++i) { - StoryEntry.Part part = new StoryEntry.Part(); - part.readParams(stream, exception); - parts.add(part); - } } if (stream.remaining() > 0) { isEdit = stream.readBool(exception); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java index 7a73bb6ad..04293febe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java @@ -1216,12 +1216,12 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } } - public void showPremiumBulletin(String str, int resId) { + public void showPremiumBulletin(String text) { container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); BulletinFactory.of(container, resourcesProvider).createSimpleBulletin( - ContextCompat.getDrawable(getContext(), R.drawable.msg_premium_normal), - LocaleController.getString("IncreaseLimit", R.string.IncreaseLimit), - premiumText(LocaleController.getString(str, resId)) + R.raw.star_premium_2, + LocaleController.getString(R.string.IncreaseLimit), + premiumText(text) ).show(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java index 3b7e39262..eae8dba76 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java @@ -80,13 +80,13 @@ public class HintView2 extends View { private Drawable closeButtonDrawable; private boolean closeButton; - private float rounding = dp(8); + protected float rounding = dp(8); private final RectF innerPadding = new RectF(dp(11), dp(6), dp(11), dp(7)); private float closeButtonMargin = dp(2); private float arrowHalfWidth = dp(7); private float arrowHeight = dp(6); - private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + protected final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private CharSequence textToSet; private AnimatedTextView.AnimatedTextDrawable textDrawable; @@ -212,6 +212,12 @@ public class HintView2 extends View { return this; } + public HintView2 setIcon(int resId) { + RLottieDrawable icon = new RLottieDrawable(resId, "" + resId, dp(34), dp(34)); + icon.start(); + return setIcon(icon); + } + public HintView2 setIcon(Drawable icon) { if (this.icon != null) { this.icon.setCallback(null); @@ -260,6 +266,7 @@ public class HintView2 extends View { len += paint.measureText(spanned, s, e); paint.setTypeface(oldTypeface); } + s = e; } e = Math.max(s, text.length()); if (e - s > 0) { @@ -275,15 +282,16 @@ public class HintView2 extends View { float prevLeftWidth = 0; float prevRightWidth = Float.MAX_VALUE; + int dir = -1; for (int i = 0; i < 10; ++i) { // Adjust the mid to point to the nearest space on the left - while (mid > 0 && text.charAt(mid) != ' ') { - mid--; + while (mid > 0 && mid < text.length() && text.charAt(mid) != ' ') { + mid += dir; } - leftWidth = measureCorrectly(text.subSequence(0, mid).toString(), paint); - rightWidth = measureCorrectly(text.subSequence(mid, text.length()).toString().trim(), paint); + leftWidth = measureCorrectly(text.subSequence(0, mid), paint); + rightWidth = measureCorrectly(AndroidUtilities.getTrimmedString(text.subSequence(mid, text.length())), paint); // If we're not making progress, exit the loop. // (This is a basic way to ensure termination when we can't improve the result.) @@ -296,11 +304,13 @@ public class HintView2 extends View { // If left side is shorter, move midpoint to the right. if (leftWidth < rightWidth) { - mid++; + dir = +1; + mid += dir; } // If right side is shorter or equal, move midpoint to the left. else { - mid--; + dir = -1; + mid += dir; } // Ensure mid doesn't go out of bounds @@ -585,12 +595,16 @@ public class HintView2 extends View { private final Rect boundsWithArrow = new Rect(); private final RectF bounds = new RectF(); - private final Path path = new Path(); + protected final Path path = new Path(); private float arrowX, arrowY; private float pathLastWidth, pathLastHeight; private boolean pathSet; private boolean firstDraw = true; + protected void drawBgPath(Canvas canvas) { + canvas.drawPath(path, backgroundPaint); + } + @Override protected void dispatchDraw(Canvas canvas) { if (multiline && textLayout == null) { @@ -656,7 +670,7 @@ public class HintView2 extends View { backgroundAlpha *= .2f; } backgroundPaint.setAlpha((int) (wasAlpha * backgroundAlpha)); - canvas.drawPath(path, backgroundPaint); + drawBgPath(canvas); backgroundPaint.setAlpha(wasAlpha); if (selectorDrawable != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/IStoryPart.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/IStoryPart.java deleted file mode 100644 index 910e2c8a9..000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/IStoryPart.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.telegram.ui.Stories.recorder; - -import android.graphics.Matrix; - -import java.io.File; - -public abstract class IStoryPart { - public int id; - public int width, height; - public final Matrix matrix = new Matrix(); -} 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 25ef77662..c07b4bedf 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 @@ -42,6 +42,7 @@ import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -66,10 +67,12 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.DispatchQueue; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; @@ -87,6 +90,7 @@ import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.BubbleActivity; +import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; @@ -112,6 +116,7 @@ import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.Paint.Views.EntitiesContainerView; import org.telegram.ui.Components.Paint.Views.EntityView; import org.telegram.ui.Components.Paint.Views.LocationView; +import org.telegram.ui.Components.Paint.Views.MessageEntityView; import org.telegram.ui.Components.Paint.Views.PaintCancelView; import org.telegram.ui.Components.Paint.Views.PaintColorsListView; import org.telegram.ui.Components.Paint.Views.PaintDoneView; @@ -161,6 +166,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai private boolean ignoreLayout; private float baseScale; private Size paintingSize; + public boolean drawForThemeToggle, clipVideoMessageForBitmap; private EntityView currentEntityView; private boolean editingText; @@ -272,11 +278,14 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai private boolean reactionLayoutShowing; private boolean invalidateReactionPosition; private BlurringShader.BlurManager blurManager; + private PreviewView.TextureViewHolder videoTextureHolder; @SuppressLint("NotifyDataSetChanged") - public PaintView(Context context, boolean fileFromGallery, File file, boolean isVideo, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap blurBitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, StoryEntry entry, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, BlurringShader.BlurManager blurManager, Theme.ResourcesProvider resourcesProvider) { + public PaintView(Context context, boolean fileFromGallery, File file, boolean isVideo, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap blurBitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, StoryEntry entry, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, BlurringShader.BlurManager blurManager, Theme.ResourcesProvider resourcesProvider, PreviewView.TextureViewHolder videoTextureHolder) { super(context, activity, true); setDelegate(this); + this.blurManager = blurManager; + this.videoTextureHolder = videoTextureHolder; this.fileFromGallery = fileFromGallery; this.file = file; this.isVideo = isVideo; @@ -385,7 +394,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai textDim.setBackgroundColor(0x4d000000); textDim.setAlpha(0f); - renderView = new RenderView(context, new Painting(getPaintingSize(), originalBitmap, originalRotation, blurManager), bitmapToEdit, blurBitmapToEdit, blurManager) { + renderView = new RenderView(context, new Painting(getPaintingSize(), originalBitmap, originalRotation, blurManager), bitmapToEdit, blurBitmapToEdit, entry != null && entry.isRepostMessage ? null : blurManager) { @Override public void selectBrush(Brush brush) { int index = 1 + Brush.BRUSHES_LIST.indexOf(brush); @@ -800,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, blurManager != null); + paintToolsView = new PaintToolsView(context, !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); @@ -1770,15 +1779,15 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai widgetsCount++; } } - if (widgetsCount >= 1 && !UserConfig.getInstance(currentAccount).isPremium()) { - showPremiumBulletin("StoryPremiumWidgets", R.string.StoryPremiumWidgets); + if (widgetsCount >= MessagesController.getInstance(currentAccount).storiesSuggestedReactionsLimitDefault && !UserConfig.getInstance(currentAccount).isPremium()) { + showPremiumBulletin(LocaleController.formatPluralString("StoryPremiumWidgets2", MessagesController.getInstance(currentAccount).storiesSuggestedReactionsLimitPremium)); return false; } - if (widgetsCount >= 5) { + if (widgetsCount >= MessagesController.getInstance(currentAccount).storiesSuggestedReactionsLimitPremium) { container.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); BulletinFactory.of(container, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, LocaleController.getString("LimitReached", R.string.LimitReached), - LocaleController.getString("StoryReactionsWidgetLimit", R.string.StoryReactionsWidgetLimit) + LocaleController.formatPluralString("StoryReactionsWidgetLimit2", MessagesController.getInstance(currentAccount).storiesSuggestedReactionsLimitPremium) ).show(true); return false; } @@ -2145,13 +2154,25 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai view = textPaintView; } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO) { PhotoView photoView = createPhoto(entity.text, false); + photoView.preloadSegmented(entity.segmentedPath); if ((entity.subType & 2) != 0) { photoView.mirror(); } + if ((entity.subType & 16) != 0) { + photoView.toggleSegmented(false); + } view = photoView; ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.width = entity.viewWidth; layoutParams.height = entity.viewHeight; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_MESSAGE) { + MessageEntityView messageView = createMessage(entry.messageObjects, false, entry.isVideo); + view = messageView; + if (entity.viewWidth > 0 && entity.viewHeight > 0) { + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + layoutParams.width = entity.viewWidth; + layoutParams.height = entity.viewHeight; + } } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_LOCATION) { LocationView locationView = createLocationSticker(entity.mediaGeo, entity.mediaArea, false); locationView.setType(entity.subType, entity.color); @@ -2310,13 +2331,15 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai @Override public Bitmap getBitmap(ArrayList entities, Bitmap[] thumbBitmap) { - return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false, null); + return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false, false, null); } - public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean drawBlur, StoryEntry entry) { + public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean drawMessage, boolean drawBlur, StoryEntry entry) { Bitmap bitmap; if (drawPaint) { bitmap = renderView.getResultBitmap(false, drawBlur); + } else if (drawMessage) { + bitmap = Bitmap.createBitmap(Math.max(1, entitiesView.getMeasuredWidth()), Math.max(1, entitiesView.getMeasuredHeight()), Bitmap.Config.ARGB_8888); } else if (drawEntities) { Bitmap ref = renderView.getResultBitmap(false, false); if (ref != null) { @@ -2440,6 +2463,13 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai if (photoView.isMirrored()) { mediaEntity.subType |= 2; } + if (photoView.hasSegmentedImage() && photoView.isSegmented()) { + File segmentedFile = photoView.saveSegmentedImage(currentAccount); + if (segmentedFile != null) { + mediaEntity.subType |= 16; + mediaEntity.segmentedPath = segmentedFile.getPath(); + } + } } else if (entity instanceof LocationView) { LocationView locationView = (LocationView) entity; mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_LOCATION; @@ -2491,6 +2521,44 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai if (roundView.isMirrored()) { mediaEntity.subType |= 2; } + } else if (entity instanceof MessageEntityView) { + MessageEntityView messageView = (MessageEntityView) entity; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_MESSAGE; + mediaEntity.width = mediaEntity.viewWidth = messageView.getWidth(); + mediaEntity.height = mediaEntity.viewHeight = messageView.getHeight(); + mediaEntity.mediaArea = new TL_stories.TL_inputMediaAreaChannelPost(); + mediaEntity.mediaArea.coordinates = new TL_stories.TL_mediaAreaCoordinates(); + if (entry != null && entry.messageObjects != null) { + MessageObject messageObject = entry.messageObjects.get(0); + ((TL_stories.TL_inputMediaAreaChannelPost) mediaEntity.mediaArea).channel = MessagesController.getInstance(currentAccount).getInputChannel(-StoryEntry.getRepostDialogId(messageObject)); + ((TL_stories.TL_inputMediaAreaChannelPost) mediaEntity.mediaArea).msg_id = StoryEntry.getRepostMessageId(messageObject); + } + if (!drawMessage) { + skipDrawToBitmap = true; + } else if (entry != null && entry.isVideo) { + entry.matrix.reset(); + View child = null; + ImageReceiver photoImage = null; + if (messageView.listView.getChildCount() == 1) { + child = messageView.listView.getChildAt(0); + if (child instanceof ChatMessageCell) { + photoImage = ((ChatMessageCell) child).getPhotoImage(); + } + } + if (photoImage != null) { + float scale = Math.max(photoImage.getImageWidth() / Math.max(1, entry.width), photoImage.getImageHeight() / Math.max(1, entry.height)); + entry.matrix.postScale(scale, scale); + entry.matrix.postTranslate(photoImage.getCenterX() - entry.width * scale / 2f, photoImage.getCenterY() - entry.height * scale / 2f); + entry.matrix.postTranslate(messageView.container.getX(), messageView.container.getY()); + entry.matrix.postTranslate(messageView.listView.getX(), messageView.listView.getY()); + entry.matrix.postTranslate(child.getX(), child.getY()); + entry.matrix.postScale(messageView.getScaleX(), messageView.getScaleY(), messageView.getPivotX(), messageView.getPivotY()); + entry.matrix.postRotate(messageView.getRotation(), messageView.getPivotX(), messageView.getPivotY()); + entry.matrix.postTranslate(messageView.getX(), messageView.getY()); + entry.matrix.postScale(1f / entitiesView.getWidth(), 1f / entitiesView.getHeight()); + entry.matrix.postScale(entry.resultWidth, entry.resultHeight); + } + } } else { continue; } @@ -2513,7 +2581,17 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai mediaEntity.textViewHeight = mediaEntity.viewHeight / (float) entitiesView.getMeasuredHeight(); mediaEntity.scale = scaleX; - if (entity instanceof StickerView) { + if (entity instanceof MessageEntityView) { + MessageEntityView mv = (MessageEntityView) entity; + mv.getBubbleBounds(AndroidUtilities.rectTmp); + AndroidUtilities.rectTmp.offset(mv.container.getX(), mv.container.getY()); + AndroidUtilities.rectTmp.offset(mv.listView.getX(), mv.listView.getY()); + mediaEntity.mediaArea.coordinates.x = (x + v.getWidth() / 2f - v.getWidth() / 2f * scaleX + AndroidUtilities.rectTmp.centerX() * scaleX) / entitiesView.getMeasuredWidth() * 100; + mediaEntity.mediaArea.coordinates.y = (y + v.getHeight() / 2f - v.getHeight() / 2f * scaleY + AndroidUtilities.rectTmp.centerY() * scaleY) / entitiesView.getMeasuredHeight() * 100; + mediaEntity.mediaArea.coordinates.w = AndroidUtilities.rectTmp.width() * scaleX / entitiesView.getMeasuredWidth() * 100; + mediaEntity.mediaArea.coordinates.h = AndroidUtilities.rectTmp.height() * scaleY / entitiesView.getMeasuredHeight() * 100; + mediaEntity.mediaArea.coordinates.rotation = -mediaEntity.rotation / Math.PI * 180; + } else if (entity instanceof StickerView) { final float a = ((StickerView) entity).centerImage.getImageAspectRatio(); final float cx = mediaEntity.x + mediaEntity.width / 2f; final float cy = mediaEntity.y + mediaEntity.height / 2f; @@ -2534,7 +2612,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai if (entity instanceof LocationView) { mediaEntity.mediaArea.coordinates.w = (mediaEntity.width - 2 * ((LocationView) entity).marker.padx * scaleX / (float) entitiesView.getMeasuredWidth()) * 100; mediaEntity.mediaArea.coordinates.h = (mediaEntity.height - 2 * ((LocationView) entity).marker.pady * scaleY / (float) entitiesView.getMeasuredHeight()) * 100; - } else if (entity instanceof ReactionWidgetEntityView){ + } else if (entity instanceof ReactionWidgetEntityView) { float padW = 2 * ((ReactionWidgetEntityView) entity).getPadding() * scaleX / (float) entitiesView.getMeasuredWidth(); float padH = 2 * ((ReactionWidgetEntityView) entity).getPadding() * scaleX / (float) entitiesView.getMeasuredHeight(); mediaEntity.mediaArea.coordinates.w = (mediaEntity.width - padW) * 100; @@ -2543,7 +2621,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai mediaEntity.mediaArea.coordinates.rotation = -mediaEntity.rotation / Math.PI * 180; } } - if (drawEntities && bitmap != null) { + if ((drawEntities || drawMessage && mediaEntity.type == VideoEditedInfo.MediaEntity.TYPE_MESSAGE) && bitmap != null) { canvas = new Canvas(bitmap); final float s = bitmap.getWidth() / (float) entitiesView.getMeasuredWidth(); for (int k = 0; k < 2; k++) { @@ -2572,7 +2650,14 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } b.recycle(); } else { - v.draw(currentCanvas); + if (v instanceof MessageEntityView) { + MessageEntityView mv = (MessageEntityView) v; + mv.prepareToDraw(true); + v.draw(currentCanvas); + mv.prepareToDraw(false); + } else { + v.draw(currentCanvas); + } } currentCanvas.restore(); } @@ -3392,6 +3477,14 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } private void showMenuForEntity(final EntityView entityView) { + if (entityView instanceof MessageEntityView) { + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); + return; + } + return; + } + int[] pos = getCenterLocationInWindow(entityView); int x = pos[0]; int y = pos[1] - dp(32); @@ -3400,29 +3493,31 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai LinearLayout parent = new LinearLayout(getContext()); parent.setOrientation(LinearLayout.HORIZONTAL); - TextView deleteView = new TextView(getContext()); - deleteView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); - deleteView.setGravity(Gravity.CENTER_VERTICAL); - deleteView.setLines(1); - deleteView.setSingleLine(); - deleteView.setEllipsize(TextUtils.TruncateAt.END); - deleteView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); - deleteView.setPadding(dp(16), 0, dp(16), 0); - deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - deleteView.setTag(0); - deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); - deleteView.setOnClickListener(v -> { - if (entityView instanceof RoundView) { - onTryDeleteRound(); - } else { - removeEntity(entityView); - } + if (!(entityView instanceof MessageEntityView)) { + TextView deleteView = new TextView(getContext()); + deleteView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + deleteView.setGravity(Gravity.CENTER_VERTICAL); + deleteView.setLines(1); + deleteView.setSingleLine(); + deleteView.setEllipsize(TextUtils.TruncateAt.END); + deleteView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + deleteView.setPadding(dp(16), 0, dp(16), 0); + deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + deleteView.setTag(0); + deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); + deleteView.setOnClickListener(v -> { + if (entityView instanceof RoundView) { + onTryDeleteRound(); + } else { + removeEntity(entityView); + } - if (popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(true); - } - }); - parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + } if (entityView instanceof TextPaintView) { TextView editView = new TextView(getContext()); @@ -3494,7 +3589,23 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (!(entityView instanceof PhotoView) && !(entityView instanceof RoundView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { + if (entityView instanceof PhotoView && ((PhotoView) entityView).hasSegmentedImage()) { + PhotoView photoView = (PhotoView) entityView; + TextView cutView = createActionLayoutButton(5, LocaleController.getString(photoView.isSegmented() ? R.string.SegmentationUndoCutOut : R.string.SegmentationCutOut)); + cutView.setOnClickListener(v -> { + photoView.toggleSegmented(true); + if (photoView.isSegmented()) { + onSwitchSegmentedAnimation(photoView); + } + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(cutView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + photoView.highlightSegmented(); + } + + if (!(entityView instanceof PhotoView) && !(entityView instanceof MessageEntityView) && !(entityView instanceof RoundView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { TextView duplicateView = new TextView(getContext()); duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); duplicateView.setLines(1); @@ -3598,7 +3709,7 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai boolean occupied = false; for (int index = 0; index < entitiesView.getChildCount(); index++) { View view = entitiesView.getChildAt(index); - if (!(view instanceof EntityView)) + if (!(view instanceof EntityView) || view instanceof MessageEntityView) continue; Point location = ((EntityView) view).getPosition(); @@ -3933,6 +4044,10 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } + public void onSwitchSegmentedAnimation(PhotoView photoView) { + + } + public void onDeselectRound(RoundView roundView) { } @@ -3978,6 +4093,33 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai return view; } + public MessageEntityView createMessage(ArrayList messageObjects, boolean select, boolean hasVideo) { + forceChanges = true; + MessageEntityView view = new MessageEntityView(getContext(), centerPositionForEntity(), 0, 1f, messageObjects, blurManager, hasVideo, videoTextureHolder) { + @Override + public boolean drawForBitmap() { + return drawForThemeToggle; + } + }; + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + selectEntity(view); + } + return view; + } + + public MessageEntityView findMessageView() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child instanceof MessageEntityView) { + return (MessageEntityView) child; + } + } + return null; + } + public PhotoView createPhoto(TLObject obj, boolean select) { forceChanges = true; Size size = basePhotoSize(obj); @@ -4076,6 +4218,9 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai if (entityView != null) { undoStore.unregisterUndo(entityView.getUUID()); } + if (entityView instanceof PhotoView) { + ((PhotoView) entityView).deleteSegmentedFile(); + } weightChooserView.setValueOverride(weightDefaultValueOverride); weightChooserView.setShowPreview(true); @@ -4101,6 +4246,14 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai return selectEntity(entityView); } + public boolean isEntityDeletable() { + return isEntityDeletable(currentEntityView); + } + + public boolean isEntityDeletable(EntityView entityView) { + return !(entityView instanceof MessageEntityView); + } + @Override public void onEntityDragEnd(boolean delete) { updatePreviewViewTranslationY(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java index 2227f1f4d..c24eb0d64 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java @@ -55,7 +55,7 @@ public class PreviewButtons extends FrameLayout { private View shadowView; - private ArrayList buttons = new ArrayList<>(); + private ArrayList buttons = new ArrayList<>(); public ShareButtonView shareButton; private String shareText; @@ -79,6 +79,25 @@ public class PreviewButtons extends FrameLayout { updateAppearT(); } + public void setFiltersVisible(boolean visible) { + for (int i = 0; i < buttons.size(); ++i) { + ButtonView button = buttons.get(i); + if (button.id == BUTTON_ADJUST) { + button.setVisibility(visible ? View.VISIBLE : View.GONE); + } + } + } + + private boolean isFiltersVisible() { + for (int i = 0; i < buttons.size(); ++i) { + ButtonView button = buttons.get(i); + if (button.id == BUTTON_ADJUST) { + return button.getVisibility() == View.VISIBLE; + } + } + return false; + } + public void setShareText(String text) { if (TextUtils.equals(text, shareText)) { return; @@ -106,11 +125,19 @@ public class PreviewButtons extends FrameLayout { shareButton.layout(w - shareButton.getMeasuredWidth(), (h - shareButton.getMeasuredHeight()) / 2, w, (h + shareButton.getMeasuredHeight()) / 2); int W = w - dp(10 + 10 + 12.33f) - shareButton.getMeasuredWidth(); - int maxPossibleMargin = buttons.size() < 2 ? 0 : (W - buttons.size() * dp(40)) / (buttons.size() - 1); - int margin = Math.min(dp(20), maxPossibleMargin); + int visibleButtons = 0; + for (int i = 0; i < buttons.size(); ++i) { + ButtonView button = buttons.get(i); + if (button.getVisibility() == View.VISIBLE) { + visibleButtons++; + } + } + int maxPossibleMargin = visibleButtons < 2 ? 0 : (W - visibleButtons * dp(40)) / (visibleButtons - 1); + int margin = Math.min(dp(isFiltersVisible() ? 20 : 30), maxPossibleMargin); int t = (h - dp(40)) / 2, b = (h + dp(40)) / 2; - for (int i = 0, x = dp(12.33f); i < buttons.size(); ++i) { + for (int i = 0, x = dp(12.33f) + (!isFiltersVisible() ? (W - visibleButtons * dp(40) - (visibleButtons - 1) * margin) / 2 : 0); i < buttons.size(); ++i) { + if (buttons.get(i).getVisibility() != View.VISIBLE) continue; buttons.get(i).layout(x, t, x + dp(40), b); x += dp(40) + margin; } @@ -319,8 +346,10 @@ public class PreviewButtons extends FrameLayout { } private class ButtonView extends ImageView { + public final int id; public ButtonView(Context context, int id, int resId) { super(context); + this.id = id; setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); setScaleType(ScaleType.CENTER); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java index 7000412b2..e90825ba8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java @@ -1,16 +1,26 @@ package org.telegram.ui.Stories.recorder; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.ValueAnimator; +import android.app.Activity; import android.content.ContentUris; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PointF; import android.graphics.Shader; import android.graphics.SurfaceTexture; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.provider.MediaStore; @@ -18,25 +28,39 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.Size; +import android.util.SparseIntArray; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.TextureView; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.FrameLayout; +import androidx.annotation.NonNull; + import com.google.android.exoplayer2.C; import com.google.zxing.common.detector.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.EmojiThemes; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatBackgroundDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.BlurringShader; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.MotionBackgroundDrawable; +import org.telegram.ui.Components.Paint.Texture; import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.PhotoFilterView; import org.telegram.ui.Components.VideoEditTextureView; @@ -75,20 +99,19 @@ public class PreviewView extends FrameLayout { public static final long MAX_DURATION = 59_500L; public static final long MIN_DURATION = 1_000L; - private final HashMap partsBitmap = new HashMap<>(); - private final HashMap partsBounce = new HashMap<>(); - private final BlurringShader.BlurManager blurManager; + private final TextureViewHolder textureViewHolder; - public PreviewView(Context context, BlurringShader.BlurManager blurManager) { + public PreviewView(Context context, BlurringShader.BlurManager blurManager, TextureViewHolder textureViewHolder) { super(context); this.blurManager = blurManager; + this.textureViewHolder = textureViewHolder; - snapPaint.setStrokeWidth(AndroidUtilities.dp(1)); + snapPaint.setStrokeWidth(dp(1)); snapPaint.setStyle(Paint.Style.STROKE); snapPaint.setColor(0xffffffff); - snapPaint.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(1), 0x40000000); + snapPaint.setShadowLayer(dp(3), 0, dp(1), 0x40000000); } protected void onTimeDrag(boolean dragStart, long time, boolean dragEnd) {} @@ -112,7 +135,7 @@ public class PreviewView extends FrameLayout { if (entry == null) { setupVideoPlayer(null, whenReady, seekTo); setupImage(null); - setupParts(null); + setupWallpaper(null, false); gradientPaint.setShader(null); setupAudio((StoryEntry) null, false); setupRound(null, null, false); @@ -131,8 +154,36 @@ public class PreviewView extends FrameLayout { setupImage(entry); setupGradient(); } - setupParts(entry); applyMatrix(); + setupWallpaper(entry, false); + setupAudio(entry, false); + setupRound(entry, null, false); + } + + // set without video for faster transition + public void preset(StoryEntry entry) { + this.entry = entry; + if (entry == null) { + setupImage(null); + setupWallpaper(null, false); + gradientPaint.setShader(null); + setupAudio((StoryEntry) null, false); + setupRound(null, null, false); + return; + } + if (entry.isVideo) { + setupImage(entry); + if (entry.gradientTopColor != 0 || entry.gradientBottomColor != 0) { + setupGradient(); + } else { + entry.setupGradient(this::setupGradient); + } + } else { + setupImage(entry); + setupGradient(); + } + applyMatrix(); + setupWallpaper(entry, false); setupAudio(entry, false); setupRound(entry, null, false); } @@ -178,7 +229,7 @@ public class PreviewView extends FrameLayout { @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - + invalidateTextureViewHolder(); } @Override @@ -548,14 +599,16 @@ public class PreviewView extends FrameLayout { invalidate(); } - private void setupVideoPlayer(StoryEntry entry, Runnable whenReady, long seekTo) { + public void setupVideoPlayer(StoryEntry entry, Runnable whenReady, long seekTo) { if (entry == null) { if (videoPlayer != null) { videoPlayer.pause(); videoPlayer.releasePlayer(true); videoPlayer = null; } - if (textureView != null) { + if (textureViewHolder != null && textureViewHolder.active) { + textureViewHolder.setTextureView(null); + } else if (textureView != null) { textureView.clearAnimation(); textureView.animate().alpha(0).withEndAction(() -> { if (textureView != null) { @@ -566,7 +619,7 @@ public class PreviewView extends FrameLayout { }).start(); } if (timelineView != null) { - timelineView.setVideo(null, 1, 0); + timelineView.setVideo(false, null, 1, 0); } AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (whenReady != null) { @@ -626,6 +679,9 @@ public class PreviewView extends FrameLayout { @Override public void onRenderedFirstFrame() { + if (textureViewHolder != null && textureViewHolder.active) { + textureViewHolder.activateTextureView(videoWidth, videoHeight); + } if (whenReadyFinal[0] != null) { post(whenReadyFinal[0]); whenReadyFinal[0] = null; @@ -637,7 +693,7 @@ public class PreviewView extends FrameLayout { bitmap = null; invalidate(); } - } else if (textureView != null) { + } else if (textureView != null && !(textureViewHolder != null && textureViewHolder.active)) { textureView.animate().alpha(1f).setDuration(180).withEndAction(() -> { if (bitmap != null) { bitmap.recycle(); @@ -652,7 +708,9 @@ public class PreviewView extends FrameLayout { } @Override - public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + invalidateTextureViewHolder(); + } @Override public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { @@ -669,11 +727,15 @@ public class PreviewView extends FrameLayout { textureView = new VideoEditTextureView(getContext(), videoPlayer); blurManager.resetBitmap(); - textureView.updateUiBlurManager(blurManager); - textureView.setAlpha(whenReady == null ? 0f : 1f); + textureView.updateUiBlurManager(entry.isRepostMessage ? null : blurManager); textureView.setOpaque(false); applyMatrix(); - addView(textureView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT)); + if (textureViewHolder != null && textureViewHolder.active) { + textureViewHolder.setTextureView(textureView); + } else { + textureView.setAlpha(whenReady == null ? 0f : 1f); + addView(textureView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT)); + } entry.detectHDR((hdrInfo) -> { if (textureView != null) { @@ -694,7 +756,8 @@ public class PreviewView extends FrameLayout { checkVolumes(); updateAudioPlayer(true); - timelineView.setVideo(entry.getOriginalFile().getAbsolutePath(), getDuration(), entry.videoVolume); + final boolean isRound = entry.isRepostMessage && entry.messageObjects != null && entry.messageObjects.size() == 1 && entry.messageObjects.get(0).type == MessageObject.TYPE_ROUND_VIDEO; + timelineView.setVideo(isRound, entry.getOriginalFile().getAbsolutePath(), getDuration(), entry.videoVolume); timelineView.setVideoLeft(entry.left); timelineView.setVideoRight(entry.right); if (timelineView != null && seekTo > 0) { @@ -703,6 +766,60 @@ public class PreviewView extends FrameLayout { } } + public static class TextureViewHolder { + private TextureView textureView; + private Utilities.Callback whenTextureViewReceived; + private Utilities.Callback2 whenTextureViewActive; + public boolean textureViewActive; + public int videoWidth, videoHeight; + + public boolean active; + + public void setTextureView(TextureView textureView) { + if (this.textureView == textureView) return; + if (this.textureView != null) { + ViewParent parent = this.textureView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(this.textureView); + } + this.textureView = null; + } + textureViewActive = false; + this.textureView = textureView; + if (whenTextureViewReceived != null) { + whenTextureViewReceived.run(this.textureView); + } + } + + public void activateTextureView(int w, int h) { + textureViewActive = true; + videoWidth = w; + videoHeight = h; + if (whenTextureViewActive != null) { + whenTextureViewActive.run(videoWidth, videoHeight); + } + } + + public void takeTextureView(Utilities.Callback whenReceived, Utilities.Callback2 whenActive) { + whenTextureViewReceived = whenReceived; + whenTextureViewActive = whenActive; + if (textureView != null && whenTextureViewReceived != null) { + whenTextureViewReceived.run(textureView); + } + if (textureViewActive && whenTextureViewActive != null) { + whenTextureViewActive.run(videoWidth, videoHeight); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == textureView && entry != null && entry.isRepostMessage) { + return false; + } + return super.drawChild(canvas, child, drawingTime); + } + public void setupRound(StoryEntry entry, RoundView roundView, boolean animated) { if (entry == null || entry.round == null) { if (roundPlayer != null) { @@ -802,53 +919,6 @@ public class PreviewView extends FrameLayout { return t; } - public void setupParts(StoryEntry entry) { - if (entry == null) { - for (Bitmap bitmap : partsBitmap.values()) { - if (bitmap != null) { - bitmap.recycle(); - } - } - partsBitmap.clear(); - partsBounce.clear(); - return; - } - final int rw = getMeasuredWidth() <= 0 ? AndroidUtilities.displaySize.x : getMeasuredWidth(); - final int rh = (int) (rw * 16 / 9f); - for (int i = 0; i < entry.parts.size(); ++i) { - StoryEntry.Part part = entry.parts.get(i); - if (part == null) { - continue; - } - Bitmap bitmap = partsBitmap.get(part.id); - if (bitmap != null) { - continue; - } - String path = part.file.getPath(); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(path, options); - options.inJustDecodeBounds = false; - options.inSampleSize = StoryEntry.calculateInSampleSize(options, rw, rh); - bitmap = BitmapFactory.decodeFile(path, options); - partsBitmap.put(part.id, bitmap); - } - for (Iterator> i = partsBitmap.entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); - boolean found = false; - for (int j = 0; j < entry.parts.size(); ++j) { - if (entry.parts.get(j).id == e.getKey()) { - found = true; - break; - } - } - if (!found) { - i.remove(); - partsBounce.remove(e.getKey()); - } - } - } - public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterView) { if (filterTextureView != null) { removeView(filterTextureView); @@ -1026,7 +1096,10 @@ public class PreviewView extends FrameLayout { } } + private AnimatedFloat wallpaperDrawableCrossfade = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); private final Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + private Drawable lastWallpaperDrawable; + private Drawable wallpaperDrawable; private final Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private int gradientTop, gradientBottom; @@ -1065,10 +1138,35 @@ public class PreviewView extends FrameLayout { } private final AnimatedFloat thumbAlpha = new AnimatedFloat(this, 0, 320, CubicBezierInterpolator.EASE_OUT); + public boolean drawForThemeToggle = false; @Override protected void dispatchDraw(Canvas canvas) { - canvas.drawRect(0, 0, getWidth(), getHeight(), gradientPaint); + if (wallpaperDrawable != null) { + if (drawForThemeToggle) { + Path path = new Path(); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + path.addRoundRect(AndroidUtilities.rectTmp, dp(12), dp(12), Path.Direction.CW); + canvas.save(); + canvas.clipPath(path); + } + boolean drawableReady = true; + if (wallpaperDrawable instanceof MotionBackgroundDrawable) { + drawableReady = ((MotionBackgroundDrawable) wallpaperDrawable).getPatternBitmap() != null; + } + float crossfadeAlpha = !drawableReady ? 0f : wallpaperDrawableCrossfade.set(1f); + if (lastWallpaperDrawable != null && crossfadeAlpha < 1) { + lastWallpaperDrawable.setAlpha((int) (0xFF * (1f - crossfadeAlpha))); + StoryEntry.drawBackgroundDrawable(canvas, lastWallpaperDrawable, getWidth(), getHeight()); + } + wallpaperDrawable.setAlpha((int) (0xFF * crossfadeAlpha)); + StoryEntry.drawBackgroundDrawable(canvas, wallpaperDrawable, getWidth(), getHeight()); + if (drawForThemeToggle) { + canvas.restore(); + } + } else { + canvas.drawRect(0, 0, getWidth(), getHeight(), gradientPaint); + } if (draw && entry != null) { float alpha = this.thumbAlpha.set(bitmap != null); if (thumbBitmap != null && (1f - alpha) > 0) { @@ -1087,46 +1185,16 @@ public class PreviewView extends FrameLayout { } } super.dispatchDraw(canvas); - if (draw && entry != null) { - float trash = trashT.set(!inTrash); - for (int i = 0; i < entry.parts.size(); ++i) { - StoryEntry.Part part = entry.parts.get(i); - if (part == null) { - continue; - } - Bitmap bitmap = partsBitmap.get(part.id); - if (bitmap == null) { - continue; - } - float scale = 1f; - ButtonBounce bounce = partsBounce.get(part.id); - if (bounce != null) { - scale = bounce.getScale(.05f); - } - matrix.set(part.matrix); - canvas.save(); - if (scale != 1) { - tempVertices[0] = part.width / 2f; - tempVertices[1] = part.height / 2f; - matrix.mapPoints(tempVertices); - canvas.scale(scale, scale, tempVertices[0] / entry.resultWidth * getWidth(), tempVertices[1] / entry.resultHeight * getHeight()); - } - if (trashPartIndex == part.id) { - float trashScale = AndroidUtilities.lerp(.2f, 1f, trash); - canvas.scale(trashScale, trashScale, trashCx, trashCy); - } - matrix.preScale((float) part.width / bitmap.getWidth(), (float) part.height / bitmap.getHeight()); - matrix.postScale((float) getWidth() / entry.resultWidth, (float) getHeight() / entry.resultHeight); - canvas.drawBitmap(bitmap, matrix, bitmapPaint); - canvas.restore(); - } - } } public VideoEditTextureView getTextureView() { return textureView; } + protected void invalidateTextureViewHolder() { + + } + public Pair getPaintSize() { if (entry == null) { return new Pair<>(1080, 1920); @@ -1151,7 +1219,7 @@ public class PreviewView extends FrameLayout { } public void applyMatrix() { - if (entry == null) { + if (entry == null || entry.isRepostMessage) { return; } if (textureView != null) { @@ -1185,16 +1253,7 @@ public class PreviewView extends FrameLayout { private float rotationDiff; private boolean snappedToCenterAndScaled, snappedRotation; private boolean doNotSpanRotation; - private float[] tempPoint = new float[4]; - private IStoryPart activePart; - private boolean isPart; - private float Tx, Ty; - private boolean activePartPressed; - - private int trashPartIndex; - private boolean inTrash; - private AnimatedFloat trashT = new AnimatedFloat(this, 0, 280, CubicBezierInterpolator.EASE_OUT_QUINT); - private float trashCx, trashCy; + private boolean moving; public boolean additionalTouchEvent(MotionEvent ev) { return false; @@ -1229,33 +1288,15 @@ public class PreviewView extends FrameLayout { final float scale = (entry.resultWidth / (float) getWidth()); if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { - Tx = Ty = 0; rotationDiff = 0; snappedRotation = false; snappedToCenterAndScaled = false; doNotSpanRotation = false; - activePart = findPartAt(touch.x, touch.y); - if (isPart = (activePart instanceof StoryEntry.Part)) { - entry.parts.remove(activePart); - entry.parts.add((StoryEntry.Part) activePart); - trashPartIndex = activePart.id; - invalidate(); - allowWithSingleTouch = true; - ButtonBounce bounce = partsBounce.get(activePart.id); - if (bounce == null) { - partsBounce.put(activePart.id, bounce = new ButtonBounce(this)); - } - bounce.setPressed(true); - activePartPressed = true; - onEntityDragStart(); - onEntityDraggedTop(false); - onEntityDraggedBottom(false); - } else { - trashPartIndex = -1; - } - touchMatrix.set(activePart.matrix); + invalidate(); + moving = true; + touchMatrix.set(entry.matrix); } - if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && activePart != null) { + if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && moving && entry != null) { float tx = touch.x * scale, ty = touch.y * scale; float ltx = lastTouch.x * scale, lty = lastTouch.y * scale; if (ev.getPointerCount() > 1) { @@ -1285,15 +1326,6 @@ public class PreviewView extends FrameLayout { } if (ev.getPointerCount() > 1 || allowWithSingleTouch) { touchMatrix.postTranslate(tx - ltx, ty - lty); - Tx += (tx - ltx); - Ty += (ty - lty); - } - if (activePartPressed && MathUtils.distance(0, 0, Tx, Ty) > AndroidUtilities.touchSlop) { - ButtonBounce bounce = partsBounce.get(activePart.id); - if (bounce != null) { - bounce.setPressed(false); - } - activePartPressed = false; } finalMatrix.set(touchMatrix); matrix.set(touchMatrix); @@ -1312,41 +1344,19 @@ public class PreviewView extends FrameLayout { snappedRotation = false; } } - boolean trash = isPart && MathUtils.distance(touch.x, touch.y, getWidth() / 2f, getHeight() - AndroidUtilities.dp(76)) < AndroidUtilities.dp(35); - if (trash != inTrash) { - onEntityDragTrash(trash); - inTrash = trash; - } - if (trash) { - trashCx = touch.x; - trashCy = touch.y; - } - if (isPart) { - onEntityDraggedTop(cy - h / 2f < AndroidUtilities.dp(66) / (float) getHeight() * entry.resultHeight); - onEntityDraggedBottom(cy + h / 2f > entry.resultHeight - AndroidUtilities.dp(64 + 50) / (float) getHeight() * entry.resultHeight); - } - activePart.matrix.set(finalMatrix); + entry.matrix.set(finalMatrix); entry.editedMedia = true; applyMatrix(); invalidate(); } if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { - Tx = Ty = 0; - if (!(activePart instanceof StoryEntry.Part) || ev.getPointerCount() <= 1) { - ButtonBounce bounce = partsBounce.get(activePart.id); - if (bounce != null) { - bounce.setPressed(false); - } - activePartPressed = false; + if (ev.getPointerCount() <= 1) { allowWithSingleTouch = false; - onEntityDragEnd(inTrash && ev.getAction() == MotionEvent.ACTION_UP); - activePart = null; - inTrash = false; onEntityDraggedTop(false); onEntityDraggedBottom(false); } - isPart = false; + moving = false; allowRotation = false; rotationDiff = 0; @@ -1361,39 +1371,10 @@ public class PreviewView extends FrameLayout { return true; } - public void deleteCurrentPart() { - if (activePart != null) { - entry.parts.remove(activePart); - setupParts(entry); - } - } - - private Matrix tempMatrix; - private float[] tempVertices = new float[2]; - private IStoryPart findPartAt(float x, float y) { - for (int i = entry.parts.size() - 1; i >= 0; --i) { - IStoryPart part = entry.parts.get(i); - tempVertices[0] = x / getWidth() * entry.resultWidth; - tempVertices[1] = y / getHeight() * entry.resultHeight; - if (tempMatrix == null) { - tempMatrix = new Matrix(); - } - part.matrix.invert(tempMatrix); - tempMatrix.mapPoints(tempVertices); - if (tempVertices[0] >= 0 && tempVertices[0] <= part.width && tempVertices[1] >= 0 && tempVertices[1] <= part.height) { - return part; - } - } - return entry; - } - private long tapTime; - private float tapX, tapY; private boolean tapTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { tapTime = System.currentTimeMillis(); - tapX = ev.getX(); - tapY = ev.getY(); return true; } else if (ev.getAction() == MotionEvent.ACTION_UP) { if (System.currentTimeMillis() - tapTime <= ViewConfiguration.getTapTimeout() && onTap != null) { @@ -1424,10 +1405,8 @@ public class PreviewView extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean result = touchEvent(ev); - if (!(activePart instanceof StoryEntry.Part)) { - result = additionalTouchEvent(ev) || result; - tapTouchEvent(ev); - } + result = additionalTouchEvent(ev) || result; + tapTouchEvent(ev); if (result) { if (ev.getPointerCount() <= 1) { return super.dispatchTouchEvent(ev) || true; @@ -1479,4 +1458,202 @@ public class PreviewView extends FrameLayout { public void play(boolean play) { updatePauseReason(-9982, !play); } + + public static Drawable getBackgroundDrawable(Drawable prevDrawable, int currentAccount, long dialogId, boolean isDark) { + if (dialogId == Long.MIN_VALUE) { + return null; + } + TLRPC.WallPaper wallpaper = null; + if (dialogId >= 0) { + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(dialogId); + if (userFull != null) { + wallpaper = userFull.wallpaper; + } + } else { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null) { + wallpaper = chatFull.wallpaper; + } + } + return getBackgroundDrawable(prevDrawable, currentAccount, wallpaper, isDark); + } + + public static Drawable getBackgroundDrawable(Drawable prevDrawable, int currentAccount, TLRPC.WallPaper wallpaper, boolean isDark) { + if (wallpaper != null && TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(wallpaper))) { + return ChatBackgroundDrawable.getOrCreate(prevDrawable, wallpaper, isDark); + } + + EmojiThemes theme = null; + if (wallpaper != null && wallpaper.settings != null) { + theme = ChatThemeController.getInstance(currentAccount).getTheme(wallpaper.settings.emoticon); + } + if (theme != null) { + return getBackgroundDrawableFromTheme(currentAccount, theme, 0, isDark); + } + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("themeconfig", Activity.MODE_PRIVATE); + String dayThemeName = preferences.getString("lastDayTheme", "Blue"); + if (Theme.getTheme(dayThemeName) == null || Theme.getTheme(dayThemeName).isDark()) { + dayThemeName = "Blue"; + } + String nightThemeName = preferences.getString("lastDarkTheme", "Dark Blue"); + if (Theme.getTheme(nightThemeName) == null || !Theme.getTheme(nightThemeName).isDark()) { + nightThemeName = "Dark Blue"; + } + Theme.ThemeInfo themeInfo = Theme.getActiveTheme(); + if (dayThemeName.equals(nightThemeName)) { + if (themeInfo.isDark() || dayThemeName.equals("Dark Blue") || dayThemeName.equals("Night")) { + dayThemeName = "Blue"; + } else { + nightThemeName = "Dark Blue"; + } + } + if (isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } + SparseIntArray currentColors = new SparseIntArray(); + final String[] wallpaperLink = new String[1]; + final SparseIntArray themeColors; + if (themeInfo.assetName != null) { + themeColors = Theme.getThemeFileValues(null, themeInfo.assetName, wallpaperLink); + } else { + themeColors = Theme.getThemeFileValues(new File(themeInfo.pathToFile), null, wallpaperLink); + } + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); + } + } + Theme.ThemeAccent accent = themeInfo.getAccent(false); + if (accent != null) { + accent.fillAccentColors(themeColors, currentColors); + } else if (themeColors != null) { + for (int i = 0; i < themeColors.size(); ++i) { + currentColors.put(themeColors.keyAt(i), themeColors.valueAt(i)); + } + } + Theme.BackgroundDrawableSettings bg = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink[0], 0, true); + return bg.themedWallpaper != null ? bg.themedWallpaper : bg.wallpaper; + } + + public void setupWallpaper(StoryEntry entry, boolean animated) { + lastWallpaperDrawable = wallpaperDrawable; + if (wallpaperDrawable != null) { + wallpaperDrawable.setCallback(null); + } + if (entry == null) { + wallpaperDrawable = null; + return; + } + long dialogId = entry.backgroundWallpaperPeerId; + if (entry.backgroundWallpaperEmoticon != null) { + wallpaperDrawable = entry.backgroundDrawable = getBackgroundDrawableFromTheme(entry.currentAccount, entry.backgroundWallpaperEmoticon, entry.isDark); + } else if (dialogId != Long.MIN_VALUE) { + wallpaperDrawable = entry.backgroundDrawable = getBackgroundDrawable(wallpaperDrawable, entry.currentAccount, dialogId, entry.isDark); + } else { + wallpaperDrawable = null; + return; + } + if (lastWallpaperDrawable != wallpaperDrawable) { + if (animated) { + wallpaperDrawableCrossfade.set(0, true); + } else { + lastWallpaperDrawable = null; + } + } + if (wallpaperDrawable != null) { + wallpaperDrawable.setCallback(this); + } + if (blurManager != null) { + if (wallpaperDrawable != null) { + if (wallpaperDrawable instanceof BitmapDrawable) { + blurManager.setFallbackBlur(((BitmapDrawable) wallpaperDrawable).getBitmap(), 0); + } else { + int w = wallpaperDrawable.getIntrinsicWidth(); + int h = wallpaperDrawable.getIntrinsicHeight(); + if (w <= 0 || h <= 0) { + w = 1080; + h = 1920; + } + float scale = Math.max(100f / w, 100f / h); + if (scale > 1) { + w *= scale; + h *= scale; + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + wallpaperDrawable.setBounds(0, 0, w, h); + wallpaperDrawable.draw(new Canvas(bitmap)); + blurManager.setFallbackBlur(bitmap, 0, true); + } + } else { + blurManager.setFallbackBlur(null, 0); + } + } + invalidate(); + } + + public static Drawable getBackgroundDrawableFromTheme(int currentAccount, String emoticon, boolean isDark) { + return getBackgroundDrawableFromTheme(currentAccount, emoticon, isDark, false); + } + + public static Drawable getBackgroundDrawableFromTheme(int currentAccount, String emoticon, boolean isDark, boolean preview) { + EmojiThemes theme = ChatThemeController.getInstance(currentAccount).getTheme(emoticon); + if (theme == null) { + return Theme.getCachedWallpaper(); + } + return getBackgroundDrawableFromTheme(currentAccount, theme, 0, isDark, preview); + } + + public static Drawable getBackgroundDrawableFromTheme(int currentAccount, EmojiThemes chatTheme, int prevPhase, boolean isDark) { + return getBackgroundDrawableFromTheme(currentAccount, chatTheme, prevPhase, isDark, false); + } + + public static Drawable getBackgroundDrawableFromTheme(int currentAccount, EmojiThemes chatTheme, int prevPhase, boolean isDark, boolean preview) { + Drawable drawable; + if (chatTheme.showAsDefaultStub) { + Theme.ThemeInfo themeInfo = EmojiThemes.getDefaultThemeInfo(isDark); + SparseIntArray currentColors = chatTheme.getPreviewColors(currentAccount, isDark ? 1 : 0); + String wallpaperLink = chatTheme.getWallpaperLink(isDark ? 1 : 0); + Theme.BackgroundDrawableSettings settings = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink, prevPhase, false); + drawable = settings.wallpaper; + drawable = new ColorDrawable(Color.BLACK); + } else { + SparseIntArray currentColors = chatTheme.getPreviewColors(currentAccount, isDark ? 1 : 0); + int backgroundColor = currentColors.get(Theme.key_chat_wallpaper, Theme.getColor(Theme.key_chat_wallpaper)); + int gradientColor1 = currentColors.get(Theme.key_chat_wallpaper_gradient_to1, Theme.getColor(Theme.key_chat_wallpaper_gradient_to1)); + int gradientColor2 = currentColors.get(Theme.key_chat_wallpaper_gradient_to2, Theme.getColor(Theme.key_chat_wallpaper_gradient_to2)); + int gradientColor3 = currentColors.get(Theme.key_chat_wallpaper_gradient_to3, Theme.getColor(Theme.key_chat_wallpaper_gradient_to3)); + + MotionBackgroundDrawable motionDrawable = new MotionBackgroundDrawable(); + motionDrawable.isPreview = preview; + motionDrawable.setPatternBitmap(chatTheme.getWallpaper(isDark ? 1 : 0).settings.intensity); + motionDrawable.setColors(backgroundColor, gradientColor1, gradientColor2, gradientColor3, 0,true); + motionDrawable.setPhase(prevPhase); + int patternColor = motionDrawable.getPatternColor(); + final boolean isDarkTheme = isDark; + chatTheme.loadWallpaper(isDark ? 1 : 0, pair -> { + if (pair == null) { + return; + } + long themeId = pair.first; + Bitmap bitmap = pair.second; + if (themeId == chatTheme.getTlTheme(isDark ? 1 : 0).id && bitmap != null) { + int intensity = chatTheme.getWallpaper(isDarkTheme ? 1 : 0).settings.intensity; + motionDrawable.setPatternBitmap(intensity, bitmap); + motionDrawable.setPatternColorFilter(patternColor); + motionDrawable.setPatternAlpha(1f); + } + }); + drawable = motionDrawable; + } + return drawable; + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return wallpaperDrawable == who || super.verifyDrawable(who); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java index a06875614..12fdbfb33 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java @@ -8,16 +8,22 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Build; import android.provider.MediaStore; import android.text.SpannableString; +import android.text.TextUtils; import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -47,7 +53,7 @@ import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; -public class StoryEntry extends IStoryPart { +public class StoryEntry { public final int currentAccount = UserConfig.selectedAccount; @@ -70,6 +76,9 @@ public class StoryEntry extends IStoryPart { public String repostCaption; public TLRPC.MessageMedia repostMedia; + public boolean isRepostMessage; + public ArrayList messageObjects; + public boolean isError; public TLRPC.TL_error error; @@ -90,21 +99,20 @@ public class StoryEntry extends IStoryPart { public String thumbPath; public Bitmap thumbPathBitmap; public float videoVolume = 1f; + public int orientation, invert; public boolean muted; public float left, right = 1; - public int orientation; - public int invert; - // public int width, height; public long duration; public int resultWidth = 720; public int resultHeight = 1280; - public int partsMaxId = 1; - public final ArrayList parts = new ArrayList<>(); + public int width, height; + // matrix describes transformations from width x height to resultWidth x resultHeight + public final Matrix matrix = new Matrix(); public File round; public String roundThumb; @@ -115,42 +123,10 @@ public class StoryEntry extends IStoryPart { public TLRPC.InputPeer peer; - public static class Part extends IStoryPart { - public File file; - public boolean fileDeletable; - public int orientantion, invert; - - public void readParams(AbstractSerializedData stream, boolean exception) { - width = stream.readInt32(exception); - height = stream.readInt32(exception); - file = new File(stream.readString(exception)); - fileDeletable = stream.readBool(exception); - orientantion = stream.readInt32(exception); - invert = stream.readInt32(exception); - float[] values = new float[9]; - for (int i = 0; i < 9; ++i) { - values[i] = stream.readFloat(exception); - } - matrix.setValues(values); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(width); - stream.writeInt32(height); - stream.writeString(file == null ? "" : file.getAbsolutePath()); - stream.writeBool(fileDeletable); - stream.writeInt32(orientantion); - stream.writeInt32(invert); - float[] values = new float[9]; - matrix.getValues(values); - for (int i = 0; i < 9; ++i) { - stream.writeFloat(values[i]); - } - } - } - - // matrix describes transformations from width x height to resultWidth x resultHeight -// public final Matrix matrix = new Matrix(); + public Drawable backgroundDrawable; + public boolean isDark = Theme.isCurrentThemeDark(); + public long backgroundWallpaperPeerId = Long.MIN_VALUE; // Long.MIN_VALUE = no wallpaper + public String backgroundWallpaperEmoticon; public int gradientTopColor, gradientBottomColor; public CharSequence caption; @@ -180,6 +156,9 @@ public class StoryEntry extends IStoryPart { public ArrayList mediaEntities; public List stickers; public List editStickers; + public File messageFile; + public File messageVideoMaskFile; + public File backgroundFile; // filter public File filterFile; @@ -189,6 +168,10 @@ public class StoryEntry extends IStoryPart { private boolean fromCamera; public boolean wouldBeVideo() { + return wouldBeVideo(mediaEntities); + } + + public boolean wouldBeVideo(ArrayList mediaEntities) { if (isVideo) { return true; } @@ -225,6 +208,23 @@ public class StoryEntry extends IStoryPart { ); } + public static void drawBackgroundDrawable(Canvas canvas, Drawable drawable, int w, int h) { + if (drawable == null) { + return; + } + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bd = (BitmapDrawable) drawable; + int bw = bd.getBitmap().getWidth(); + int bh = bd.getBitmap().getHeight(); + final float scale = Math.max(w / (float) bw, h / (float) bh); + drawable.setBounds(0, 0, (int) (bw * scale), (int) (bh * scale)); + drawable.draw(canvas); + } else { + drawable.setBounds(0, 0, w, h); + drawable.draw(canvas); + } + } + public Bitmap buildBitmap(float scale, Bitmap mainFileBitmap) { Matrix tempMatrix = new Matrix(); @@ -233,9 +233,36 @@ public class StoryEntry extends IStoryPart { Bitmap finalBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(finalBitmap); - Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - gradientPaint.setShader(new LinearGradient(0, 0, 0, canvas.getHeight(), new int[] { gradientTopColor, gradientBottomColor }, new float[] {0, 1}, Shader.TileMode.CLAMP)); - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), gradientPaint); + if (backgroundFile != null) { + try { + Bitmap paintBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(backgroundFile.getPath(), opts), w, h, false); + canvas.save(); + float s = resultWidth / (float) paintBitmap.getWidth(); + canvas.scale(s, s); + tempMatrix.postScale(scale, scale); + canvas.drawBitmap(paintBitmap, 0, 0, bitmapPaint); + canvas.restore(); + paintBitmap.recycle(); + } catch (Exception e) { + FileLog.e(e); + } + } else if (backgroundWallpaperEmoticon != null) { + Drawable drawable = backgroundDrawable; + if (drawable == null) { + drawable = PreviewView.getBackgroundDrawableFromTheme(currentAccount, backgroundWallpaperEmoticon, isDark); + } + drawBackgroundDrawable(canvas, drawable, canvas.getWidth(), canvas.getHeight()); + } else if (backgroundWallpaperPeerId != Long.MIN_VALUE) { + Drawable drawable = backgroundDrawable; + if (drawable == null) { + drawable = PreviewView.getBackgroundDrawable(null, currentAccount, backgroundWallpaperPeerId, isDark); + } + drawBackgroundDrawable(canvas, drawable, canvas.getWidth(), canvas.getHeight()); + } else { + Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + gradientPaint.setShader(new LinearGradient(0, 0, 0, canvas.getHeight(), new int[]{gradientTopColor, gradientBottomColor}, new float[]{0, 1}, Shader.TileMode.CLAMP)); + canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), gradientPaint); + } tempMatrix.set(matrix); if (mainFileBitmap != null) { @@ -258,24 +285,24 @@ public class StoryEntry extends IStoryPart { } } - for (int i = 0; i < parts.size(); ++i) { + if (paintFile != null) { try { - final Part part = parts.get(i); - Bitmap fileBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(part.file.getPath(), opts), w, h, false); - final float s = (float) part.width / fileBitmap.getWidth(); - tempMatrix.set(part.matrix); - tempMatrix.preScale(s, s); + Bitmap paintBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(paintFile.getPath(), opts), w, h, false); + canvas.save(); + float s = resultWidth / (float) paintBitmap.getWidth(); + canvas.scale(s, s); tempMatrix.postScale(scale, scale); - canvas.drawBitmap(fileBitmap, tempMatrix, bitmapPaint); - fileBitmap.recycle(); + canvas.drawBitmap(paintBitmap, 0, 0, bitmapPaint); + canvas.restore(); + paintBitmap.recycle(); } catch (Exception e) { FileLog.e(e); } } - if (paintFile != null) { + if (messageFile != null) { try { - Bitmap paintBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(paintFile.getPath(), opts), w, h, false); + Bitmap paintBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(messageFile.getPath(), opts), w, h, false); canvas.save(); float s = resultWidth / (float) paintBitmap.getWidth(); canvas.scale(s, s); @@ -483,6 +510,18 @@ public class StoryEntry extends IStoryPart { paintFile.delete(); paintFile = null; } + if (backgroundFile != null) { + backgroundFile.delete(); + backgroundFile = null; + } + if (messageFile != null) { + messageFile.delete(); + messageFile = null; + } + if (messageVideoMaskFile != null) { + messageVideoMaskFile.delete(); + messageVideoMaskFile = null; + } if (paintEntitiesFile != null) { paintEntitiesFile.delete(); paintEntitiesFile = null; @@ -513,11 +552,17 @@ public class StoryEntry extends IStoryPart { } thumbPath = null; } - for (Part part : parts) { - if (part.fileDeletable) { - part.file.delete(); + if (mediaEntities != null) { + for (VideoEditedInfo.MediaEntity entity : mediaEntities) { + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO && !TextUtils.isEmpty(entity.segmentedPath)) { + try { + new File(entity.segmentedPath).delete(); + } catch (Exception e) { + FileLog.e(e); + } + entity.segmentedPath = ""; + } } - part.file = null; } if (round != null && (!isEdit || editedMedia)) { round.delete(); @@ -590,6 +635,115 @@ public class StoryEntry extends IStoryPart { return entry; } + public static boolean canRepostMessage(MessageObject messageObject) { + if (messageObject == null || messageObject.isSponsored()) { + return false; + } + if (messageObject.messageOwner != null && messageObject.messageOwner.noforwards) { + return false; + } + if (messageObject.type == MessageObject.TYPE_POLL || messageObject.type == MessageObject.TYPE_CONTACT) { + return false; + } + long dialogId = messageObject.getDialogId(); + TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); + if (chat != null && chat.noforwards) { + return false; + } + if (dialogId >= 0 || !ChatObject.isChannelAndNotMegaGroup(chat)) { + if (messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.from_id != null && (messageObject.messageOwner.fwd_from.flags & 4) != 0) { + dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.fwd_from.from_id); + chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); + if (dialogId >= 0 || chat != null && chat.noforwards || !ChatObject.isChannelAndNotMegaGroup(chat) || !ChatObject.isPublic(chat)) { + return false; + } + return true; + } + return false; + } + return true; + } + + public static Boolean useForwardForRepost(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) return null; + TLRPC.Peer peer = messageObject.messageOwner.peer_id; + long dialogId = DialogObject.getPeerDialogId(peer); + TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); + if (chat != null && chat.noforwards || !ChatObject.isChannelAndNotMegaGroup(chat)) { + if (messageObject.messageOwner.fwd_from != null && messageObject.messageOwner.fwd_from.from_id != null && (messageObject.messageOwner.fwd_from.flags & 4) != 0) { + dialogId = DialogObject.getPeerDialogId(messageObject.messageOwner.fwd_from.from_id); + chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); + if (dialogId >= 0 || chat != null && chat.noforwards || !ChatObject.isChannelAndNotMegaGroup(chat)) { + return null; // no repost + } else { + return true; // repost of forward + } + } + return null; // no repost + } + return false; // repost + } + + public static long getRepostDialogId(MessageObject messageObject) { + Boolean useForward = useForwardForRepost(messageObject); + if (useForward == null) return 0; + if (useForward) { + return DialogObject.getPeerDialogId(messageObject.messageOwner.fwd_from.from_id); + } else { + return messageObject.getDialogId(); + } + } + + public static int getRepostMessageId(MessageObject messageObject) { + Boolean useForward = useForwardForRepost(messageObject); + if (useForward == null) return 0; + if (useForward) { + return messageObject.messageOwner.fwd_from.channel_post; + } else { + return messageObject.getId(); + } + } + + public static StoryEntry repostMessage(ArrayList messageObjects) { + StoryEntry entry = new StoryEntry(); + entry.isRepostMessage = true; + entry.messageObjects = messageObjects; + entry.resultWidth = 1080; + entry.resultHeight = 1920; + MessageObject msg = messageObjects.get(0); + entry.backgroundWallpaperPeerId = getRepostDialogId(msg); + + VideoEditedInfo.MediaEntity entity = new VideoEditedInfo.MediaEntity(); + entity.type = VideoEditedInfo.MediaEntity.TYPE_MESSAGE; + entity.x = 0.5f; + entity.y = 0.5f; + entry.mediaEntities = new ArrayList<>(); + entry.mediaEntities.add(entity); + + if (messageObjects.size() == 1) { + MessageObject messageObject = messageObjects.get(0); + if (messageObject != null && (messageObject.type == MessageObject.TYPE_GIF || messageObject.type == MessageObject.TYPE_VIDEO || messageObject.type == MessageObject.TYPE_ROUND_VIDEO)) { + if (messageObject.messageOwner != null && messageObject.messageOwner.attachPath != null) { + entry.file = new File(messageObject.messageOwner.attachPath); + } + if (entry.file == null || !entry.file.exists()) { + entry.file = FileLoader.getInstance(entry.currentAccount).getPathToMessage(messageObject.messageOwner); + } + if (entry.file != null && entry.file.exists()) { + entry.isVideo = true; + entry.fileDeletable = false; + entry.duration = (long) (messageObject.getDuration() * 1000); + entry.left = 0; + entry.right = Math.min(1, 59_500f / entry.duration); + } else { + entry.file = null; + } + } + } + + return entry; + } + public static StoryEntry fromStoryItem(File file, TL_stories.StoryItem storyItem) { StoryEntry entry = new StoryEntry(); entry.isEdit = true; @@ -842,114 +996,124 @@ public class StoryEntry extends IStoryPart { resultWidth = 720; resultHeight = 1280; } - final String videoPath = file.getAbsolutePath(); - Utilities.globalQueue.postRunnable(() -> { - final int[] params = new int[AnimatedFileDrawable.PARAM_NUM_COUNT]; - AnimatedFileDrawable.getVideoInfo(videoPath, params); - AndroidUtilities.runOnUIThread(() -> { - VideoEditedInfo info = new VideoEditedInfo(); + final String videoPath = file == null ? null : file.getAbsolutePath(); + final int[] params = new int[AnimatedFileDrawable.PARAM_NUM_COUNT]; + Runnable fill = () -> { + VideoEditedInfo info = new VideoEditedInfo(); - info.isStory = true; - info.fromCamera = fromCamera; - info.originalWidth = width; - info.originalHeight = height; - info.resultWidth = resultWidth; - info.resultHeight = resultHeight; - info.paintPath = paintFile == null ? null : paintFile.getPath(); + info.isStory = true; + info.fromCamera = fromCamera; + info.originalWidth = width; + info.originalHeight = height; + info.resultWidth = resultWidth; + info.resultHeight = resultHeight; + info.paintPath = paintFile == null ? null : paintFile.getPath(); + info.messagePath = messageFile == null ? null : messageFile.getPath(); + info.messageVideoMaskPath = messageVideoMaskFile == null ? null : messageVideoMaskFile.getPath(); + info.backgroundPath = backgroundFile == null ? null : backgroundFile.getPath(); - final int encoderBitrate = MediaController.extractRealEncoderBitrate(info.resultWidth, info.resultHeight, info.bitrate, true); - if (isVideo) { - info.originalPath = videoPath; - info.isPhoto = false; - info.framerate = Math.min(59, params[AnimatedFileDrawable.PARAM_NUM_FRAMERATE]); - int videoBitrate = MediaController.getVideoBitrate(videoPath); - info.originalBitrate = videoBitrate == -1 ? params[AnimatedFileDrawable.PARAM_NUM_BITRATE] : videoBitrate; - if (info.originalBitrate < 1_000_000 && (mediaEntities != null && !mediaEntities.isEmpty())) { - info.bitrate = 2_000_000; - info.originalBitrate = -1; - } else if (info.originalBitrate < 500_000) { - info.bitrate = 2_500_000; - info.originalBitrate = -1; - } else { - info.bitrate = Utilities.clamp(info.originalBitrate, 3_000_000, 500_000); - } - FileLog.d("story bitrate, original = " + info.originalBitrate + " => " + info.bitrate); - info.originalDuration = (duration = params[AnimatedFileDrawable.PARAM_NUM_DURATION]) * 1000L; - info.startTime = (long) (left * duration) * 1000L; - info.endTime = (long) (right * duration) * 1000L; - info.estimatedDuration = info.endTime - info.startTime; - info.muted = muted; - info.estimatedSize = (long) (params[AnimatedFileDrawable.PARAM_NUM_AUDIO_FRAME_SIZE] + params[AnimatedFileDrawable.PARAM_NUM_DURATION] / 1000.0f * encoderBitrate / 8); - info.estimatedSize = Math.max(file.length(), info.estimatedSize); - info.filterState = filterState; - info.blurPath = paintBlurFile == null ? null : paintBlurFile.getPath(); - } else { - if (filterFile != null) { - info.originalPath = filterFile.getAbsolutePath(); - } else { - info.originalPath = videoPath; - } - info.isPhoto = true; - if (round != null) { - info.estimatedDuration = info.originalDuration = duration = (long) ((roundRight - roundLeft) * roundDuration); - } else if (audioPath != null) { - info.estimatedDuration = info.originalDuration = duration = (long) ((audioRight - audioLeft) * audioDuration); - } else { - info.estimatedDuration = info.originalDuration = duration = averageDuration; - } - info.startTime = -1; - info.endTime = -1; - info.muted = true; + final int encoderBitrate = MediaController.extractRealEncoderBitrate(info.resultWidth, info.resultHeight, info.bitrate, true); + if (isVideo && videoPath != null) { + info.originalPath = videoPath; + info.isPhoto = false; + info.framerate = Math.min(59, params[AnimatedFileDrawable.PARAM_NUM_FRAMERATE]); + int videoBitrate = MediaController.getVideoBitrate(videoPath); + info.originalBitrate = videoBitrate == -1 ? params[AnimatedFileDrawable.PARAM_NUM_BITRATE] : videoBitrate; + if (info.originalBitrate < 1_000_000 && (mediaEntities != null && !mediaEntities.isEmpty())) { + info.bitrate = 2_000_000; info.originalBitrate = -1; - info.bitrate = -1; - info.framerate = 30; - info.estimatedSize = (long) (duration / 1000.0f * encoderBitrate / 8); - info.filterState = null; + } else if (info.originalBitrate < 500_000) { + info.bitrate = 2_500_000; + info.originalBitrate = -1; + } else { + info.bitrate = Utilities.clamp(info.originalBitrate, 3_000_000, 500_000); } - info.avatarStartTime = -1; - - info.cropState = new MediaController.CropState(); - info.cropState.useMatrix = new Matrix(); - info.cropState.useMatrix.set(matrix); - - info.mediaEntities = mediaEntities; - - info.gradientTopColor = gradientTopColor; - info.gradientBottomColor = gradientBottomColor; - info.forceFragmenting = true; - - info.hdrInfo = hdrInfo; - info.parts = parts; - - info.mixedSoundInfos.clear(); + FileLog.d("story bitrate, original = " + info.originalBitrate + " => " + info.bitrate); + info.originalDuration = (duration = params[AnimatedFileDrawable.PARAM_NUM_DURATION]) * 1000L; + info.startTime = (long) (left * duration) * 1000L; + info.endTime = (long) (right * duration) * 1000L; + info.estimatedDuration = info.endTime - info.startTime; + info.muted = muted; + info.estimatedSize = (long) (params[AnimatedFileDrawable.PARAM_NUM_AUDIO_FRAME_SIZE] + params[AnimatedFileDrawable.PARAM_NUM_DURATION] / 1000.0f * encoderBitrate / 8); + info.estimatedSize = Math.max(file.length(), info.estimatedSize); + info.filterState = filterState; + info.blurPath = paintBlurFile == null ? null : paintBlurFile.getPath(); + } else { + if (filterFile != null) { + info.originalPath = filterFile.getAbsolutePath(); + } else { + info.originalPath = videoPath; + } + info.isPhoto = true; if (round != null) { - final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(round.getAbsolutePath()); - soundInfo.volume = roundVolume; - soundInfo.audioOffset = (long) (roundLeft * roundDuration) * 1000L; - if (isVideo) { - soundInfo.startTime = (long) (roundOffset - left * duration) * 1000L; - } else { - soundInfo.startTime = 0; - } - soundInfo.duration = (long) ((roundRight - roundLeft) * roundDuration) * 1000L; - info.mixedSoundInfos.add(soundInfo); - } - if (audioPath != null) { - final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(audioPath); - soundInfo.volume = audioVolume; - soundInfo.audioOffset = (long) (audioLeft * audioDuration) * 1000L; - if (isVideo) { - soundInfo.startTime = (long) (audioOffset - left * duration) * 1000L; - } else { - soundInfo.startTime = 0; - } - soundInfo.duration = (long) ((audioRight - audioLeft) * audioDuration) * 1000L; - info.mixedSoundInfos.add(soundInfo); + info.estimatedDuration = info.originalDuration = duration = (long) ((roundRight - roundLeft) * roundDuration); + } else if (audioPath != null) { + info.estimatedDuration = info.originalDuration = duration = (long) ((audioRight - audioLeft) * audioDuration); + } else { + info.estimatedDuration = info.originalDuration = duration = averageDuration; } + info.startTime = -1; + info.endTime = -1; + info.muted = true; + info.originalBitrate = -1; + info.bitrate = -1; + info.framerate = 30; + info.estimatedSize = (long) (duration / 1000.0f * encoderBitrate / 8); + info.filterState = null; + } + info.account = currentAccount; + info.wallpaperPeerId = backgroundWallpaperPeerId; + info.isDark = isDark; + info.avatarStartTime = -1; - whenDone.run(info); + info.cropState = new MediaController.CropState(); + info.cropState.useMatrix = new Matrix(); + info.cropState.useMatrix.set(matrix); + + info.mediaEntities = mediaEntities; + + info.gradientTopColor = gradientTopColor; + info.gradientBottomColor = gradientBottomColor; + info.forceFragmenting = true; + + info.hdrInfo = hdrInfo; + + info.mixedSoundInfos.clear(); + if (round != null) { + final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(round.getAbsolutePath()); + soundInfo.volume = roundVolume; + soundInfo.audioOffset = (long) (roundLeft * roundDuration) * 1000L; + if (isVideo) { + soundInfo.startTime = (long) (roundOffset - left * duration) * 1000L; + } else { + soundInfo.startTime = 0; + } + soundInfo.duration = (long) ((roundRight - roundLeft) * roundDuration) * 1000L; + info.mixedSoundInfos.add(soundInfo); + } + if (audioPath != null) { + final MediaCodecVideoConvertor.MixedSoundInfo soundInfo = new MediaCodecVideoConvertor.MixedSoundInfo(audioPath); + soundInfo.volume = audioVolume; + soundInfo.audioOffset = (long) (audioLeft * audioDuration) * 1000L; + if (isVideo) { + soundInfo.startTime = (long) (audioOffset - left * duration) * 1000L; + } else { + soundInfo.startTime = 0; + } + soundInfo.duration = (long) ((audioRight - audioLeft) * audioDuration) * 1000L; + info.mixedSoundInfos.add(soundInfo); + } + + whenDone.run(info); + }; + if (file == null) { + fill.run(); + } else { + Utilities.globalQueue.postRunnable(() -> { + AnimatedFileDrawable.getVideoInfo(videoPath, params); + AndroidUtilities.runOnUIThread(fill); }); - }); + } } public static File makeCacheFile(final int account, boolean video) { @@ -1166,9 +1330,6 @@ public class StoryEntry extends IStoryPart { newEntry.height = height; newEntry.resultWidth = resultWidth; newEntry.resultHeight = resultHeight; - newEntry.partsMaxId = partsMaxId; - newEntry.parts.clear(); - newEntry.parts.addAll(parts); newEntry.peer = peer; newEntry.invert = invert; newEntry.matrix.set(matrix); @@ -1189,6 +1350,8 @@ public class StoryEntry extends IStoryPart { newEntry.uploadThumbFile = uploadThumbFile; newEntry.draftThumbFile = draftThumbFile; newEntry.paintFile = paintFile; + newEntry.messageFile = messageFile; + newEntry.backgroundFile = backgroundFile; newEntry.paintBlurFile = paintBlurFile; newEntry.paintEntitiesFile = paintEntitiesFile; newEntry.averageDuration = averageDuration; 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 7163aaac3..55bbf5ee9 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 @@ -20,6 +20,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Insets; @@ -31,6 +32,7 @@ import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -53,7 +55,6 @@ import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.URLSpan; -import android.util.Log; import android.util.Pair; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -68,6 +69,7 @@ import android.view.WindowInsets; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; @@ -82,7 +84,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BotWebViewVibrationEffect; -import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -111,20 +112,25 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.AvatarSpan; -import org.telegram.ui.BasePermissionsActivity; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.BlobDrawable; +import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlurringShader; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.GestureDetectorFixDoubleTap; import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Paint.RenderView; +import org.telegram.ui.Components.Paint.Views.EntityView; +import org.telegram.ui.Components.Paint.Views.MessageEntityView; +import org.telegram.ui.Components.Paint.Views.PhotoView; import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.PhotoFilterBlurControl; import org.telegram.ui.Components.PhotoFilterCurvesControl; @@ -135,6 +141,7 @@ import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.TextStyleSpan; +import org.telegram.ui.Components.ThanosEffect; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.VideoEditTextureView; import org.telegram.ui.Components.WaveDrawable; @@ -172,6 +179,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private WindowView windowView; private ContainerView containerView; private FlashViews flashViews; + private ThanosEffect thanosEffect; private static StoryRecorder instance; private boolean wasSend; @@ -243,7 +251,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg int type = 0; float rounding; RectF screenRect = new RectF(); + Drawable backgroundDrawable; ImageReceiver backgroundImageReceiver; + boolean hasShadow; Paint backgroundPaint; Drawable iconDrawable; int iconSize; @@ -343,6 +353,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg final View imageView = floatingButton.getChildAt(0); imageView.getLocationOnScreen(loc); src.screenRect.set(loc[0], loc[1], loc[0] + imageView.getWidth(), loc[1] + imageView.getHeight()); + src.hasShadow = true; src.backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); src.backgroundPaint.setColor(Theme.getColor(Theme.key_chats_actionBackground)); src.iconDrawable = floatingButton.getContext().getResources().getDrawable(R.drawable.story_camera).mutate(); @@ -351,6 +362,36 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg return src; } + public static SourceView fromShareCell(ShareDialogCell shareDialogCell) { + if (shareDialogCell == null) { + return null; + } + BackupImageView imageView = shareDialogCell.getImageView(); + SourceView src = new SourceView() { + @Override + protected void show() { + imageView.setVisibility(View.VISIBLE); + } + @Override + protected void hide() { + imageView.post(() -> { + imageView.setVisibility(View.GONE); + }); + } + }; + int[] loc = new int[2]; + imageView.getLocationOnScreen(loc); + src.screenRect.set(loc[0], loc[1], loc[0] + imageView.getWidth(), loc[1] + imageView.getHeight()); + src.backgroundDrawable = new ShareDialogCell.RepostStoryDrawable(imageView.getContext(), null, false, shareDialogCell.resourcesProvider); +// src.hasShadow = false; +// src.backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); +// src.backgroundPaint.setColor(Theme.getColor(Theme.key_chats_actionBackground)); +// src.iconDrawable = shareDialogCell.getContext().getResources().getDrawable(R.drawable.large_repost_story).mutate(); +// src.iconSize = AndroidUtilities.dp(30); + src.rounding = Math.max(src.screenRect.width(), src.screenRect.height()) / 2f; + return src; + } + public static SourceView fromStoryCell(DialogStoriesCell.StoryCell storyCell) { if (storyCell == null || storyCell.getRootView() == null) { return null; @@ -403,6 +444,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg fromRect.set(sourceView.screenRect); fromRounding = sourceView.rounding; } else { + fromSourceView = null; openType = 0; fromRect.set(0, dp(100), AndroidUtilities.displaySize.x, dp(100) + AndroidUtilities.displaySize.y); fromRounding = dp(8); @@ -422,6 +464,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg prepareClosing = false; // privacySelectorHintOpened = false; forceBackgroundVisible = false; + videoTextureHolder.active = false; if (windowManager != null && windowView != null && windowView.getParent() == null) { windowManager.addView(windowView, windowLayoutParams); @@ -479,6 +522,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg outputEntry = entry; isVideo = outputEntry != null && outputEntry.isVideo; + videoTextureHolder.active = false; if (sourceView != null) { fromSourceView = sourceView; @@ -513,6 +557,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }, time); navigateTo(PAGE_PREVIEW, false); switchToEditMode(EDIT_MODE_NONE, false); + previewButtons.appear(false, false); addNotificationObservers(); } @@ -532,6 +577,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg outputEntry = entry; StoryPrivacySelector.applySaved(currentAccount, outputEntry); isVideo = outputEntry != null && outputEntry.isVideo; + videoTextureHolder.active = false; if (sourceView != null) { fromSourceView = sourceView; @@ -562,14 +608,68 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg navigateToPreviewWithPlayerAwait(() -> { animateOpenTo(1, animated, this::onOpenDone); - previewButtons.appear(true, true); }, time); + previewButtons.appear(true, false); navigateTo(PAGE_PREVIEW, false); switchToEditMode(EDIT_MODE_NONE, false); addNotificationObservers(); } + private static boolean firstOpen = true; + public void openRepost(SourceView sourceView, StoryEntry entry) { + if (isShown) { + return; + } + + prepareClosing = false; + forceBackgroundVisible = false; + + if (windowManager != null && windowView != null && windowView.getParent() == null) { + windowManager.addView(windowView, windowLayoutParams); + } + + outputEntry = entry; + StoryPrivacySelector.applySaved(currentAccount, outputEntry); + isVideo = outputEntry != null && outputEntry.isVideo; + videoTextureHolder.active = isVideo; + + if (sourceView != null) { + fromSourceView = sourceView; + openType = sourceView.type; + fromRect.set(sourceView.screenRect); + fromRounding = sourceView.rounding; + fromSourceView.hide(); + } else { + openType = 0; + fromRect.set(0, dp(100), AndroidUtilities.displaySize.x, dp(100) + AndroidUtilities.displaySize.y); + fromRounding = dp(8); + } + + containerView.updateBackground(); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); + + containerView.setTranslationX(0); + containerView.setTranslationY(0); + containerView.setTranslationY2(0); + containerView.setScaleX(1f); + containerView.setScaleY(1f); + dismissProgress = 0; + + AndroidUtilities.lockOrientation(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + + if (outputEntry != null) { + captionEdit.setText(outputEntry.caption); + } + + previewButtons.appear(true, false); + navigateTo(PAGE_PREVIEW, false); + switchToEditMode(EDIT_MODE_NONE, false); + animateOpenTo(1, true, this::onOpenDone); + + addNotificationObservers(); + } + public void close(boolean animated) { if (!isShown) { return; @@ -662,6 +762,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg onFullyOpenListener.run(); onFullyOpenListener = null; } + + containerView.invalidate(); + previewContainer.invalidate(); } }); if (value < 1 && wasSend) { @@ -669,7 +772,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg openCloseAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); } else { if (value > 0 || containerView.getTranslationY1() < AndroidUtilities.dp(20)) { - openCloseAnimator.setDuration(270L); + openCloseAnimator.setDuration(300L); openCloseAnimator.setInterpolator(new FastOutSlowInInterpolator()); } else { openCloseAnimator.setDuration(400L); @@ -688,6 +791,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } checkBackgroundVisibility(); } + if (value > 0) { + firstOpen = false; + } } private void onOpenDone() { @@ -713,6 +819,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg createPhotoPaintView(); hidePhotoPaintView(); createFilterPhotoView(); + } else if (outputEntry != null && outputEntry.isRepostMessage) { + if (outputEntry.isVideo) { + previewView.setupVideoPlayer(outputEntry, null, 0); + } + createFilterPhotoView(); } } @@ -814,7 +925,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private GestureDetectorFixDoubleTap gestureDetector; private ScaleGestureDetector scaleGestureDetector; - public WindowView(Context context) { + public WindowView(Context context) { super(context); gestureDetector = new GestureDetectorFixDoubleTap(context, new GestureListener()); scaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener()); @@ -884,8 +995,14 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg fromSourceView.backgroundImageReceiver.setAlpha(alpha); fromSourceView.backgroundImageReceiver.draw(canvas); fromSourceView.backgroundImageReceiver.setRoundRadius(prevRoundRadius); + } else if (fromSourceView.backgroundDrawable != null) { + fromSourceView.backgroundDrawable.setBounds((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom); + fromSourceView.backgroundDrawable.setAlpha((int) (0xFF * alpha * alpha * alpha)); + fromSourceView.backgroundDrawable.draw(canvas); } else if (fromSourceView.backgroundPaint != null) { - fromSourceView.backgroundPaint.setShadowLayer(dp(2), 0, dp(3), Theme.multAlpha(0x33000000, alpha)); + if (fromSourceView.hasShadow) { + fromSourceView.backgroundPaint.setShadowLayer(dp(2), 0, dp(3), Theme.multAlpha(0x33000000, alpha)); + } fromSourceView.backgroundPaint.setAlpha((int) (0xFF * alpha)); canvas.drawRoundRect(rectF, r, r, fromSourceView.backgroundPaint); } @@ -1194,6 +1311,21 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg MeasureSpec.makeMeasureSpec(W, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(H, MeasureSpec.EXACTLY) ); + if (thanosEffect != null) { + thanosEffect.measure( + MeasureSpec.makeMeasureSpec(W, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(H, MeasureSpec.EXACTLY) + ); + } + if (changeDayNightView != null) { + changeDayNightView.measure( + MeasureSpec.makeMeasureSpec(W, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(H, MeasureSpec.EXACTLY) + ); + } + if (themeSheet != null) { + themeSheet.measure(widthMeasureSpec, heightMeasureSpec); + } if (galleryListView != null) { galleryListView.measure(MeasureSpec.makeMeasureSpec(previewW, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(H, MeasureSpec.EXACTLY)); @@ -1276,10 +1408,19 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg containerView.layout(l, t, r, b); flashViews.backgroundView.layout(0, 0, W, H); + if (thanosEffect != null) { + thanosEffect.layout(0, 0, W, H); + } + if (changeDayNightView != null) { + changeDayNightView.layout(0, 0, W, H); + } if (galleryListView != null) { galleryListView.layout((W - galleryListView.getMeasuredWidth()) / 2, 0, (W + galleryListView.getMeasuredWidth()) / 2, H); } + if (themeSheet != null) { + themeSheet.layout((W - themeSheet.getMeasuredWidth()) / 2, H - themeSheet.getMeasuredHeight(), (W + themeSheet.getMeasuredWidth()) / 2, H); + } if (captionEdit != null) { EmojiView emojiView = captionEdit.editText.getEmojiView(); @@ -1374,6 +1515,14 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + @Override + public void invalidate() { + if (openCloseAnimator != null && openCloseAnimator.isRunning()) { + return; + } + super.invalidate(); + } + private float translationY1; private float translationY2; @@ -1496,7 +1645,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg topGradient = new LinearGradient(0, top, 0, top + dp(72), new int[] {0x40000000, 0x00000000}, new float[] { top / (top + dp(72)), 1 }, Shader.TileMode.CLAMP ); topGradientPaint.setShader(topGradient); } - topGradientPaint.setAlpha((int) (0xFF * openProgress)); + topGradientPaint.setAlpha(0xFF); AndroidUtilities.rectTmp.set(0, 0, getWidth(), dp(72 + 12) + top); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(12), dp(12), topGradientPaint); } @@ -1515,6 +1664,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private FrameLayout previewContainer; private FrameLayout actionBarContainer; + private LinearLayout actionBarButtons; private FrameLayout controlContainer; private FrameLayout captionContainer; private FrameLayout navbarContainer; @@ -1523,6 +1673,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private SimpleTextView titleTextView; private StoryPrivacyBottomSheet privacySheet; private BlurringShader.BlurManager blurManager; + private PreviewView.TextureViewHolder videoTextureHolder; private View captionEditOverlay; /* PAGE_CAMERA */ @@ -1542,6 +1693,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private HintTextView hintTextView; private ZoomControlView zoomControlView; private HintView2 cameraHint; + private StoryThemeSheet themeSheet; /* PAGE_PREVIEW */ private PreviewView previewView; @@ -1553,6 +1705,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private DownloadButton downloadButton; private RLottieDrawable muteButtonDrawable; private RLottieImageView muteButton; + private RLottieDrawable themeButtonDrawable; + private ImageView themeButton; private PlayPauseButton playButton; private HintView2 muteHint; private HintView2 dualHint; @@ -1682,10 +1836,19 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg setSystemGestureExclusionRects(Arrays.asList(leftExclRect, rightExclRect)); } } + + @Override + public void invalidate() { + if (openCloseAnimator != null && openCloseAnimator.isRunning()) { + return; + } + super.invalidate(); + } }); containerView.addView(flashViews.foregroundView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); blurManager = new BlurringShader.BlurManager(previewContainer); + videoTextureHolder = new PreviewView.TextureViewHolder(); containerView.addView(actionBarContainer = new FrameLayout(context)); // 150dp containerView.addView(controlContainer = new FrameLayout(context)); // 220dp containerView.addView(captionContainer = new FrameLayout(context) { @@ -1739,7 +1902,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg previewContainer.setClipToOutline(true); } photoFilterEnhanceView = new PhotoFilterView.EnhanceView(context, this::createFilterPhotoView); - previewView = new PreviewView(context, blurManager) { + previewView = new PreviewView(context, blurManager, videoTextureHolder) { @Override public boolean additionalTouchEvent(MotionEvent ev) { if (captionEdit != null && captionEdit.isRecording()) { @@ -1774,9 +1937,6 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg trash.animate().alpha(0f).withEndAction(() -> { trash.setVisibility(View.GONE); }).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).setStartDelay(delete ? 500 : 0).start(); - if (delete) { - deleteCurrentPart(); - } super.onEntityDragEnd(delete); } @@ -1838,6 +1998,18 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } } + + @Override + protected void invalidateTextureViewHolder() { + if (outputEntry != null && outputEntry.isRepostMessage && outputEntry.isVideo && paintView != null && paintView.entitiesView != null) { + for (int i = 0; i < paintView.entitiesView.getChildCount(); ++i) { + View child = paintView.entitiesView.getChildAt(i); + if (child instanceof MessageEntityView) { + ((MessageEntityView) child).invalidateAll(); + } + } + } + } }; previewView.invalidateBlur = this::invalidateBlur; previewView.setOnTapListener(() -> { @@ -1864,6 +2036,29 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg previewContainer.addView(photoFilterEnhanceView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); captionEdit = new CaptionStory(context, windowView, windowView, containerView, resourcesProvider, blurManager) { + @Override + protected boolean ignoreTouches(float x, float y) { + if (paintView == null || paintView.entitiesView == null || captionEdit.keyboardShown) return false; + x += captionEdit.getX(); + y += captionEdit.getY(); + x += captionContainer.getX(); + y += captionContainer.getY(); + x -= previewContainer.getX(); + y -= previewContainer.getY(); + + for (int i = 0; i < paintView.entitiesView.getChildCount(); ++i) { + View view = paintView.entitiesView.getChildAt(i); + if (view instanceof EntityView) { + org.telegram.ui.Components.Rect rect = ((EntityView) view).getSelectionBounds(); + AndroidUtilities.rectTmp.set(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); + if (AndroidUtilities.rectTmp.contains(x, y)) { + return true; + } + } + } + return false; + } + @Override protected void drawBlurBitmap(Bitmap bitmap, float amount) { windowView.drawBlurBitmap(bitmap, amount); @@ -1872,7 +2067,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @Override protected boolean captionLimitToast() { - if (MessagesController.getInstance(currentAccount).premiumLocked) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { return false; } Bulletin visibleBulletin = Bulletin.getVisibleBulletin(); @@ -2099,14 +2294,19 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg titleTextView.setRightPadding(AndroidUtilities.dp(144)); actionBarContainer.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 56, Gravity.TOP | Gravity.FILL_HORIZONTAL, 71, 0, 0, 0)); + actionBarButtons = new LinearLayout(context); + actionBarButtons.setOrientation(LinearLayout.HORIZONTAL); + actionBarButtons.setGravity(Gravity.RIGHT); + actionBarContainer.addView(actionBarButtons, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 56, Gravity.RIGHT | Gravity.FILL_HORIZONTAL, 0, 0, 8, 0)); + downloadButton = new DownloadButton(context, done -> { applyPaint(); + applyPaintMessage(); applyFilter(done); }, currentAccount, windowView, resourcesProvider); - actionBarContainer.addView(downloadButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT)); muteHint = new HintView2(activity, HintView2.DIRECTION_TOP) - .setJoint(1, -68) + .setJoint(1, -77 + 8 - 2) .setDuration(2000) .setBounce(false) .setAnimatedTextHacks(true, true, false); @@ -2137,7 +2337,6 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }); muteButton.setVisibility(View.GONE); muteButton.setAlpha(0f); - actionBarContainer.addView(muteButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT, 0, 0, 48, 0)); playButton = new PlayPauseButton(context); playButton.setBackground(Theme.createSelectorDrawable(0x20ffffff)); @@ -2148,7 +2347,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg previewView.play(!playing); playButton.drawable.setPause(!playing, true); }); - actionBarContainer.addView(playButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT, 0, 0, 48 + 48, 0)); + + actionBarButtons.addView(playButton, LayoutHelper.createLinear(46, 56, Gravity.TOP | Gravity.RIGHT)); + actionBarButtons.addView(muteButton, LayoutHelper.createLinear(46, 56, Gravity.TOP | Gravity.RIGHT)); + actionBarButtons.addView(downloadButton, LayoutHelper.createFrame(46, 56, Gravity.TOP | Gravity.RIGHT)); flashButton = new ToggleButton2(context); flashButton.setBackground(Theme.createSelectorDrawable(0x20ffffff)); @@ -2492,12 +2694,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg return; } preparingUpload = true; - Utilities.globalQueue.postRunnable(() -> { - applyPaint(); - AndroidUtilities.runOnUIThread(() -> { - preparingUpload = false; - uploadInternal(asStory); - }); + applyPaintInBackground(() -> { + applyPaintMessage(); + preparingUpload = false; + uploadInternal(asStory); }); } @@ -2599,7 +2799,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg final Paint bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); TextureView textureView = previewView.getTextureView(); - if (storyEntry.isVideo && textureView != null) { + if (storyEntry.isVideo && !storyEntry.isRepostMessage && textureView != null) { Bitmap previewTextureView = textureView.getBitmap(); Matrix matrix = textureView.getTransform(null); if (matrix != null) { @@ -2641,9 +2841,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (paintView != null && paintView.entitiesView != null) { canvas.save(); canvas.scale(scale, scale); + paintView.drawForThemeToggle = true; paintView.entitiesView.drawForThumb = true; paintView.entitiesView.draw(canvas); paintView.entitiesView.drawForThumb = false; + paintView.drawForThemeToggle = false; canvas.restore(); } @@ -3166,6 +3368,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } public boolean onBackPressed() { + if (openCloseAnimator != null && openCloseAnimator.isRunning()) { + return false; + } if (captionEdit != null && captionEdit.stopRecording()) { return false; } @@ -3178,6 +3383,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } if (captionEdit.onBackPressed()) { return false; + } else if (themeSheet != null) { + themeSheet.dismiss(); + return false; } else if (galleryListView != null) { if (galleryListView.onBackPressed()) { return false; @@ -3190,10 +3398,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } else if (currentEditMode > EDIT_MODE_NONE) { switchToEditMode(EDIT_MODE_NONE, true); return false; - } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isRepost) && (outputEntry == null || !outputEntry.isEdit || (paintView != null && paintView.hasChanges()) || outputEntry.editedMedia || outputEntry.editedCaption)) { + } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isRepost && !outputEntry.isRepostMessage) && (outputEntry == null || !outputEntry.isEdit || (paintView != null && paintView.hasChanges()) || outputEntry.editedMedia || outputEntry.editedCaption)) { if (paintView != null && paintView.onBackPressed()) { return false; - } else if ((fromGallery && (paintView == null || !paintView.hasChanges()) && (outputEntry == null || outputEntry.filterFile == null) || !previewButtons.isShareEnabled()) && (outputEntry == null || !outputEntry.isEdit || !outputEntry.isRepost)) { + } else if ((fromGallery && (paintView == null || !paintView.hasChanges()) && (outputEntry == null || outputEntry.filterFile == null) || !previewButtons.isShareEnabled()) && (outputEntry == null || !outputEntry.isEdit || !outputEntry.isRepost && !outputEntry.isRepostMessage)) { navigateTo(PAGE_CAMERA, true); } else { showDismissEntry(); @@ -3239,6 +3447,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private Runnable afterPlayerAwait; private boolean previewAlreadySet; public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo) { + navigateToPreviewWithPlayerAwait(open, seekTo, 800); + } + public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo, long ms) { if (awaitingPlayer || outputEntry == null) { return; } @@ -3258,7 +3469,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg previewView.setVisibility(View.VISIBLE); previewView.set(outputEntry, afterPlayerAwait, seekTo); previewView.setupAudio(outputEntry, false); - AndroidUtilities.runOnUIThread(afterPlayerAwait, 800); + AndroidUtilities.runOnUIThread(afterPlayerAwait, ms); } private AnimatorSet pageAnimator; @@ -3276,7 +3487,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg onNavigateStart(oldPage, page); if (previewButtons != null) { - previewButtons.appear(page == PAGE_PREVIEW && openProgress > 0, animated); + previewButtons.appear(page == PAGE_PREVIEW, animated); } showVideoTimer(page == PAGE_CAMERA && isVideo, animated); if (page != PAGE_PREVIEW) { @@ -3310,9 +3521,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg animators.add(ObjectAnimator.ofFloat(timelineView, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); - ((ViewGroup.MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); + if (themeButton != null) { + animators.add(ObjectAnimator.ofFloat(themeButton, View.ALPHA, page == PAGE_PREVIEW && (outputEntry != null && outputEntry.isRepostMessage) ? 1f : 0)); + } // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(zoomControlView, View.ALPHA, 0)); @@ -3346,9 +3559,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg captionContainer.setAlpha(page == PAGE_PREVIEW ? 1f : 0); captionContainer.setTranslationY(page == PAGE_PREVIEW ? 0 : dp(12)); muteButton.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); - ((ViewGroup.MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); playButton.setAlpha(page == PAGE_PREVIEW && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1f : 0); downloadButton.setAlpha(page == PAGE_PREVIEW ? 1f : 0); + if (themeButton != null) { + themeButton.setAlpha(page == PAGE_PREVIEW && (outputEntry != null && outputEntry.isRepostMessage) ? 1f : 0); + } // privacySelector.setAlpha(page == PAGE_PREVIEW ? 1f : 0); timelineView.setAlpha(page == PAGE_PREVIEW ? 1f : 0); titleTextView.setAlpha(page == PAGE_PREVIEW ? 1f : 0f); @@ -3385,6 +3600,22 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg containerViewBackAnimator.start(); } + private void openThemeSheet() { + if (themeSheet == null) { + themeSheet = new StoryThemeSheet(getContext(), currentAccount, resourcesProvider, () -> { + windowView.removeView(themeSheet); + themeSheet = null; + }) { + @Override + protected void updateWallpaper() { + previewView.setupWallpaper(outputEntry, true); + } + }; + windowView.addView(themeSheet); + } + themeSheet.open(outputEntry); + } + private Parcelable lastGalleryScrollPosition; private MediaController.AlbumEntry lastGallerySelectedAlbum; @@ -3672,6 +3903,12 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg titleTextView.setRightPadding(AndroidUtilities.dp(48)); } downloadButton.setVisibility(View.VISIBLE); + if (outputEntry != null && outputEntry.isRepostMessage) { + getThemeButton().setVisibility(View.VISIBLE); + updateThemeButtonDrawable(false); + } else if (themeButton != null) { + themeButton.setVisibility(View.GONE); + } // privacySelector.setVisibility(View.VISIBLE); previewButtons.setVisibility(View.VISIBLE); previewView.setVisibility(View.VISIBLE); @@ -3680,7 +3917,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg // privacySelector.setStoryPeriod(outputEntry == null || !UserConfig.getInstance(currentAccount).isPremium() ? 86400 : outputEntry.period); captionEdit.setPeriod(outputEntry == null ? 86400 : outputEntry.period, false); - captionEdit.setPeriodVisible(!MessagesController.getInstance(currentAccount).premiumLocked && (outputEntry == null || !outputEntry.isEdit)); + captionEdit.setPeriodVisible(!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && (outputEntry == null || !outputEntry.isEdit)); captionEdit.setHasRoundVideo(outputEntry != null && outputEntry.round != null); setReply(); } @@ -3689,8 +3926,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg previewButtons.setShareText(outputEntry != null && outputEntry.isEdit ? LocaleController.getString("Done", R.string.Done) : LocaleController.getString("Next", R.string.Next)); // privacySelector.set(outputEntry, false); if (!previewAlreadySet) { - previewView.set(outputEntry); - previewView.setupAudio(outputEntry, false); + if (outputEntry != null && outputEntry.isRepostMessage) { + previewView.preset(outputEntry); + } else { + previewView.set(outputEntry); + } } previewAlreadySet = false; captionEdit.editText.getEditText().setOnPremiumMenuLockClickListener(MessagesController.getInstance(currentAccount).storyEntitiesAllowed() ? null : () -> { @@ -3720,6 +3960,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } else { captionEdit.clear(); } + previewButtons.setFiltersVisible(outputEntry == null || !outputEntry.isRepostMessage || outputEntry.isVideo); previewButtons.setShareEnabled(!videoError && !captionEdit.isCaptionOverLimit() && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); muteButton.setImageResource(outputEntry != null && outputEntry.muted ? R.drawable.media_unmute : R.drawable.media_mute); previewView.setVisibility(View.VISIBLE); @@ -3728,6 +3969,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg titleTextView.setTranslationX(0); if (outputEntry != null && outputEntry.isEdit) { titleTextView.setText(LocaleController.getString(R.string.RecorderEditStory)); + } else if (outputEntry != null && outputEntry.isRepostMessage) { + titleTextView.setText(LocaleController.getString(R.string.RecorderRepost)); } else if (outputEntry != null && outputEntry.isRepost) { SpannableStringBuilder title = new SpannableStringBuilder(); AvatarSpan span = new AvatarSpan(titleTextView, currentAccount, 32); @@ -3794,6 +4037,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg muteButton.setVisibility(View.GONE); playButton.setVisibility(View.GONE); downloadButton.setVisibility(View.GONE); + if (themeButton != null) { + themeButton.setVisibility(View.GONE); + } // privacySelector.setVisibility(View.GONE); previewView.setVisibility(View.GONE); timelineView.setVisibility(View.GONE); @@ -3809,6 +4055,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (outputEntry == null || !outputEntry.isRepost) { createPhotoPaintView(); hidePhotoPaintView(); + } + if (outputEntry == null || !outputEntry.isRepost && !outputEntry.isRepostMessage) { createFilterPhotoView(); } if (photoFilterEnhanceView != null) { @@ -3912,6 +4160,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, editMode == EDIT_MODE_NONE && isVideo ? 1 : 0)); animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, editMode == EDIT_MODE_NONE && (isVideo || outputEntry != null && !TextUtils.isEmpty(outputEntry.audioPath)) ? 1 : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); + if (themeButton != null) { + animators.add(ObjectAnimator.ofFloat(themeButton, View.ALPHA, editMode == EDIT_MODE_NONE && (outputEntry != null && outputEntry.isRepostMessage) ? 1f : 0)); + } // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); // animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, currentPage == PAGE_PREVIEW && isVideo && editMode == EDIT_MODE_NONE ? 1f : 0f)); @@ -4032,7 +4283,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg new MediaController.CropState(), null, blurManager, - resourcesProvider + resourcesProvider, + videoTextureHolder ) { @Override public void onEntityDraggedTop(boolean value) { @@ -4055,13 +4307,12 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @Override public void onEntityDragEnd(boolean delete) { + if (!isEntityDeletable()) { + delete = false; + } captionContainer.clearAnimation(); captionContainer.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); - trash.onDragInfo(false, delete); - trash.clearAnimation(); - trash.animate().alpha(0f).withEndAction(() -> { - trash.setVisibility(View.GONE); - }).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).setStartDelay(delete ? 500 : 0).start(); + showTrash(false, delete); if (delete) { removeCurrentEntity(); } @@ -4074,11 +4325,22 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg paintView.showReactionsLayout(false); captionContainer.clearAnimation(); captionContainer.animate().alpha(0f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + showTrash(isEntityDeletable(), false); + } - trash.setVisibility(View.VISIBLE); - trash.setAlpha(0f); - trash.clearAnimation(); - trash.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + public void showTrash(boolean show, boolean delete) { + if (show) { + trash.setVisibility(View.VISIBLE); + trash.setAlpha(0f); + trash.clearAnimation(); + trash.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + } else { + trash.onDragInfo(false, delete); + trash.clearAnimation(); + trash.animate().alpha(0f).withEndAction(() -> { + trash.setVisibility(View.GONE); + }).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).setStartDelay(delete ? 500 : 0).start(); + } } private boolean multitouch; @@ -4087,20 +4349,13 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg public void onEntityDragMultitouchStart() { multitouch = true; paintView.showReactionsLayout(false); - trash.onDragInfo(false, false); - trash.clearAnimation(); - trash.animate().alpha(0f).withEndAction(() -> { - trash.setVisibility(View.GONE); - }).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + showTrash(false, false); } @Override public void onEntityDragMultitouchEnd() { multitouch = false; - trash.setVisibility(View.VISIBLE); - trash.setAlpha(0f); - trash.clearAnimation(); - trash.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + showTrash(isEntityDeletable(), false); previewHighlight.show(false, false, null); } @@ -4142,7 +4397,6 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (outputEntry != null && !isVideo) { boolean appear = !TextUtils.isEmpty(outputEntry.audioPath); playButton.drawable.setPause(!previewView.isPlaying(), false); - ((MarginLayoutParams) playButton.getLayoutParams()).rightMargin = dp(48 + (isVideo ? 48 : 0)); playButton.setVisibility(View.VISIBLE); playButton.animate().alpha(appear ? 1 : 0).withEndAction(() -> { if (!appear) { @@ -4221,6 +4475,51 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + @Override + public void onSwitchSegmentedAnimation(PhotoView photoView) { + if (photoView == null) { + return; + } + ThanosEffect thanosEffect = getThanosEffect(); + if (thanosEffect == null) { + photoView.onSwitchSegmentedAnimationStarted(false); + return; + } + Bitmap bitmap = photoView.getSegmentedOutBitmap(); + if (bitmap == null) { + photoView.onSwitchSegmentedAnimationStarted(false); + return; + } + Matrix matrix = new Matrix(); + float w = photoView.getWidth(), h = photoView.getHeight(); + float tx = 0, ty = 0; + if (photoView.getRotation() != 0) { + final float bw = bitmap.getWidth(); + final float bh = bitmap.getHeight(); + final float r = (float) Math.sqrt((bw / 2f) * (bw / 2f) + (bh / 2f) * (bh / 2f)); + final float d = 2 * r; + Bitmap newBitmap = Bitmap.createBitmap((int) d, (int) d, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(newBitmap); + canvas.save(); + canvas.rotate(photoView.getRotation(), r, r); + canvas.drawBitmap(bitmap, (d - bw) / 2, (d - bh) / 2, null); + bitmap.recycle(); + bitmap = newBitmap; + + final float pd = 2 * (float) Math.sqrt((w / 2f) * (w / 2f) + (h / 2f) * (h / 2f)); + tx = -(pd - w) / 2; + ty = -(pd - h) / 2; + w = pd; + h = pd; + } + matrix.postScale(w, h); + matrix.postScale(photoView.getScaleX(), photoView.getScaleY(), w / 2f, h / 2f); + matrix.postTranslate(containerView.getX() + previewContainer.getX() + photoView.getX() + tx, containerView.getY() + previewContainer.getY() + photoView.getY() + ty); + thanosEffect.animate(matrix, bitmap, () -> { + photoView.onSwitchSegmentedAnimationStarted(true); + }, () -> {}); + } + @Override public void onSelectRound(RoundView roundView) { if (timelineView != null) { @@ -4343,6 +4642,12 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg paintView.clearSelection(); } downloadButton.setVisibility(View.VISIBLE); + if (outputEntry != null && outputEntry.isRepostMessage) { + getThemeButton().setVisibility(View.VISIBLE); + updateThemeButtonDrawable(false); + } else if (themeButton != null) { + themeButton.setVisibility(View.GONE); + } titleTextView.setVisibility(View.VISIBLE); // privacySelector.setVisibility(View.VISIBLE); if (isVideo) { @@ -4388,6 +4693,9 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg muteButton.setVisibility(View.GONE); playButton.setVisibility(View.GONE); downloadButton.setVisibility(View.GONE); + if (themeButton != null) { + themeButton.setVisibility(View.GONE); + } // privacySelector.setVisibility(View.GONE); timelineView.setVisibility(View.GONE); titleTextView.setVisibility(View.GONE); @@ -4400,6 +4708,193 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg photoFilterEnhanceView.setAllowTouch(toMode == EDIT_MODE_FILTER || toMode == EDIT_MODE_NONE); } } + private void applyPaintInBackground(Runnable whenDone) { + final PaintView paintView = this.paintView; + final StoryEntry outputEntry = this.outputEntry; + if (paintView == null || outputEntry == null) { + return; + } + + outputEntry.clearPaint(); + final boolean hasChanges = paintView.hasChanges(); + final boolean hasBlur = paintView.hasBlur(); + final int resultWidth = outputEntry.resultWidth; + final int resultHeight = outputEntry.resultHeight; + Utilities.searchQueue.postRunnable(() -> { + + ArrayList mediaEntities = new ArrayList<>(); + + paintView.getBitmap(mediaEntities, resultWidth, resultHeight, false, false, false, false, outputEntry); + if (!outputEntry.isVideo) { + outputEntry.averageDuration = Utilities.clamp(paintView.getLcm(), 7500L, 5000L); + } + List masks = paintView.getMasks(); + final List stickers = masks != null ? new ArrayList<>(masks) : null; + final boolean isVideo = outputEntry.isVideo; + final boolean wouldBeVideo = outputEntry.wouldBeVideo(); + + mediaEntities.clear(); + Bitmap bitmap = paintView.getBitmap(mediaEntities, resultWidth, resultHeight, true, false, false, !isVideo, outputEntry); + if (mediaEntities.isEmpty()) { + mediaEntities = null; + } + + final File paintFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101), true); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + + final File backgroundFile; + if (outputEntry.isRepostMessage && outputEntry.backgroundWallpaperPeerId != Long.MIN_VALUE) { + Drawable drawable = outputEntry.backgroundDrawable; + if (drawable == null) { + drawable = PreviewView.getBackgroundDrawable(null, currentAccount, outputEntry.backgroundWallpaperPeerId, isDark); + } + if (drawable != null) { + backgroundFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + bitmap = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ARGB_8888); + StoryEntry.drawBackgroundDrawable(new Canvas(bitmap), drawable, bitmap.getWidth(), bitmap.getHeight()); + try { + bitmap.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(backgroundFile)); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + } + } else { + backgroundFile = null; + } + } else { + backgroundFile = null; + } + File messageVideoMaskFile = null; + if (outputEntry.isRepostMessage && outputEntry.isVideo) { + int videoWidth = outputEntry.width; + int videoHeight = outputEntry.height; + MessageEntityView messageEntityView = paintView.findMessageView(); + ImageReceiver photoImage = null; + if (messageEntityView != null && messageEntityView.listView.getChildCount() == 1 && videoWidth > 0 && videoHeight > 0) { + View child = messageEntityView.listView.getChildAt(0); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) messageEntityView.listView.getChildAt(0); + photoImage = cell.getPhotoImage(); + } + } + if (photoImage != null && (int) photoImage.getImageWidth() > 0 && (int) photoImage.getImageHeight() > 0) { + float scale = Math.max(photoImage.getImageWidth() / videoWidth, photoImage.getImageHeight() / videoHeight); + final float S = 2f; + int w = (int) (videoWidth * scale / S), h = (int) (videoHeight * scale / S); + Bitmap maskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + float[] radii = new float[8]; + for (int a = 0; a < photoImage.getRoundRadius().length; a++) { + radii[a * 2] = photoImage.getRoundRadius()[a]; + radii[a * 2 + 1] = photoImage.getRoundRadius()[a]; + } + Canvas canvas = new Canvas(maskBitmap); + Path path = new Path(); + canvas.scale(1f / S, 1f / S); + AndroidUtilities.rectTmp.set( + w * S / 2f - photoImage.getImageWidth() / 2f, + h * S / 2f - photoImage.getImageHeight() / 2f, + w * S / 2f + photoImage.getImageWidth() / 2f, + h * S / 2f + photoImage.getImageHeight() / 2f + ); + path.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + canvas.drawPath(path, paint); + try { + messageVideoMaskFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + maskBitmap.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(messageVideoMaskFile)); + } catch (Exception e) { + FileLog.e(e); + messageVideoMaskFile = null; + } + maskBitmap.recycle(); + } + } + final File finalMessageVideoMaskFile = messageVideoMaskFile; + + final File paintEntitiesFile; + if (!wouldBeVideo) { + bitmap = paintView.getBitmap(new ArrayList<>(), resultWidth, resultHeight, false, true, false, false, outputEntry); + paintEntitiesFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, resultWidth, resultHeight, 87, false, 101, 101), true); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + } else { + paintEntitiesFile = null; + } + + final File paintBlurFile; + if (hasBlur) { + bitmap = paintView.getBlurBitmap(); + paintBlurFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, resultWidth, resultHeight, 87, false, 101, 101), true); + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + } else { + paintBlurFile = null; + } + + final ArrayList finalMediaEntities = mediaEntities; + AndroidUtilities.runOnUIThread(() -> { + try { + if (outputEntry.paintFile != null) { + outputEntry.paintFile.delete(); + } + } catch (Exception ignore) {} + try { + if (outputEntry.paintEntitiesFile != null) { + outputEntry.paintEntitiesFile.delete(); + } + } catch (Exception ignore) {} + try { + if (outputEntry.paintBlurFile != null) { + outputEntry.paintBlurFile.delete(); + } + } catch (Exception ignore) {} + outputEntry.paintFile = null; + outputEntry.paintEntitiesFile = null; + outputEntry.paintBlurFile = null; + if (outputEntry.backgroundFile != null) { + try { + outputEntry.backgroundFile.delete(); + } catch (Exception e) { + FileLog.e(e); + } + outputEntry.backgroundFile = null; + } + if (outputEntry.messageVideoMaskFile != null) { + try { + outputEntry.messageVideoMaskFile.delete(); + } catch (Exception e) { + FileLog.e(e); + } + outputEntry.messageVideoMaskFile = null; + } + + outputEntry.editedMedia |= hasChanges; + outputEntry.mediaEntities = finalMediaEntities; + outputEntry.paintFile = paintFile; + outputEntry.backgroundFile = backgroundFile; + outputEntry.paintEntitiesFile = paintEntitiesFile; + outputEntry.messageVideoMaskFile = finalMessageVideoMaskFile; + outputEntry.paintBlurFile = paintBlurFile; + outputEntry.stickers = stickers; + + if (whenDone != null) { + whenDone.run(); + } + }); + }); + } private void applyPaint() { if (paintView == null || outputEntry == null) { @@ -4414,7 +4909,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } else { outputEntry.mediaEntities.clear(); } - paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false, outputEntry); + paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false, false, outputEntry); if (!outputEntry.isVideo) { outputEntry.averageDuration = Utilities.clamp(paintView.getLcm(), 7500L, 5000L); } @@ -4424,7 +4919,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg final boolean wouldBeVideo = outputEntry.wouldBeVideo(); outputEntry.mediaEntities = new ArrayList<>(); - Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, !isVideo, outputEntry); + Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, false, !isVideo, outputEntry); if (outputEntry.mediaEntities.isEmpty()) { outputEntry.mediaEntities = null; } @@ -4454,8 +4949,94 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } bitmap = null; + if (outputEntry.isRepostMessage) { + if (outputEntry.backgroundFile != null) { + try { + outputEntry.backgroundFile.delete(); + } catch (Exception e) { + FileLog.e(e); + } + outputEntry.backgroundFile = null; + } + if (outputEntry.backgroundWallpaperPeerId != Long.MIN_VALUE) { + Drawable drawable = outputEntry.backgroundDrawable; + if (drawable == null) { + drawable = PreviewView.getBackgroundDrawable(null, currentAccount, outputEntry.backgroundWallpaperPeerId, isDark); + } + if (drawable != null) { + outputEntry.backgroundFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + bitmap = Bitmap.createBitmap(outputEntry.resultWidth, outputEntry.resultHeight, Bitmap.Config.ARGB_8888); + StoryEntry.drawBackgroundDrawable(new Canvas(bitmap), drawable, bitmap.getWidth(), bitmap.getHeight()); + try { + bitmap.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(outputEntry.backgroundFile)); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + } + } + } + } + if (outputEntry.isRepostMessage) { + if (outputEntry.messageVideoMaskFile != null) { + try { + outputEntry.messageVideoMaskFile.delete(); + } catch (Exception e) { + FileLog.e(e); + } + outputEntry.messageVideoMaskFile = null; + } + if (outputEntry.isRepostMessage && outputEntry.isVideo) { + int videoWidth = outputEntry.width; + int videoHeight = outputEntry.height; + MessageEntityView messageEntityView = paintView.findMessageView(); + if (messageEntityView != null && messageEntityView.listView.getChildCount() == 1 && videoWidth > 0 && videoHeight > 0) { + View child = messageEntityView.listView.getChildAt(0); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) messageEntityView.listView.getChildAt(0); + ImageReceiver photoImage = cell.getPhotoImage(); + if (photoImage != null && (int) photoImage.getImageWidth() > 0 && (int) photoImage.getImageHeight() > 0) { + float scale = Math.max(photoImage.getImageWidth() / videoWidth, photoImage.getImageHeight() / videoHeight); + final float S = 2f; + int w = (int) (videoWidth * scale / S), h = (int) (videoHeight * scale / S); + Bitmap maskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + float[] radii = new float[8]; + for (int a = 0; a < photoImage.getRoundRadius().length; a++) { + radii[a * 2] = photoImage.getRoundRadius()[a]; + radii[a * 2 + 1] = photoImage.getRoundRadius()[a]; + } + Canvas canvas = new Canvas(maskBitmap); + Path path = new Path(); + canvas.scale(1f / S, 1f / S); + AndroidUtilities.rectTmp.set( + w * S / 2f - photoImage.getImageWidth() / 2f, + h * S / 2f - photoImage.getImageHeight() / 2f, + w * S / 2f + photoImage.getImageWidth() / 2f, + h * S / 2f + photoImage.getImageHeight() / 2f + ); + path.addRoundRect(AndroidUtilities.rectTmp, radii, Path.Direction.CW); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + canvas.drawPath(path, paint); + try { + outputEntry.messageVideoMaskFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + maskBitmap.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(outputEntry.messageVideoMaskFile)); + } catch (Exception e) { + FileLog.e(e); + outputEntry.messageVideoMaskFile = null; + } + maskBitmap.recycle(); + } + } + } + } + } + if (!wouldBeVideo) { - bitmap = paintView.getBitmap(new ArrayList<>(), outputEntry.resultWidth, outputEntry.resultHeight, false, true, false, outputEntry); + bitmap = paintView.getBitmap(new ArrayList<>(), outputEntry.resultWidth, outputEntry.resultHeight, false, true, false, false, outputEntry); outputEntry.paintEntitiesFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101), true); if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); @@ -4473,6 +5054,42 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } + // separated to run on main thread (chatmessagecell uses global paints and resources) + private void applyPaintMessage() { + if (paintView == null || outputEntry == null) { + return; + } + + if (outputEntry.isRepostMessage) { + if (outputEntry.messageFile != null) { + try { + outputEntry.messageFile.delete(); + } catch (Exception e) { + FileLog.e(e); + } + outputEntry.messageFile = null; + } + outputEntry.messageFile = StoryEntry.makeCacheFile(currentAccount, "webp"); + Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, true, !isVideo, outputEntry); + try { + bitmap.compress(Bitmap.CompressFormat.WEBP, 100, new FileOutputStream(outputEntry.messageFile)); + } catch (Exception e) { + FileLog.e(e); + try { + outputEntry.messageFile.delete(); + } catch (Exception e2) { + FileLog.e(e2); + } + outputEntry.messageFile = null; + } finally { + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + } + bitmap = null; + } + } + } + private void applyFilter(Runnable whenDone) { if (photoFilterView == null || outputEntry == null) { if (whenDone != null) { @@ -4809,6 +5426,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg showSavedDraftHint = !outputEntry.isDraft; applyFilter(null); applyPaint(); + applyPaintMessage(); destroyPhotoFilterView(); StoryEntry storyEntry = outputEntry; storyEntry.destroy(true); @@ -4825,11 +5443,11 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }); } builder.setPositiveButton(outputEntry != null && outputEntry.isDraft && !outputEntry.isEdit ? LocaleController.getString("StoryDeleteDraft") : LocaleController.getString("Discard", R.string.Discard), (dialogInterface, i) -> { - if (outputEntry != null && !(outputEntry.isEdit || outputEntry.isRepost) && outputEntry.isDraft) { + if (outputEntry != null && !(outputEntry.isEdit || outputEntry.isRepost && !outputEntry.isRepostMessage) && outputEntry.isDraft) { MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().delete(outputEntry); outputEntry = null; } - if (outputEntry != null && (outputEntry.isEdit || outputEntry.isRepost)) { + if (outputEntry != null && (outputEntry.isEdit || outputEntry.isRepost && !outputEntry.isRepostMessage)) { close(true); } else { navigateTo(PAGE_CAMERA, true); @@ -5332,4 +5950,195 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return cameraStr; } + + public ThanosEffect getThanosEffect() { + if (!ThanosEffect.supports()) { + return null; + } + if (thanosEffect == null) { + windowView.addView(thanosEffect = new ThanosEffect(getContext(), () -> { + ThanosEffect thisThanosEffect = thanosEffect; + if (thisThanosEffect != null) { + thanosEffect = null; + windowView.removeView(thisThanosEffect); + } + })); + } + return thanosEffect; + } + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + public ImageView getThemeButton() { + if (themeButton == null) { + themeButtonDrawable = new RLottieDrawable(R.raw.sun_outline, "" + R.raw.sun_outline, dp(28), dp(28), true, null); + themeButtonDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (!(outputEntry != null && outputEntry.isDark)) { + themeButtonDrawable.setCustomEndFrame(0); + themeButtonDrawable.setCurrentFrame(0); + } else { + themeButtonDrawable.setCurrentFrame(35); + themeButtonDrawable.setCustomEndFrame(36); + } + themeButtonDrawable.beginApplyLayerColors(); + int color = Theme.getColor(Theme.key_chats_menuName, resourcesProvider); + themeButtonDrawable.setLayerColor("Sunny.**", color); + themeButtonDrawable.setLayerColor("Path 6.**", color); + themeButtonDrawable.setLayerColor("Path.**", color); + themeButtonDrawable.setLayerColor("Path 5.**", color); + themeButtonDrawable.commitApplyLayerColors(); + themeButton = new ImageView(getContext()); + themeButton.setScaleType(ImageView.ScaleType.CENTER); + themeButton.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); + themeButton.setBackground(Theme.createSelectorDrawable(0x20ffffff)); + themeButton.setOnClickListener(e -> { + toggleTheme(); + }); +// themeButton.setOnLongClickListener(e -> { +// openThemeSheet(); +// return true; +// }); + themeButton.setVisibility(View.GONE); + themeButton.setImageDrawable(themeButtonDrawable); + themeButton.setAlpha(0f); + actionBarButtons.addView(themeButton, 0, LayoutHelper.createLinear(46, 56, Gravity.TOP | Gravity.RIGHT)); + } + return themeButton; + } + + public void updateThemeButtonDrawable(boolean animated) { + if (themeButtonDrawable != null) { + if (animated) { + themeButtonDrawable.setCustomEndFrame(outputEntry != null && outputEntry.isDark ? themeButtonDrawable.getFramesCount() : 0); + if (themeButtonDrawable != null) { + themeButtonDrawable.start(); + } + } else { + int frame = outputEntry != null && outputEntry.isDark ? themeButtonDrawable.getFramesCount() - 1 : 0; + themeButtonDrawable.setCurrentFrame(frame, false, true); + themeButtonDrawable.setCustomEndFrame(frame); + if (themeButton != null) { + themeButton.invalidate(); + } + } + } + } + + public void toggleTheme() { + if (outputEntry == null || changeDayNightView != null || themeButton == null || changeDayNightViewAnimator != null && changeDayNightViewAnimator.isRunning()) { + return; + } + final boolean isDark = outputEntry.isDark; + + Bitmap bitmap = Bitmap.createBitmap(windowView.getWidth(), windowView.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + themeButton.setAlpha(0f); + if (previewView != null) { + previewView.drawForThemeToggle = true; + } + if (paintView != null) { + paintView.drawForThemeToggle = true; + } + windowView.draw(bitmapCanvas); + if (previewView != null) { + previewView.drawForThemeToggle = false; + } + if (paintView != null) { + paintView.drawForThemeToggle = false; + } + themeButton.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + themeButton.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + themeButton.getMeasuredWidth() / 2f; + float cy = y + themeButton.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isDark) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + themeButton.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + if (changeDayNightView != null) { + changeDayNightView.invalidate(); + } + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setStartDelay(80); + changeDayNightViewAnimator.setDuration(isDark ? 320 : 450); + changeDayNightViewAnimator.setInterpolator(isDark ? CubicBezierInterpolator.EASE_IN : CubicBezierInterpolator.EASE_OUT_QUINT); + changeDayNightViewAnimator.start(); + + windowView.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + if (outputEntry == null) { + return; + } + outputEntry.isDark = !outputEntry.isDark; + if (previewView != null) { + previewView.setupWallpaper(outputEntry, false); + } + if (paintView != null && paintView.entitiesView != null) { + for (int i = 0; i < paintView.entitiesView.getChildCount(); ++i) { + View child = paintView.entitiesView.getChildAt(i); + if (child instanceof MessageEntityView) { + ((MessageEntityView) child).setupTheme(outputEntry); + } + } + } + updateThemeButtonDrawable(true); + }); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryThemeSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryThemeSheet.java new file mode 100644 index 000000000..4c2a95c05 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryThemeSheet.java @@ -0,0 +1,154 @@ +package org.telegram.ui.Stories.recorder; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatThemeController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChannelColorActivity; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; + +public class StoryThemeSheet extends FrameLayout { + + private final ImageView backButtonView; + private final BackDrawable backButtonDrawable; + + private final TextView titleView; + + private final ChannelColorActivity.ThemeChooser themeView; + + private final Theme.ResourcesProvider resourcesProvider; + private final Runnable whenDie; + + public StoryThemeSheet(Context context, int currentAccount, Theme.ResourcesProvider resourcesProvider, Runnable whenDie) { + super(context); + this.resourcesProvider = resourcesProvider; + this.whenDie = whenDie; + + setBackground(Theme.createRoundRectDrawable(dp(14),0, Theme.getColor(Theme.key_dialogBackground, resourcesProvider))); + + backButtonView = new ImageView(getContext()); + int padding = dp(10); + backButtonView.setPadding(padding, padding, padding, padding); + backButtonView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP)); + backButtonDrawable = new BackDrawable(true); + backButtonView.setImageDrawable(backButtonDrawable); + backButtonView.setOnClickListener(v -> { + dismiss(); + }); + addView(backButtonView, LayoutHelper.createFrame(44, 44, Gravity.TOP | Gravity.LEFT, 7, 8, 0, 0)); + + titleView = new TextView(context); + titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setText(LocaleController.getString(R.string.StorySetWallpaper)); + addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 54, 16, 24, 0)); + + themeView = new ChannelColorActivity.ThemeChooser(context, false, currentAccount, resourcesProvider) { + @Override + public boolean isDark() { + return currentEntry != null ? currentEntry.isDark : super.isDark(); + } + }; + themeView.setOnEmoticonSelected(emoticon -> { + if (currentEntry != null && !TextUtils.equals(currentEntry.backgroundWallpaperEmoticon, emoticon)) { + currentEntry.backgroundWallpaperEmoticon = emoticon; + updateWallpaper(); + } + }); + addView(themeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 56, 0, 0)); + + } + + public void updateColors() { + themeView.updateColors(); + } + + protected void updateWallpaper() { + + } + + private boolean openWhenMeasured; + private StoryEntry currentEntry; + + public void open(StoryEntry entry) { + if (currentEntry != entry) { + currentEntry = entry; + themeView.updateColors(); + } + currentEntry = entry; + if (getMeasuredHeight() == 0) { + openWhenMeasured = true; + return; + } + + if (entry != null) { + TLRPC.WallPaper wallpaper = null; + if (entry.backgroundWallpaperPeerId != Long.MIN_VALUE) { + if (entry.backgroundWallpaperPeerId < 0) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(entry.currentAccount).getChatFull(-entry.backgroundWallpaperPeerId); + if (chatFull != null) { + wallpaper = chatFull.wallpaper; + } + } else { + TLRPC.UserFull userFull = MessagesController.getInstance(entry.currentAccount).getUserFull(entry.backgroundWallpaperPeerId); + if (userFull != null) { + wallpaper = userFull.wallpaper; + } + } + } + themeView.setGalleryWallpaper(wallpaper); + if (entry.backgroundWallpaperEmoticon != null) { + themeView.setSelectedEmoticon(entry.backgroundWallpaperEmoticon, false); + } else if (!TextUtils.isEmpty(ChatThemeController.getWallpaperEmoticon(wallpaper))) { + themeView.setSelectedEmoticon(ChatThemeController.getWallpaperEmoticon(wallpaper), false); + } else { + themeView.setSelectedEmoticon(null, false); + } + } else { + themeView.setGalleryWallpaper(null); + themeView.setSelectedEmoticon(null, false); + } + + setTranslationY(getMeasuredHeight()); + animate().translationY(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + isOpen = true; + } + + public boolean isOpen; + + public void dismiss() { + animate().translationY(getMeasuredHeight()).withEndAction(() -> { + if (whenDie != null) { + whenDie.run(); + } else { + setVisibility(GONE); + } + }).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + isOpen = false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(235) + AndroidUtilities.navigationBarHeight, MeasureSpec.EXACTLY)); + if (openWhenMeasured) { + openWhenMeasured = false; + open(currentEntry); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java index 8c138ccce..25a1ff8fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java @@ -89,6 +89,7 @@ public class TimelineView extends View { private long scroll; private boolean hasVideo; + private boolean isMainVideoRound; private String videoPath; private long videoDuration; private float videoLeft; @@ -313,7 +314,7 @@ public class TimelineView extends View { this.delegate = delegate; } - public void setVideo(String videoPath, long videoDuration, float videoVolume) { + public void setVideo(boolean isRound, String videoPath, long videoDuration, float videoVolume) { if (TextUtils.equals(this.videoPath, videoPath)) { return; } @@ -321,6 +322,7 @@ public class TimelineView extends View { thumbs.destroy(); thumbs = null; } + isMainVideoRound = isRound; if (videoPath != null) { scroll = 0; this.videoPath = videoPath; @@ -402,7 +404,7 @@ public class TimelineView extends View { if (getMeasuredWidth() <= 0 || this.thumbs != null) { return; } - this.thumbs = new VideoThumbsLoader(videoPath, w - px - px, dp(38), videoDuration > 2 ? videoDuration : null); + this.thumbs = new VideoThumbsLoader(isMainVideoRound, videoPath, w - px - px, dp(38), videoDuration > 2 ? videoDuration : null); if (this.thumbs.getDuration() > 0) { videoDuration = this.thumbs.getDuration(); } @@ -413,7 +415,7 @@ public class TimelineView extends View { if (getMeasuredWidth() <= 0 || this.roundThumbs != null || hasVideo && videoDuration < 1) { return; } - this.roundThumbs = new VideoThumbsLoader(roundPath, w - px - px, dp(38), roundDuration > 2 ? roundDuration : null, hasVideo ? videoDuration : MAX_SCROLL_DURATION); + this.roundThumbs = new VideoThumbsLoader(false, roundPath, w - px - px, dp(38), roundDuration > 2 ? roundDuration : null, hasVideo ? videoDuration : MAX_SCROLL_DURATION); if (this.roundThumbs.getDuration() > 0) { roundDuration = this.roundThumbs.getDuration(); } @@ -1403,7 +1405,7 @@ public class TimelineView extends View { final int y = (int) videoBounds.top; boolean allLoaded = thumbs.frames.size() >= toFrame; - boolean fullyCovered = allLoaded; + boolean fullyCovered = allLoaded && !isMainVideoRound; if (fullyCovered) { for (int i = fromFrame; i < Math.min(thumbs.frames.size(), toFrame); ++i) { VideoThumbsLoader.BitmapFrame frame = thumbs.frames.get(i); @@ -1856,14 +1858,16 @@ public class TimelineView extends View { private final int frameWidth; private final int frameHeight; + private final boolean isRound; private boolean destroyed; - public VideoThumbsLoader(String path, int uiWidth, int uiHeight, Long overrideDuration) { - this(path, uiWidth, uiHeight, overrideDuration, MAX_SCROLL_DURATION); + public VideoThumbsLoader(boolean isRound, String path, int uiWidth, int uiHeight, Long overrideDuration) { + this(isRound, path, uiWidth, uiHeight, overrideDuration, MAX_SCROLL_DURATION); } - public VideoThumbsLoader(String path, int uiWidth, int uiHeight, Long overrideDuration, long maxDuration) { + public VideoThumbsLoader(boolean isRound, String path, int uiWidth, int uiHeight, Long overrideDuration, long maxDuration) { + this.isRound = isRound; metadataRetriever = new MediaMetadataRetriever(); long duration = MAX_SCROLL_DURATION; int width = 0; @@ -1952,6 +1956,7 @@ public class TimelineView extends View { private final Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + private Path clipPath; private void retrieveFrame() { if (metadataRetriever == null) { return; @@ -1971,6 +1976,14 @@ public class TimelineView extends View { (int) ((scaledBitmap.getWidth() + bitmap.getWidth() * scale) / 2f), (int) ((scaledBitmap.getHeight() + bitmap.getHeight() * scale) / 2f) ); + if (isRound) { + if (clipPath == null) { + clipPath = new Path(); + } + clipPath.rewind(); + clipPath.addCircle(frameWidth / 2f, frameHeight / 2f, Math.min(frameWidth, frameHeight) / 2f, Path.Direction.CW); + canvas.clipPath(clipPath); + } canvas.drawBitmap(bitmap, src, dest, bitmapPaint); bitmap.recycle(); bitmap = scaledBitmap; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index 1f9e60c88..a71957aa0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -2192,7 +2192,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No view = new AppIconsSelectorCell(mContext, ThemeActivity.this, currentAccount); break; case TYPE_CHOOSE_COLOR: - view = new PeerColorActivity.ChangeNameColorCell(currentAccount, false, mContext, getResourceProvider()); + view = new PeerColorActivity.ChangeNameColorCell(currentAccount, 0, mContext, getResourceProvider()); break; } return new RecyclerListView.Holder(view); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index ede8d96a5..34a725026 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -19,7 +19,6 @@ import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; -import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; @@ -49,13 +48,12 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; +import android.os.Bundle; import android.os.SystemClock; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; -import android.util.Log; import android.util.SparseIntArray; import android.util.StateSet; import android.util.TypedValue; @@ -84,6 +82,7 @@ import androidx.viewpager.widget.ViewPager; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.DownloadController; import org.telegram.messenger.Emoji; @@ -110,17 +109,16 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.MenuDrawable; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Cells.BrightnessControlCell; import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.DialogCell; @@ -128,21 +126,22 @@ import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.PatternCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.ColorPicker; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; import org.telegram.ui.Components.GestureDetector2; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MotionBackgroundDrawable; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RLottieDrawable; -import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SeekBarView; @@ -151,6 +150,7 @@ import org.telegram.ui.Components.Text; import org.telegram.ui.Components.UndoView; import org.telegram.ui.Components.WallpaperCheckBoxView; import org.telegram.ui.Components.WallpaperParallaxEffect; +import org.telegram.ui.Stories.recorder.PreviewView; import org.telegram.ui.Stories.recorder.SliderView; import java.io.File; @@ -163,7 +163,15 @@ import java.util.List; public class ThemePreviewActivity extends BaseFragment implements DownloadController.FileDownloadProgressListener, NotificationCenter.NotificationCenterDelegate { - public final ThemeDelegate themeDelegate = new ThemeDelegate(); + public final ThemeDelegate themeDelegate = new ThemeDelegate() { + @Override + public boolean isDark() { + if (onSwitchDayNightDelegate != null) { + return onSwitchDayNightDelegate.isDark(); + } + return super.isDark(); + } + }; @Override public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { @@ -302,6 +310,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private float dimAmount = 0f; private float progressToDarkTheme; DayNightSwitchDelegate onSwitchDayNightDelegate; + private ColoredImageSpan lockSpan; private AnimatorSet patternViewAnimation; @@ -343,8 +352,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private boolean shouldShowBrightnessControll; private RLottieDrawable sunDrawable; private ActionBarMenuItem dayNightItem; - private float changeDayNightViewProgress; - private ValueAnimator changeDayNightViewAnimator; + private ValueAnimator changeDayNightViewAnimator2; private FrameLayout dimmingSliderContainer; private SliderView dimmingSlider; @@ -399,6 +407,21 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } }); + private boolean checkingBoostsLevel = false, checkedBoostsLevel = false; + public TL_stories.TL_premium_boostsStatus boostsStatus; + private void checkBoostsLevel() { + if (dialogId >= 0 || checkingBoostsLevel || checkedBoostsLevel || boostsStatus != null) { + return; + } + checkingBoostsLevel = true; + getMessagesController().getBoostsController().getBoostsStats(dialogId, boostsStatus -> { + this.boostsStatus = boostsStatus; + checkedBoostsLevel = true; + updateApplyButton1(true); + checkingBoostsLevel = false; + }); + } + float maxScrollOffset; float currentScrollOffset; float defaultScrollOffset; @@ -465,6 +488,11 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro return forceDark; } + @Override + public boolean supportsAnimation() { + return true; + } + @Override public void switchDayNight(boolean animated) { forceDark = !forceDark; @@ -490,7 +518,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } public interface WallpaperActivityDelegate { - void didSetNewBackground(); + void didSetNewBackground(TLRPC.WallPaper wallpaper); } public ThemePreviewActivity(Object wallPaper, Bitmap bitmap) { @@ -761,7 +789,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView2.getLayoutParams(); layoutParams.topMargin = actionBarHeight; if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); } listView2.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize - layoutParams.bottomMargin, MeasureSpec.EXACTLY)); @@ -781,7 +809,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro if (bottomOverlayChat != null) { bottomOverlayChat.setPadding(dp(12), dp(12), dp(12), dp(12) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); layoutParams = (FrameLayout.LayoutParams) bottomOverlayChat.getLayoutParams(); - layoutParams.height = dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); + layoutParams.height = dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); measureChildWithMargins(bottomOverlayChat, widthMeasureSpec, 0, heightMeasureSpec, 0); } if (sheetDrawable != null) { @@ -929,47 +957,51 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro SharedConfig.increaseDayNightWallpaperSiwtchHint(); } boolean isDark = onSwitchDayNightDelegate.isDark(); - sunDrawable.setPlayInDirectionOfCustomEndFrame(true); - if (isDark) { - sunDrawable.setCustomEndFrame(0); - } else { - sunDrawable.setCustomEndFrame(36); - } - sunDrawable.start(); if (onSwitchDayNightDelegate != null) { - onSwitchDayNightDelegate.switchDayNight(true); - } - if (shouldShowBrightnessControll) { - if (onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { - dimmingSlider.setVisibility(View.VISIBLE); - dimmingSlider.animateValueTo(dimAmount); + if (!onSwitchDayNightDelegate.supportsAnimation()) { + toggleTheme(); } else { - dimmingSlider.animateValueTo(0); - } - if (changeDayNightViewAnimator != null) { - changeDayNightViewAnimator.removeAllListeners(); - changeDayNightViewAnimator.cancel(); - } - changeDayNightViewAnimator = ValueAnimator.ofFloat(progressToDarkTheme, onSwitchDayNightDelegate.isDark() ? 1 : 0); - changeDayNightViewAnimator.addUpdateListener(animation -> { - progressToDarkTheme = (float) animation.getAnimatedValue(); - backgroundImage.invalidate(); - bottomOverlayChat.invalidate(); - dimmingSlider.setAlpha(progressToDarkTheme); - dimmingSliderContainer.invalidate(); - invalidateBlur(); - }); - changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (!onSwitchDayNightDelegate.isDark()) { - dimmingSlider.setVisibility(View.GONE); - } + onSwitchDayNightDelegate.switchDayNight(true); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (isDark) { + sunDrawable.setCustomEndFrame(0); + } else { + sunDrawable.setCustomEndFrame(36); } - }); - changeDayNightViewAnimator.setDuration(250); - changeDayNightViewAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - changeDayNightViewAnimator.start(); + sunDrawable.start(); + if (shouldShowBrightnessControll) { + if (onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { + dimmingSlider.setVisibility(View.VISIBLE); + dimmingSlider.animateValueTo(dimAmount); + } else { + dimmingSlider.animateValueTo(0); + } + if (changeDayNightViewAnimator2 != null) { + changeDayNightViewAnimator2.removeAllListeners(); + changeDayNightViewAnimator2.cancel(); + } + changeDayNightViewAnimator2 = ValueAnimator.ofFloat(progressToDarkTheme, onSwitchDayNightDelegate.isDark() ? 1 : 0); + changeDayNightViewAnimator2.addUpdateListener(animation -> { + progressToDarkTheme = (float) animation.getAnimatedValue(); + backgroundImage.invalidate(); + bottomOverlayChat.invalidate(); + dimmingSlider.setAlpha(progressToDarkTheme); + dimmingSliderContainer.invalidate(); + invalidateBlur(); + }); + changeDayNightViewAnimator2.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!onSwitchDayNightDelegate.isDark()) { + dimmingSlider.setVisibility(View.GONE); + } + } + }); + changeDayNightViewAnimator2.setDuration(250); + changeDayNightViewAnimator2.setInterpolator(CubicBezierInterpolator.DEFAULT); + changeDayNightViewAnimator2.start(); + } + } } } else if (id == OPTION_PHOTO_EDIT) { if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { @@ -1319,7 +1351,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro listView2.setVerticalScrollBarEnabled(true); listView2.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); } else if (screenType == SCREEN_TYPE_ACCENT_COLOR) { listView2.setPadding(0, dp(4), 0, dp(16)); } else { @@ -1451,14 +1483,10 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro applyButton1 = new BlurButton(context); ScaleStateListAnimator.apply(applyButton1, 0.033f, 1.2f); - if (dialogId != 0) { - applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaperForMe)); - } else { - applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaper)); - } + updateApplyButton1(false); applyButton1.setOnClickListener(view -> applyWallpaperBackground(false)); - if (dialogId != 0 && !self && serverWallpaper == null) { + if (dialogId > 0 && !self && serverWallpaper == null) { applyButton2 = new BlurButton(context); ScaleStateListAnimator.apply(applyButton2, 0.033f, 1.2f); TLRPC.User user = getMessagesController().getUser(dialogId); @@ -1550,7 +1578,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize(dp(14)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - { + if (!(currentWallpaper instanceof WallpapersListActivity.EmojiWallpaper)) { int textsCount; if (screenType == SCREEN_TYPE_ACCENT_COLOR || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { textsCount = 3; @@ -2398,11 +2426,78 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro invalidateBlur(); } + private void updateApplyButton1(boolean animated) { + if (dialogId > 0) { + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaperForMe)); + } else if (dialogId < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat != null) { + applyButton1.setText(LocaleController.formatString(R.string.ApplyWallpaperForChannel, chat.title)); + if (boostsStatus != null && boostsStatus.level < getMessagesController().channelCustomWallpaperLevelMin) { + SpannableStringBuilder text = new SpannableStringBuilder("l"); + if (lockSpan == null) { + lockSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); + lockSpan.setTopOffset(1); + } + text.setSpan(lockSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.append(" ").append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", getMessagesController().channelCustomWallpaperLevelMin)); + applyButton1.setSubText(text, animated); + } else if (boostsStatus == null) { + checkBoostsLevel(); + } + } else { + applyButton1.setText(LocaleController.formatString(R.string.ApplyWallpaperForChannel, LocaleController.getString(R.string.AccDescrChannel).toLowerCase())); + } + } else { + applyButton1.setText(LocaleController.getString(R.string.ApplyWallpaper)); + } + } + private void applyWallpaperBackground(boolean forBoth) { + if (dialogId < 0) { + if (boostsStatus != null && boostsStatus.level < getMessagesController().channelCustomWallpaperLevelMin) { + getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { + if (getContext() == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), LimitReachedBottomSheet.TYPE_BOOSTS_FOR_CUSTOM_WALLPAPER, currentAccount, getResourceProvider()); + limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + if (!insideBottomSheet()) { + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + } + ; + StatisticActivity fragment = new StatisticActivity(args); + presentFragment(fragment); + }); + } + showDialog(limitReachedBottomSheet); + }); + return; + } else if (boostsStatus == null) { + return; + } + } if (!getUserConfig().isPremium() && forBoth) { showDialog(new PremiumFeatureBottomSheet(this, PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER, true)); return; } + if (currentWallpaper instanceof WallpapersListActivity.EmojiWallpaper) { + if (delegate != null) { + delegate.didSetNewBackground(null); + } + finishFragment(); + return; + } boolean done; boolean sameFile = false; @@ -2559,9 +2654,10 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro int gradientColor3 = 0; File path = null; + TLRPC.WallPaper tlwallPaper = null; if (currentWallpaper instanceof TLRPC.TL_wallPaper) { - TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; - slug = wallPaper.slug; + tlwallPaper = (TLRPC.TL_wallPaper) currentWallpaper; + slug = tlwallPaper.slug; } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; if (Theme.DEFAULT_BACKGROUND_SLUG.equals(wallPaper.slug)) { @@ -2648,12 +2744,12 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro needFinishFragment = false; if (path != null && getMessagesController().uploadingWallpaperInfo == wallpaperInfo) { - TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); - wallPaper.settings = new TLRPC.TL_wallPaperSettings(); - wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); - wallPaper.settings.blur = wallpaperInfo.isBlurred; - wallPaper.settings.motion = wallpaperInfo.isMotion; - wallPaper.uploadingImage = path.getAbsolutePath(); + tlwallPaper = new TLRPC.TL_wallPaper(); + tlwallPaper.settings = new TLRPC.TL_wallPaperSettings(); + tlwallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); + tlwallPaper.settings.blur = wallpaperInfo.isBlurred; + tlwallPaper.settings.motion = wallpaperInfo.isMotion; + tlwallPaper.uploadingImage = path.getAbsolutePath(); Bitmap bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); float s = Math.max(50 / (float) backgroundImage.getMeasuredWidth(), 50 / (float) backgroundImage.getMeasuredHeight()); @@ -2668,23 +2764,31 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro backgroundImage.draw(canvas); dimAmount = currentDim; Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); - wallPaper.stripedThumb = bitmap; + tlwallPaper.stripedThumb = bitmap; - createServiceMessageLocal(wallPaper, forBoth); + createServiceMessageLocal(tlwallPaper, forBoth); - TLRPC.UserFull fullUser = getMessagesController().getUserFull(dialogId); - if (fullUser != null) { - fullUser.wallpaper = wallPaper; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, fullUser); + if (dialogId >= 0) { + TLRPC.UserFull fullUser = getMessagesController().getUserFull(dialogId); + if (fullUser != null) { + fullUser.wallpaper = tlwallPaper; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, fullUser); + } + } else { + TLRPC.ChatFull fullChat = getMessagesController().getChatFull(-dialogId); + if (fullChat != null) { + fullChat.wallpaper = tlwallPaper; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, fullChat, 0, false, false); + } } } else { - ChatThemeController.getInstance(currentAccount).setWallpaperToUser(dialogId, null, wallpaperInfo, serverWallpaper, () -> { + ChatThemeController.getInstance(currentAccount).setWallpaperToPeer(dialogId, null, wallpaperInfo, serverWallpaper, () -> { }); } setupFinished = true; if (delegate != null) { - delegate.didSetNewBackground(); + delegate.didSetNewBackground(tlwallPaper); } finishFragment(); } else { @@ -2701,7 +2805,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } if (needFinishFragment) { if (delegate != null) { - delegate.didSetNewBackground(); + delegate.didSetNewBackground(tlwallPaper); } finishFragment(); } @@ -4457,6 +4561,11 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } else { backgroundImage.setImage(wallPaper.imageUrl, imageFilter, wallPaper.thumbUrl, "100_100_b"); } + } else if (currentWallpaper instanceof WallpapersListActivity.EmojiWallpaper) { + final boolean isDark = onSwitchDayNightDelegate != null ? onSwitchDayNightDelegate.isDark() : Theme.isCurrentThemeDark(); + Drawable backgroundDrawable = PreviewView.getBackgroundDrawableFromTheme(currentAccount, ((WallpapersListActivity.EmojiWallpaper) currentWallpaper).emoticon, isDark); + backgroundImage.setBackground(backgroundDrawable); + themeDelegate.applyChatServiceMessageColor(AndroidUtilities.calcDrawableColor(backgroundDrawable), checkBlur(backgroundDrawable), backgroundDrawable, currentIntensity); } } else { if (backgroundGradientDisposable != null) { @@ -4768,50 +4877,86 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro TLRPC.Message message; MessageObject messageObject; if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - message = new TLRPC.TL_message(); - if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - message.message = LocaleController.getString("BackgroundColorSinglePreviewLine2", R.string.BackgroundColorSinglePreviewLine2); - } else { - message.message = LocaleController.getString("BackgroundPreviewLine2", R.string.BackgroundPreviewLine2); + if (dialogId >= 0) { + message = new TLRPC.TL_message(); + if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + message.message = LocaleController.getString(R.string.BackgroundColorSinglePreviewLine2); + } else { + message.message = LocaleController.getString(R.string.BackgroundPreviewLine2); + } + message.date = date + 60; + message.dialog_id = 1; + message.flags = 259; + message.id = 1; + message.media = new TLRPC.TL_messageMediaEmpty(); + message.out = true; + message.from_id = new TLRPC.TL_peerUser(); + message.from_id.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); + message.peer_id = new TLRPC.TL_peerUser(); + message.peer_id.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); + messageObject = new MessageObject(currentAccount, message, true, false) { + @Override + public boolean needDrawAvatar() { + return false; + } + }; + messageObject.eventId = 1; + messageObject.resetLayout(); + messages.add(messageObject); } - message.date = date + 60; - message.dialog_id = 1; - message.flags = 259; - message.from_id = new TLRPC.TL_peerUser(); - message.from_id.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); - message.id = 1; - message.media = new TLRPC.TL_messageMediaEmpty(); - message.out = true; - message.peer_id = new TLRPC.TL_peerUser(); - message.peer_id.user_id = 0; - messageObject = new MessageObject(currentAccount, message, true, false); - messageObject.eventId = 1; - messageObject.resetLayout(); - messages.add(messageObject); + MessageObject replyMessageObject = null; message = new TLRPC.TL_message(); - if (dialogId != 0) { - message.message = LocaleController.getString("BackgroundColorSinglePreviewLine3", R.string.BackgroundColorSinglePreviewLine3); - } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - message.message = LocaleController.getString("BackgroundColorSinglePreviewLine1", R.string.BackgroundColorSinglePreviewLine1); + TLRPC.Chat currentChat = dialogId < 0 ? getMessagesController().getChat(-dialogId) : null; + if (currentChat != null) { + message.message = LocaleController.getString(R.string.ChannelBackgroundMessagePreview); + + TLRPC.TL_message replyMessage = new TLRPC.TL_message(); + replyMessage.message = LocaleController.getString(R.string.ChannelBackgroundMessageReplyText); + replyMessageObject = new MessageObject(currentAccount, replyMessage, true, false) { + @Override + public boolean needDrawAvatar() { + return false; + } + }; + + message.from_id = new TLRPC.TL_peerChannel(); + message.from_id.channel_id = currentChat.id; + message.peer_id = new TLRPC.TL_peerChannel(); + message.peer_id.channel_id = currentChat.id; } else { - message.message = LocaleController.getString("BackgroundPreviewLine1", R.string.BackgroundPreviewLine1); + if (dialogId != 0) { + message.message = LocaleController.getString(R.string.BackgroundColorSinglePreviewLine3); + } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + message.message = LocaleController.getString(R.string.BackgroundColorSinglePreviewLine1); + } else { + message.message = LocaleController.getString(R.string.BackgroundPreviewLine1); + } + message.from_id = new TLRPC.TL_peerUser(); + message.peer_id = new TLRPC.TL_peerUser(); + message.peer_id.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); } message.date = date + 60; message.dialog_id = 1; message.flags = 257 + 8; - message.from_id = new TLRPC.TL_peerUser(); message.id = 1; message.media = new TLRPC.TL_messageMediaEmpty(); message.out = false; - message.peer_id = new TLRPC.TL_peerUser(); - message.peer_id.user_id = UserConfig.getInstance(currentAccount).getClientUserId(); - messageObject = new MessageObject(currentAccount, message, true, false); + messageObject = new MessageObject(currentAccount, message, replyMessageObject, true, false) { + @Override + public boolean needDrawAvatar() { + return false; + } + }; + if (replyMessageObject != null) { + messageObject.customReplyName = LocaleController.getString(R.string.ChannelBackgroundMessageReplyName); + } messageObject.eventId = 1; messageObject.resetLayout(); messages.add(messageObject); if (dialogId != 0 && serverWallpaper == null) { + TLRPC.User user = getMessagesController().getUser(dialogId); message = new TLRPC.TL_message(); message.message = ""; messageObject = new MessageObject(currentAccount, message, true, false); @@ -4820,9 +4965,12 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro messages.add(messageObject); message = new TLRPC.TL_message(); - TLRPC.User user = getMessagesController().getUser(dialogId); - String username = user == null ? "DELETED" : user.first_name; - message.message = LocaleController.formatString("ChatBackgroundHint", R.string.ChatBackgroundHint, username); + if (user != null) { + String username = UserObject.getFirstName(user); + message.message = LocaleController.formatString(R.string.ChatBackgroundHint, username); + } else { + message.message = LocaleController.getString(R.string.ChannelBackgroundHint); + } message.date = date + 60; message.dialog_id = 1; message.flags = 257 + 8; @@ -5181,7 +5329,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro view = new ChatMessageCell(mContext, false, null, new Theme.ResourcesProvider() { @Override public int getColor(int key) { - return getThemedColor(key); + return themeDelegate.getColor(key); } @Override @@ -5198,16 +5346,41 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro if (drawableKey.equals(Theme.key_drawable_msgOutMediaSelected)) { return msgOutMediaDrawableSelected; } - if (getResourceProvider() != null) { - return getResourceProvider().getDrawable(drawableKey); + if (themeDelegate != null) { + return themeDelegate.getDrawable(drawableKey); } return Theme.getThemeDrawable(drawableKey); } + @Override + public boolean isDark() { + return themeDelegate.isDark(); + } + + @Override + public int getCurrentColor(int key) { + return themeDelegate.getCurrentColor(key); + } + + @Override + public int getColorOrDefault(int key) { + return themeDelegate.getColorOrDefault(key); + } + + @Override + public Paint getPaint(String paintKey) { + return themeDelegate.getPaint(paintKey); + } + + @Override + public boolean hasGradientService() { + return themeDelegate.hasGradientService(); + } + @Override public void applyServiceShaderMatrix(int w, int h, float translationX, float translationY) { - if (getResourceProvider() != null) { - getResourceProvider().applyServiceShaderMatrix(w, h, translationX, translationY); + if (themeDelegate != null) { + themeDelegate.applyServiceShaderMatrix(w, h, translationX, translationY); } else { Theme.ResourcesProvider.super.applyServiceShaderMatrix(w, h, translationX, translationY); } @@ -5287,7 +5460,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } else { pinnedTop = false; } - messageCell.isChat = showSecretMessages; + messageCell.isChat = showSecretMessages || dialogId < 0; messageCell.setFullyDraw(true); messageCell.setMessageObject(message, null, pinnedBotton, pinnedTop); } else if (view instanceof ChatActionCell) { @@ -5609,11 +5782,19 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro message.unread = true; message.out = true; message.local_id = message.id = getUserConfig().getNewMessageId(); - message.from_id = new TLRPC.TL_peerUser(); - message.from_id.user_id = getUserConfig().getClientUserId(); + TLRPC.Chat currentChat = getMessagesController().getChat(-dialogId); + if (ChatObject.isChannel(currentChat)) { + message.from_id = new TLRPC.TL_peerChannel(); + message.from_id.channel_id = currentChat.id; + message.peer_id = new TLRPC.TL_peerChannel(); + message.peer_id.channel_id = currentChat.id; + } else { + message.from_id = new TLRPC.TL_peerUser(); + message.from_id.user_id = getUserConfig().getClientUserId(); + message.peer_id = new TLRPC.TL_peerUser(); + message.peer_id.user_id = dialogId; + } message.flags |= 256; - message.peer_id = new TLRPC.TL_peerUser(); - message.peer_id.user_id = dialogId; message.date = getConnectionsManager().getCurrentTime(); TLRPC.TL_messageActionSetChatWallPaper setChatWallPaper = new TLRPC.TL_messageActionSetChatWallPaper(); message.action = setChatWallPaper; @@ -5631,6 +5812,8 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro public interface DayNightSwitchDelegate { boolean isDark(); + boolean supportsAnimation(); + void switchDayNight(boolean animated); } @@ -5742,6 +5925,14 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro @Override public void setBackground(Drawable drawable) { background = drawable; + if (background != null) { + background.setCallback(this); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return background == who || super.verifyDrawable(who); } } @@ -5770,6 +5961,9 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private class BlurButton extends View { private Text text; + private Text subtext; + private boolean subtextShown; + private AnimatedFloat subtextShownT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); private final Drawable rippleDrawable = Theme.createRadSelectorDrawable(0x10ffffff, 8, 8); private final ColorFilter colorFilter; @@ -5779,7 +5973,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro ColorMatrix colorMatrix = new ColorMatrix(); AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.35f); - AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.75f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.9f); colorFilter = new ColorMatrixColorFilter(colorMatrix); } @@ -5787,6 +5981,17 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro this.text = new Text(text, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); } + public void setSubText(CharSequence subtext, boolean animated) { + if (subtext != null) { + this.subtext = new Text(subtext, 12); + } + subtextShown = subtext != null; + if (!animated) { + subtextShownT.set(subtextShown, true); + } + invalidate(); + } + public CharSequence getText() { return this.text != null ? this.text.getText() : null; } @@ -5830,10 +6035,19 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro invalidate(); } + final float subtitleT = subtextShownT.set(subtextShown); if (loadingT < 1 && text != null) { text .ellipsize(getWidth() - dp(14)) - .draw(canvas, (getWidth() - text.getWidth()) / 2f, getHeight() / 2f + loadingT * dp(24), textColor, 1f - loadingT); + .draw(canvas, (getWidth() - text.getWidth()) / 2f, getHeight() / 2f + loadingT * dp(24) - dp(7) * subtitleT, textColor, 1f - loadingT); + } + if (loadingT < 1 && subtext != null) { + canvas.save(); + canvas.scale(subtitleT, subtitleT, getWidth() / 2f, getHeight() / 2f + dp(11)); + subtext + .ellipsize(getWidth() - dp(14)) + .draw(canvas, (getWidth() - subtext.getWidth()) / 2f, getHeight() / 2f + loadingT * dp(24) + dp(11), Theme.multAlpha(textColor, .75f), 1f - loadingT); + canvas.restore(); } rippleDrawable.setBounds(0, 0, getWidth(), getHeight()); @@ -5890,7 +6104,7 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro } } - public static class ThemeDelegate implements Theme.ResourcesProvider { + public class ThemeDelegate implements Theme.ResourcesProvider { public Theme.ResourcesProvider parentProvider; @@ -6006,6 +6220,22 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro if (serviceBitmapShader != null && (currentColors.indexOfKey(Theme.key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable)) { ColorMatrix colorMatrix = new ColorMatrix(); + if (drawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); + if (intensity >= 0) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark() ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark() ? +.12f : -.06f); + } else { + colorMatrix.setSaturation(1.1f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark() ? .4f : .8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark() ? +.08f : -.06f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark() ? .9f : .84f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark() ? -.04f : +.06f); + } if (drawable instanceof MotionBackgroundDrawable) { float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); if (overrideIntensity != null) { @@ -6051,5 +6281,159 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro Theme.applyServiceShaderMatrix(serviceBitmap, serviceBitmapShader, serviceBitmapMatrix, w, h, translationX, translationY); } } + + @Override + public boolean isDark() { + return onSwitchDayNightDelegate != null ? onSwitchDayNightDelegate.isDark() : (parentProvider != null ? parentProvider.isDark() : Theme.isCurrentThemeDark()); + } + } + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + @SuppressLint("NotifyDataSetChanged") + public void toggleTheme() { + if (changeDayNightView != null) { + return; + } + + FrameLayout decorView1 = insideBottomSheet() ? (FrameLayout) parentLayout.getBottomSheet().getWindow().getDecorView() : (FrameLayout) getParentActivity().getWindow().getDecorView(); + Bitmap bitmap = Bitmap.createBitmap(decorView1.getWidth(), decorView1.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + dayNightItem.setAlpha(0f); + decorView1.draw(bitmapCanvas); + dayNightItem.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + dayNightItem.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + dayNightItem.getMeasuredWidth() / 2f; + float cy = y + dayNightItem.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (themeDelegate.isDark()) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + dayNightItem.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setDuration(400); + changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad); + changeDayNightViewAnimator.start(); + + decorView1.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + onSwitchDayNightDelegate.switchDayNight(false); + setForceDark(themeDelegate.isDark(), true); + setCurrentImage(false); + invalidateBlur(); + updateBlurred(); + if (themeDescriptions != null) { + for (int i = 0; i < themeDescriptions.size(); ++i) { + themeDescriptions.get(i).setColor(getThemedColor(themeDescriptions.get(i).getCurrentKey()), false, false); + } + } + + if (shouldShowBrightnessControll) { + if (onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { + dimmingSlider.setVisibility(View.VISIBLE); + dimmingSlider.animateValueTo(dimAmount); + } else { + dimmingSlider.animateValueTo(0); + } + if (changeDayNightViewAnimator2 != null) { + changeDayNightViewAnimator2.removeAllListeners(); + changeDayNightViewAnimator2.cancel(); + } + changeDayNightViewAnimator2 = ValueAnimator.ofFloat(progressToDarkTheme, onSwitchDayNightDelegate.isDark() ? 1 : 0); + changeDayNightViewAnimator2.addUpdateListener(animation -> { + progressToDarkTheme = (float) animation.getAnimatedValue(); + backgroundImage.invalidate(); + bottomOverlayChat.invalidate(); + dimmingSlider.setAlpha(progressToDarkTheme); + dimmingSliderContainer.invalidate(); + invalidateBlur(); + }); + changeDayNightViewAnimator2.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!onSwitchDayNightDelegate.isDark()) { + dimmingSlider.setVisibility(View.GONE); + } + } + }); + changeDayNightViewAnimator2.setDuration(250); + changeDayNightViewAnimator2.setInterpolator(CubicBezierInterpolator.DEFAULT); + changeDayNightViewAnimator2.start(); + } + }); + } + + public void setForceDark(boolean isDark, boolean playAnimation) { + if (playAnimation) { + sunDrawable.setCustomEndFrame(isDark ? sunDrawable.getFramesCount() : 0); + if (sunDrawable != null) { + sunDrawable.start(); + } + } else { + int frame = isDark ? sunDrawable.getFramesCount() - 1 : 0; + sunDrawable.setCurrentFrame(frame, false, true); + sunDrawable.setCustomEndFrame(frame); + if (dayNightItem != null) { + dayNightItem.invalidate(); + } + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index a1e20aa45..3fc5498e1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -1,5 +1,7 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.isTablet; import static org.telegram.ui.GroupCallActivity.TRANSITION_DURATION; import android.Manifest; @@ -7,6 +9,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -23,13 +26,15 @@ import android.graphics.RectF; import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.os.PowerManager; +import android.text.Layout; +import android.text.Spannable; +import android.text.TextPaint; import android.text.TextUtils; import android.transition.ChangeBounds; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; import android.transition.Visibility; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -59,11 +64,12 @@ import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; -import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -71,35 +77,51 @@ import org.telegram.messenger.voip.EncryptionKeyEmojifier; import org.telegram.messenger.voip.Instance; import org.telegram.messenger.voip.VideoCapturerDevice; import org.telegram.messenger.voip.VoIPService; +import org.telegram.messenger.voip.VoipAudioManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.DarkAlertDialog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CubicBezierInterpolator; -import org.telegram.ui.Components.HintView; +import org.telegram.ui.Components.HideViewAfterAnimation; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.voip.AcceptDeclineView; -import org.telegram.ui.Components.voip.PrivateVideoPreviewDialog; +import org.telegram.ui.Components.voip.EmojiRationalLayout; +import org.telegram.ui.Components.voip.HideEmojiTextView; +import org.telegram.ui.Components.voip.ImageWithWavesView; +import org.telegram.ui.Components.voip.EndCloseLayout; +import org.telegram.ui.Components.voip.PrivateVideoPreviewDialogNew; +import org.telegram.ui.Components.voip.RateCallLayout; +import org.telegram.ui.Components.voip.VoIPBackgroundProvider; import org.telegram.ui.Components.voip.VoIPButtonsLayout; import org.telegram.ui.Components.voip.VoIPFloatingLayout; import org.telegram.ui.Components.voip.VoIPHelper; import org.telegram.ui.Components.voip.VoIPNotificationsLayout; -import org.telegram.ui.Components.voip.VoIPOverlayBackground; import org.telegram.ui.Components.voip.VoIPPiPView; import org.telegram.ui.Components.voip.VoIPStatusTextView; import org.telegram.ui.Components.voip.VoIPTextureView; 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.VoIpSnowView; +import org.telegram.ui.Components.voip.VoIpSwitchLayout; +import org.telegram.ui.Stories.recorder.HintView2; import org.webrtc.EglBase; import org.webrtc.GlRectDrawer; import org.webrtc.RendererCommon; import org.webrtc.TextureViewRenderer; import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; public class VoIPFragment implements VoIPService.StateListener, NotificationCenter.NotificationCenterDelegate { @@ -114,23 +136,34 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent TLRPC.User currentUser; TLRPC.User callingUser; - VoIPToggleButton[] bottomButtons = new VoIPToggleButton[4]; + private VoIpSwitchLayout bottomSpeakerBtn; + private VoIpSwitchLayout bottomVideoBtn; + private VoIpSwitchLayout bottomMuteBtn; + private VoIPToggleButton bottomEndCallBtn; + private final VoIPBackgroundProvider backgroundProvider = new VoIPBackgroundProvider(); private ViewGroup fragmentView; - private VoIPOverlayBackground overlayBackground; - private BackupImageView callingUserPhotoView; - private BackupImageView callingUserPhotoViewMini; + private VoIpGradientLayout gradientLayout; + private VoIpSnowView voIpSnowView; + private ImageWithWavesView callingUserPhotoViewMini; private TextView callingUserTitle; private VoIPStatusTextView statusTextView; private ImageView backIcon; private ImageView speakerPhoneIcon; + private int selectedRating; LinearLayout emojiLayout; + FrameLayout hideEmojiLayout; + TextView hideEmojiTextView; + RateCallLayout rateCallLayout; + LinearLayout emojiRationalLayout; + TextView emojiRationalTopTextView; TextView emojiRationalTextView; - ImageView[] emojiViews = new ImageView[4]; + EndCloseLayout endCloseLayout; + BackupImageView[] emojiViews = new BackupImageView[4]; Emoji.EmojiDrawable[] emojiDrawables = new Emoji.EmojiDrawable[4]; LinearLayout statusLayout; private VoIPFloatingLayout currentUserCameraFloatingLayout; @@ -142,6 +175,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent private VoIPTextureView currentUserTextureView; private AcceptDeclineView acceptDeclineView; + private boolean isNearEar; View bottomShadow; View topShadow; @@ -154,11 +188,12 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent boolean callingUserIsVideo; boolean currentUserIsVideo; - private PrivateVideoPreviewDialog previewDialog; + private PrivateVideoPreviewDialogNew previewDialog; private int currentState; private int previousState; private WindowInsets lastInsets; + private boolean wasEstablished; float touchSlop; @@ -188,7 +223,8 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent AnimationNotificationsLocker notificationsLocker = new AnimationNotificationsLocker(); VoIPNotificationsLayout notificationsLayout; - HintView tapToVideoTooltip; + HintView2 tapToVideoTooltip; + HintView2 encryptionTooltip; ValueAnimator uiVisibilityAnimator; ValueAnimator.AnimatorUpdateListener statusbarAnimatorListener = valueAnimator -> { @@ -197,23 +233,25 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent }; float fillNaviagtionBarValue; - boolean fillNaviagtionBar; - ValueAnimator naviagtionBarAnimator; - ValueAnimator.AnimatorUpdateListener navigationBarAnimationListener = valueAnimator -> { - fillNaviagtionBarValue = (float) valueAnimator.getAnimatedValue(); - updateSystemBarColors(); - }; boolean hideUiRunnableWaiting; Runnable hideUIRunnable = () -> { hideUiRunnableWaiting = false; - if (canHideUI && uiVisible && !emojiExpanded) { + boolean tapToVideoTooltipVisible = tapToVideoTooltip != null && tapToVideoTooltip.shown(); + if (canHideUI && uiVisible && !emojiExpanded && !tapToVideoTooltipVisible) { lastContentTapTime = System.currentTimeMillis(); showUi(false); previousState = currentState; updateViewState(); } }; + + Runnable stopAnimatingBgRunnable = () -> { + if (currentState == VoIPService.STATE_ESTABLISHED) { + callingUserPhotoViewMini.setMute(true, false); + gradientLayout.pause(); + } + }; private boolean lockOnScreen; private boolean screenWasWakeup; private boolean isVideoCall; @@ -263,8 +301,8 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent instance = fragment; VoIPWindowView windowView = new VoIPWindowView(activity, !transitionFromPip) { - private Path clipPath = new Path(); - private RectF rectF = new RectF(); + private final Path clipPath = new Path(); + private final RectF rectF = new RectF(); @Override public boolean dispatchKeyEvent(KeyEvent event) { @@ -378,7 +416,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (emojiExpanded) { expandEmoji(false); } else { - if (emojiRationalTextView.getVisibility() != View.GONE) { + if (emojiRationalLayout.getVisibility() != View.GONE) { return; } if (canSwitchToPip && !lockOnScreen) { @@ -397,9 +435,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (instance != null) { if (VoIPService.getSharedInstance() != null) { int h = instance.windowView.getMeasuredHeight(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { - h -= instance.lastInsets.getSystemWindowInsetBottom(); - } if (instance.canSwitchToPip) { VoIPPiPView.show(instance.activity, instance.currentAccount, instance.windowView.getMeasuredWidth(), h, VoIPPiPView.ANIMATION_ENTER_TYPE_SCALE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { @@ -428,17 +463,14 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent ((FrameLayout.LayoutParams) acceptDeclineView.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); ((FrameLayout.LayoutParams) backIcon.getLayoutParams()).topMargin = lastInsets.getSystemWindowInsetTop(); ((FrameLayout.LayoutParams) speakerPhoneIcon.getLayoutParams()).topMargin = lastInsets.getSystemWindowInsetTop(); - ((FrameLayout.LayoutParams) topShadow.getLayoutParams()).topMargin = lastInsets.getSystemWindowInsetTop(); - ((FrameLayout.LayoutParams) statusLayout.getLayoutParams()).topMargin = AndroidUtilities.dp(68) + lastInsets.getSystemWindowInsetTop(); + ((FrameLayout.LayoutParams) statusLayout.getLayoutParams()).topMargin = AndroidUtilities.dp(135) + lastInsets.getSystemWindowInsetTop(); ((FrameLayout.LayoutParams) emojiLayout.getLayoutParams()).topMargin = AndroidUtilities.dp(17) + lastInsets.getSystemWindowInsetTop(); - ((FrameLayout.LayoutParams) callingUserPhotoViewMini.getLayoutParams()).topMargin = AndroidUtilities.dp(68) + lastInsets.getSystemWindowInsetTop(); - - ((FrameLayout.LayoutParams) currentUserCameraFloatingLayout.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); + ((FrameLayout.LayoutParams) callingUserPhotoViewMini.getLayoutParams()).topMargin = AndroidUtilities.dp(93) + lastInsets.getSystemWindowInsetTop(); + ((FrameLayout.LayoutParams) hideEmojiLayout.getLayoutParams()).topMargin = lastInsets.getSystemWindowInsetTop(); + ((FrameLayout.LayoutParams) emojiRationalLayout.getLayoutParams()).topMargin = AndroidUtilities.dp(118) + lastInsets.getSystemWindowInsetTop(); + ((FrameLayout.LayoutParams) rateCallLayout.getLayoutParams()).topMargin = AndroidUtilities.dp(380) + lastInsets.getSystemWindowInsetTop(); ((FrameLayout.LayoutParams) callingUserMiniFloatingLayout.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); - ((FrameLayout.LayoutParams) callingUserTextureView.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); ((FrameLayout.LayoutParams) notificationsLayout.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); - - ((FrameLayout.LayoutParams) bottomShadow.getLayoutParams()).bottomMargin = lastInsets.getSystemWindowInsetBottom(); currentUserCameraFloatingLayout.setInsets(lastInsets); callingUserMiniFloatingLayout.setInsets(lastInsets); fragmentView.requestLayout(); @@ -455,9 +487,11 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent isOutgoing = VoIPService.getSharedInstance().isOutgoing(); previousState = -1; currentState = VoIPService.getSharedInstance().getCallState(); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.webRtcSpeakerAmplitudeEvent); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.voipServiceCreated); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.closeInCallActivity); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.nearEarEvent); } private void destroy() { @@ -465,9 +499,11 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (service != null) { service.unregisterStateListener(this); } + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.webRtcSpeakerAmplitudeEvent); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.voipServiceCreated); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.closeInCallActivity); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.nearEarEvent); } @Override @@ -495,13 +531,34 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent updateKeyView(true); } else if (id == NotificationCenter.closeInCallActivity) { windowView.finish(); + } else if (id == NotificationCenter.webRtcSpeakerAmplitudeEvent) { + callingUserPhotoViewMini.setAmplitude((float) args[0] * 15.0f); + } else if (id == NotificationCenter.nearEarEvent) { + isNearEar = (boolean) args[0]; + if (isNearEar) { + callingUserPhotoViewMini.setMute(true, true); + } } } + private boolean signalBarWasReceived; + @Override public void onSignalBarsCountChanged(int count) { - if (statusTextView != null) { - statusTextView.setSignalBarCount(count); + if (count > 0) { + signalBarWasReceived = true; + } + if (statusTextView != null && gradientLayout != null && gradientLayout.isConnectedCalled() && signalBarWasReceived) { + AndroidUtilities.runOnUIThread(() -> { + statusTextView.setSignalBarCount(count); + if (count <= 1) { + gradientLayout.showToBadConnection(); + statusTextView.showBadConnection(true, true); + } else { + gradientLayout.hideBadConnection(); + statusTextView.showBadConnection(false, true); + } + }, 400); } } @@ -544,25 +601,35 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent accessibilityManager = ContextCompat.getSystemService(context, AccessibilityManager.class); FrameLayout frameLayout = new FrameLayout(context) { - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && lastInsets != null) { - canvas.drawRect(0, 0, getMeasuredWidth(), lastInsets.getSystemWindowInsetTop(), overlayPaint); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && lastInsets != null) { - canvas.drawRect(0, getMeasuredHeight() - lastInsets.getSystemWindowInsetBottom(), getMeasuredWidth(), getMeasuredHeight(), overlayBottomPaint); - } - } float pressedX; float pressedY; boolean check; long pressedTime; + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getActionMasked() == MotionEvent.ACTION_UP) { + callingUserPhotoViewMini.setMute(false, false); + gradientLayout.resume(); + AndroidUtilities.cancelRunOnUIThread(stopAnimatingBgRunnable); + if (currentState == VoIPService.STATE_ESTABLISHED) { + AndroidUtilities.runOnUIThread(stopAnimatingBgRunnable, 10000); + } + } + return super.onInterceptTouchEvent(ev); + } + @Override public boolean onTouchEvent(MotionEvent ev) { + if (ev.getActionMasked() == MotionEvent.ACTION_UP) { + callingUserPhotoViewMini.setMute(false, false); + gradientLayout.resume(); + AndroidUtilities.cancelRunOnUIThread(stopAnimatingBgRunnable); + if (currentState == VoIPService.STATE_ESTABLISHED) { + AndroidUtilities.runOnUIThread(stopAnimatingBgRunnable, 10000); + } + } /* === pinch to zoom === */ if (!canZoomGesture && !isInPinchToZoomTouchMode && !zoomStarted && ev.getActionMasked() != MotionEvent.ACTION_DOWN) { finishZoom(); @@ -666,6 +733,9 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } else if (canHideUI) { showUi(!uiVisible); previousState = currentState; + if (!uiVisible && tapToVideoTooltip != null && tapToVideoTooltip.shown()) { + tapToVideoTooltip.hide(); + } updateViewState(); } } @@ -678,11 +748,11 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == callingUserPhotoView && (currentUserIsVideo || callingUserIsVideo)) { + if (child == gradientLayout && (currentUserIsVideo || callingUserIsVideo)) { return false; } if ( - child == callingUserPhotoView || + child == gradientLayout || child == callingUserTextureView || (child == currentUserCameraFloatingLayout && currentUserCameraIsFullscreen) ) { @@ -704,16 +774,8 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent updateSystemBarColors(); fragmentView = frameLayout; frameLayout.setFitsSystemWindows(true); - callingUserPhotoView = new BackupImageView(context) { - int blackoutColor = ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.3f)); - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.drawColor(blackoutColor); - } - }; + gradientLayout = new VoIpGradientLayout(context, backgroundProvider); callingUserTextureView = new VoIPTextureView(context, false, true, false, false); callingUserTextureView.renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); callingUserTextureView.renderer.setEnableHardwareScaler(true); @@ -721,29 +783,18 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserTextureView.scaleType = VoIPTextureView.SCALE_TYPE_FIT; // callingUserTextureView.attachBackgroundRenderer(); - frameLayout.addView(callingUserPhotoView); + frameLayout.addView(gradientLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + frameLayout.addView(voIpSnowView = new VoIpSnowView(context), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 220)); frameLayout.addView(callingUserTextureView); - final BackgroundGradientDrawable gradientDrawable = new BackgroundGradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{0xFF1b354e, 0xFF255b7d}); final BackgroundGradientDrawable.Sizes sizes = BackgroundGradientDrawable.Sizes.ofDeviceScreen(BackgroundGradientDrawable.Sizes.Orientation.PORTRAIT); gradientDrawable.startDithering(sizes, new BackgroundGradientDrawable.ListenerAdapter() { @Override public void onAllSizesReady() { - callingUserPhotoView.invalidate(); + gradientLayout.invalidate(); } }); - overlayBackground = new VoIPOverlayBackground(context); - overlayBackground.setVisibility(View.GONE); - - callingUserPhotoView.getImageReceiver().setDelegate((imageReceiver, set, thumb, memCache) -> { - ImageReceiver.BitmapHolder bmp = imageReceiver.getBitmapSafe(); - if (bmp != null) { - overlayBackground.setBackground(bmp); - } - }); - - callingUserPhotoView.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_BIG), null, gradientDrawable, callingUser); currentUserCameraFloatingLayout = new VoIPFloatingLayout(context); currentUserCameraFloatingLayout.setDelegate((progress, value) -> currentUserTextureView.setScreenshareMiniProgress(progress, value)); @@ -778,7 +829,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent View backgroundView = new View(context); backgroundView.setBackgroundColor(0xff1b1f23); - callingUserMiniFloatingLayout.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + //callingUserMiniFloatingLayout.addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); callingUserMiniFloatingLayout.addView(callingUserMiniTextureRenderer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); callingUserMiniFloatingLayout.setOnTapListener(view -> { if (cameraForceExpanded && System.currentTimeMillis() - lastContentTapTime > 500) { @@ -796,17 +847,14 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent frameLayout.addView(currentUserCameraFloatingLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); frameLayout.addView(callingUserMiniFloatingLayout); - frameLayout.addView(overlayBackground); - bottomShadow = new View(context); bottomShadow.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.5f))})); - frameLayout.addView(bottomShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 140, Gravity.BOTTOM)); + frameLayout.addView(bottomShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 160, Gravity.BOTTOM)); topShadow = new View(context); topShadow.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.4f)), Color.TRANSPARENT})); - frameLayout.addView(topShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 140, Gravity.TOP)); - + frameLayout.addView(topShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 160, Gravity.TOP)); emojiLayout = new LinearLayout(context) { @Override @@ -824,22 +872,60 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent return; } lastContentTapTime = System.currentTimeMillis(); + if (emojiExpanded) return; if (emojiLoaded) { expandEmoji(!emojiExpanded); } }); - emojiRationalTextView = new TextView(context); - emojiRationalTextView.setText(LocaleController.formatString("CallEmojiKeyTooltip", R.string.CallEmojiKeyTooltip, UserObject.getFirstName(callingUser))); - emojiRationalTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + hideEmojiTextView = new HideEmojiTextView(context, backgroundProvider); + hideEmojiLayout = new FrameLayout(context); + hideEmojiLayout.addView(hideEmojiTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 0, 16, 0, 0)); + hideEmojiLayout.setVisibility(View.GONE); + hideEmojiLayout.setOnClickListener(v -> { + if (System.currentTimeMillis() - lastContentTapTime < 500) { + return; + } + lastContentTapTime = System.currentTimeMillis(); + if (emojiLoaded) { + expandEmoji(!emojiExpanded); + } + }); + + emojiRationalLayout = new EmojiRationalLayout(context, backgroundProvider); + emojiRationalLayout.setOrientation(LinearLayout.VERTICAL); + + emojiRationalTopTextView = new TextView(context); + emojiRationalTopTextView.setText(LocaleController.getString("VoipCallEncryptionEndToEnd", R.string.VoipCallEncryptionEndToEnd)); + emojiRationalTopTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + emojiRationalTopTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + emojiRationalTopTextView.setTextColor(Color.WHITE); + emojiRationalTopTextView.setGravity(Gravity.CENTER); + + emojiRationalTextView = new TextView(context) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + updateViewState(); + } + } + }; + emojiRationalTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); emojiRationalTextView.setTextColor(Color.WHITE); emojiRationalTextView.setGravity(Gravity.CENTER); - emojiRationalTextView.setVisibility(View.GONE); + CharSequence ellipsizeName = TextUtils.ellipsize(UserObject.getFirstName(callingUser), emojiRationalTextView.getPaint(), dp(300), TextUtils.TruncateAt.END); + emojiRationalTextView.setText(LocaleController.formatString("CallEmojiKeyTooltip", R.string.CallEmojiKeyTooltip, ellipsizeName)); + + emojiRationalLayout.setVisibility(View.GONE); + emojiRationalLayout.addView(emojiRationalTopTextView); + emojiRationalLayout.addView(emojiRationalTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 8, 0, 0)); + emojiRationalLayout.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(80), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); for (int i = 0; i < 4; i++) { - emojiViews[i] = new ImageView(context); - emojiViews[i].setScaleType(ImageView.ScaleType.FIT_XY); - emojiLayout.addView(emojiViews[i], LayoutHelper.createLinear(22, 22, i == 0 ? 0 : 4, 0, 0, 0)); + emojiViews[i] = new BackupImageView(context); + emojiViews[i].getImageReceiver().setAspectFit(true); + emojiLayout.addView(emojiViews[i], LayoutHelper.createLinear(25, 25, i == 0 ? 0 : 6, 0, 0, 0)); } statusLayout = new LinearLayout(context) { @Override @@ -871,23 +957,26 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent statusLayout.setFocusable(true); statusLayout.setFocusableInTouchMode(true); - callingUserPhotoViewMini = new BackupImageView(context); - callingUserPhotoViewMini.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_SMALL), null, Theme.createCircleDrawable(AndroidUtilities.dp(135), 0xFF000000), callingUser); + callingUserPhotoViewMini = new ImageWithWavesView(context); + AvatarDrawable avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(callingUser); + callingUserPhotoViewMini.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_BIG), null, avatarDrawable, callingUser); callingUserPhotoViewMini.setRoundRadius(AndroidUtilities.dp(135) / 2); - callingUserPhotoViewMini.setVisibility(View.GONE); callingUserTitle = new TextView(context); - callingUserTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); + callingUserTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 28); CharSequence name = ContactsController.formatName(callingUser.first_name, callingUser.last_name); name = Emoji.replaceEmoji(name, callingUserTitle.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); 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); - statusLayout.addView(callingUserTitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 6)); + statusLayout.addView(callingUserTitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 8, 0, 8, 6)); - statusTextView = new VoIPStatusTextView(context); + statusTextView = new VoIPStatusTextView(context, backgroundProvider); ViewCompat.setImportantForAccessibility(statusTextView, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); statusLayout.addView(statusTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 6)); @@ -895,18 +984,56 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent statusLayout.setClipToPadding(false); statusLayout.setPadding(0, 0, 0, AndroidUtilities.dp(15)); - frameLayout.addView(callingUserPhotoViewMini, LayoutHelper.createFrame(135, 135, Gravity.CENTER_HORIZONTAL, 0, 68, 0, 0)); - frameLayout.addView(statusLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 68, 0, 0)); - frameLayout.addView(emojiLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 17, 0, 0)); - frameLayout.addView(emojiRationalTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 24, 32, 24, 0)); + endCloseLayout = new EndCloseLayout(context); + rateCallLayout = new RateCallLayout(context, backgroundProvider); + endCloseLayout.setAlpha(0f); + rateCallLayout.setVisibility(View.GONE); + + frameLayout.addView(callingUserPhotoViewMini, LayoutHelper.createFrame(204, 204, Gravity.CENTER_HORIZONTAL, 0, 93, 0, 0)); + frameLayout.addView(statusLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 135, 0, 0)); + frameLayout.addView(hideEmojiLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + frameLayout.addView(emojiRationalLayout, LayoutHelper.createFrame(304, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 118, 0, 0)); + frameLayout.addView(emojiLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + frameLayout.addView(endCloseLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.RIGHT, 0, 0, 0, 0)); + frameLayout.addView(rateCallLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 0, 380, 0, 0)); buttonsLayout = new VoIPButtonsLayout(context); - for (int i = 0; i < 4; i++) { - bottomButtons[i] = new VoIPToggleButton(context); - buttonsLayout.addView(bottomButtons[i]); - } + bottomSpeakerBtn = new VoIpSwitchLayout(context, backgroundProvider); + bottomVideoBtn = new VoIpSwitchLayout(context, backgroundProvider); + bottomMuteBtn = new VoIpSwitchLayout(context, backgroundProvider); + bottomEndCallBtn = new VoIPToggleButton(context) { + @Override + protected void dispatchSetPressed(boolean pressed) { + super.dispatchSetPressed(pressed); + setPressedBtn(pressed); + } + }; + int startDelay = 150; + bottomSpeakerBtn.setTranslationY(AndroidUtilities.dp(100)); + bottomSpeakerBtn.setScaleX(0f); + bottomSpeakerBtn.setScaleY(0f); + bottomSpeakerBtn.animate().setStartDelay(startDelay).translationY(0).scaleY(1f).scaleX(1f).setDuration(250).start(); + bottomVideoBtn.setTranslationY(AndroidUtilities.dp(100)); + bottomVideoBtn.setScaleX(0f); + bottomVideoBtn.setScaleY(0f); + bottomVideoBtn.animate().setStartDelay(startDelay + 16).translationY(0).scaleY(1f).scaleX(1f).setDuration(250).start(); + bottomMuteBtn.setTranslationY(AndroidUtilities.dp(100)); + bottomMuteBtn.setScaleX(0f); + bottomMuteBtn.setScaleY(0f); + bottomMuteBtn.animate().setStartDelay(startDelay + 32).translationY(0).scaleY(1f).scaleX(1f).setDuration(250).start(); + bottomEndCallBtn.setTranslationY(AndroidUtilities.dp(100)); + bottomEndCallBtn.setScaleX(0f); + bottomEndCallBtn.setScaleY(0f); + bottomEndCallBtn.animate().setStartDelay(startDelay + 48).translationY(0).scaleY(1f).scaleX(1f).setDuration(250).start(); + + buttonsLayout.addView(bottomSpeakerBtn); + buttonsLayout.addView(bottomVideoBtn); + buttonsLayout.addView(bottomMuteBtn); + buttonsLayout.addView(bottomEndCallBtn); + acceptDeclineView = new AcceptDeclineView(context); acceptDeclineView.setListener(new AcceptDeclineView.Listener() { + @Override public void onAccept() { if (currentState == VoIPService.STATE_BUSY) { @@ -927,10 +1054,14 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent activity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 101); } else { if (VoIPService.getSharedInstance() != null) { - VoIPService.getSharedInstance().acceptIncomingCall(); - if (currentUserIsVideo) { - VoIPService.getSharedInstance().requestVideoCall(false); - } + runAcceptCallAnimation(() -> { + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().acceptIncomingCall(); + if (currentUserIsVideo) { + VoIPService.getSharedInstance().requestVideoCall(false); + } + } + }); } } } @@ -947,14 +1078,16 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } } }); - acceptDeclineView.setScreenWasWakeup(screenWasWakeup); + acceptDeclineView.setScaleX(1.15f); + acceptDeclineView.setScaleY(1.15f); frameLayout.addView(buttonsLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); - frameLayout.addView(acceptDeclineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 186, Gravity.BOTTOM)); + int horizontalMargin = isTablet() ? 100 : 27; + frameLayout.addView(acceptDeclineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 186, Gravity.BOTTOM, horizontalMargin, 0, horizontalMargin, 0)); backIcon = new ImageView(context); backIcon.setBackground(Theme.createSelectorDrawable(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.3f)))); - backIcon.setImageResource(R.drawable.ic_ab_back); + backIcon.setImageResource(R.drawable.msg_call_minimize_shadow); backIcon.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); backIcon.setContentDescription(LocaleController.getString("Back", R.string.Back)); frameLayout.addView(backIcon, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.LEFT)); @@ -975,12 +1108,23 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent speakerPhoneIcon.setBackground(Theme.createSelectorDrawable(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.3f)))); speakerPhoneIcon.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(12)); frameLayout.addView(speakerPhoneIcon, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT)); + speakerPhoneIcon.setAlpha(0f); speakerPhoneIcon.setOnClickListener(view -> { if (speakerPhoneIcon.getTag() == null) { return; } - if (VoIPService.getSharedInstance() != null) { - VoIPService.getSharedInstance().toggleSpeakerphoneOrShowRouteSheet(activity, false); + VoIPService service = VoIPService.getSharedInstance(); + if (service != null) { + startWaitingFoHideUi(); + final int selectedSpeaker; + if (service.isBluetoothOn()) { + selectedSpeaker = 2; + } else if (service.isSpeakerphoneOn()) { + selectedSpeaker = 0; + } else { + selectedSpeaker = 1; + } + service.toggleSpeakerphoneOrShowRouteSheet(activity, false, selectedSpeaker); } }); @@ -993,7 +1137,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent backIcon.setVisibility(View.GONE); } - notificationsLayout = new VoIPNotificationsLayout(context); + notificationsLayout = new VoIPNotificationsLayout(context, backgroundProvider); notificationsLayout.setGravity(Gravity.BOTTOM); notificationsLayout.setOnViewsUpdated(() -> { previousState = currentState; @@ -1001,11 +1145,30 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent }); frameLayout.addView(notificationsLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 200, Gravity.BOTTOM, 16, 0, 16, 0)); - tapToVideoTooltip = new HintView(context, 4); + tapToVideoTooltip = new VoIpHintView(context, HintView2.DIRECTION_BOTTOM, backgroundProvider, true) + .setMultilineText(true) + .setTextAlign(Layout.Alignment.ALIGN_CENTER) + .setDuration(-1) + .setOnHiddenListener(this::startWaitingFoHideUi) + .setHideByTouch(true) + .setMaxWidth(320) + .useScale(true) + .setInnerPadding(10, 6, 10, 6) + .setRounding(8); tapToVideoTooltip.setText(LocaleController.getString("TapToTurnCamera", R.string.TapToTurnCamera)); - frameLayout.addView(tapToVideoTooltip, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 19, 0, 19, 8)); - tapToVideoTooltip.setBottomOffset(AndroidUtilities.dp(4)); - tapToVideoTooltip.setVisibility(View.GONE); + frameLayout.addView(tapToVideoTooltip, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 19, 0, 19, 0)); + + encryptionTooltip = new VoIpHintView(context, HintView2.DIRECTION_TOP, backgroundProvider, false) + .setMultilineText(true) + .setTextAlign(Layout.Alignment.ALIGN_CENTER) + .setDuration(4000) + .setHideByTouch(true) + .setMaxWidth(320) + .useScale(true) + .setInnerPadding(10, 6, 10, 6) + .setRounding(8); + encryptionTooltip.setText(LocaleController.getString("VoipHintEncryptionKey", R.string.VoipHintEncryptionKey)); + frameLayout.addView(encryptionTooltip, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); updateViewState(); @@ -1020,6 +1183,105 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent return frameLayout; } + private void runAcceptCallAnimation(final Runnable after) { + if (bottomVideoBtn.getVisibility() == View.VISIBLE) { + int[] loc = new int[2]; + acceptDeclineView.getLocationOnScreen(loc); + //callingUserPhotoView.switchToCallConnected(loc[0] + AndroidUtilities.dp(82), loc[1] + AndroidUtilities.dp(74)); + acceptDeclineView.stopAnimations(); + after.run(); + return; + } + + bottomEndCallBtn.animate().cancel(); + bottomSpeakerBtn.animate().cancel(); + bottomMuteBtn.animate().cancel(); + bottomVideoBtn.animate().cancel(); + int[] loc = new int[2]; + acceptDeclineView.getLocationOnScreen(loc); + acceptDeclineView.stopAnimations(); + //callingUserPhotoView.switchToCallConnected(loc[0] + AndroidUtilities.dp(82), loc[1] + AndroidUtilities.dp(74)); + bottomEndCallBtn.setData(R.drawable.calls_decline, Color.WHITE, 0xFFF01D2C, LocaleController.getString("VoipEndCall2", R.string.VoipEndCall2), false, false); + bottomSpeakerBtn.setType(VoIpSwitchLayout.Type.SPEAKER, false); + bottomMuteBtn.setType(VoIpSwitchLayout.Type.MICRO, false); + bottomVideoBtn.setType(VoIpSwitchLayout.Type.VIDEO, true); + bottomEndCallBtn.setVisibility(View.VISIBLE); + bottomSpeakerBtn.setVisibility(View.VISIBLE); + bottomMuteBtn.setVisibility(View.VISIBLE); + bottomVideoBtn.setVisibility(View.VISIBLE); + bottomEndCallBtn.setAlpha(0f); + bottomSpeakerBtn.setAlpha(0f); + bottomMuteBtn.setAlpha(0f); + bottomVideoBtn.setAlpha(0f); + final ViewGroup.MarginLayoutParams lp = ((ViewGroup.MarginLayoutParams) acceptDeclineView.getLayoutParams()); + final int startMargin = lp.getMarginEnd(); + final int endMargin = AndroidUtilities.dp(52); + final int endMarginFinal = AndroidUtilities.dp(24); + final int transitionY = AndroidUtilities.dp(62); + + AnimatorSet animatorSet = new AnimatorSet(); + ValueAnimator marginAnimator = ValueAnimator.ofFloat(0f, 1f); + marginAnimator.addUpdateListener(valueAnimator -> { + float percent = (float) valueAnimator.getAnimatedValue(); + float diff = transitionY * percent; + acceptDeclineView.setTranslationY(diff); + diff = startMargin - ((startMargin + endMarginFinal) * percent); + lp.leftMargin = (int) diff; + lp.rightMargin = (int) diff; + acceptDeclineView.requestLayout(); + }); + final int totalDuration = 400; + ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(acceptDeclineView, View.SCALE_X, acceptDeclineView.getScaleX(), 1f, 1f, 1f); + ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(acceptDeclineView, View.SCALE_Y, acceptDeclineView.getScaleY(), 1f, 1f, 1f); + ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(acceptDeclineView, View.ALPHA, acceptDeclineView.getAlpha(), acceptDeclineView.getAlpha(), 0f, 0f); + animatorSet.playTogether(marginAnimator, scaleXAnimator, scaleYAnimator, alphaAnimator); + animatorSet.setDuration(totalDuration); + animatorSet.setInterpolator(new LinearInterpolator()); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + after.run(); + acceptDeclineView.setScaleX(1.15f); + acceptDeclineView.setScaleY(1.15f); + final ViewGroup.MarginLayoutParams lp = ((ViewGroup.MarginLayoutParams) acceptDeclineView.getLayoutParams()); + lp.leftMargin = AndroidUtilities.dp(10); + lp.rightMargin = AndroidUtilities.dp(10); + acceptDeclineView.setVisibility(View.GONE); + } + }); + animatorSet.start(); + + AndroidUtilities.runOnUIThread(() -> { + int[] location = new int[2]; + acceptDeclineView.getLocationOnScreen(location); + int rootX = location[0]; + int rootY = location[1]; + bottomSpeakerBtn.getLocationOnScreen(location); + bottomSpeakerBtn.setTranslationX(rootX - location[0] + AndroidUtilities.dp(42)); + bottomSpeakerBtn.setTranslationY(rootY - location[1] + AndroidUtilities.dp(44)); + bottomMuteBtn.getLocationOnScreen(location); + bottomMuteBtn.setTranslationX(rootX - location[0] + AndroidUtilities.dp(42)); + bottomMuteBtn.setTranslationY(rootY - location[1] + AndroidUtilities.dp(44)); + bottomVideoBtn.getLocationOnScreen(location); + bottomVideoBtn.setTranslationX(rootX - location[0] + AndroidUtilities.dp(42)); + bottomVideoBtn.setTranslationY(rootY - location[1] + AndroidUtilities.dp(44)); + bottomEndCallBtn.getLocationOnScreen(location); + bottomEndCallBtn.setTranslationX(rootX + acceptDeclineView.getWidth() - location[0] - AndroidUtilities.dp(49) - AndroidUtilities.dp(60)); + bottomEndCallBtn.setTranslationY(rootY - location[1] + AndroidUtilities.dp(44)); + + bottomEndCallBtn.setAlpha(1f); + bottomSpeakerBtn.setAlpha(1f); + bottomMuteBtn.setAlpha(1f); + bottomVideoBtn.setAlpha(1f); + + int halfDuration = totalDuration / 2; + bottomEndCallBtn.animate().setStartDelay(0).translationY(0f).setInterpolator(new LinearInterpolator()).translationX(0f).setDuration(halfDuration).start(); + bottomSpeakerBtn.animate().setStartDelay(0).translationY(0f).setInterpolator(new LinearInterpolator()).translationX(0f).setDuration(halfDuration).start(); + bottomMuteBtn.animate().setStartDelay(0).translationY(0f).setInterpolator(new LinearInterpolator()).translationX(0f).setDuration(halfDuration).start(); + bottomVideoBtn.animate().setStartDelay(0).translationY(0f).setInterpolator(new LinearInterpolator()).translationX(0f).setDuration(halfDuration).start(); + }, totalDuration / 3); + } + private boolean checkPointerIds(MotionEvent ev) { if (ev.getPointerCount() < 2) { return false; @@ -1110,9 +1372,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent isFinished = true; if (VoIPService.getSharedInstance() != null) { int h = instance.windowView.getMeasuredHeight(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { - h -= instance.lastInsets.getSystemWindowInsetBottom(); - } VoIPPiPView.show(instance.activity, instance.currentAccount, instance.windowView.getMeasuredWidth(), h, VoIPPiPView.ANIMATION_ENTER_TYPE_TRANSITION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { VoIPPiPView.topInset = instance.lastInsets.getSystemWindowInsetTop(); @@ -1186,7 +1445,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent topShadow.setAlpha(0f); speakerPhoneIcon.setAlpha(0f); notificationsLayout.setAlpha(0f); - callingUserPhotoView.setAlpha(0f); currentUserCameraFloatingLayout.switchingToPip = true; AndroidUtilities.runOnUIThread(() -> { @@ -1201,7 +1459,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent bottomShadow.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); topShadow.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); notificationsLayout.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - callingUserPhotoView.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); animator.addListener(new AnimatorListenerAdapter() { @Override @@ -1285,12 +1542,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserTextureView.setTranslationX(callingUserToX); callingUserTextureView.setTranslationY(callingUserToY); callingUserTextureView.setRoundCorners(AndroidUtilities.dp(6) * 1f / callingUserToScale); - - callingUserPhotoView.setAlpha(0f); - callingUserPhotoView.setScaleX(callingUserToScale); - callingUserPhotoView.setScaleY(callingUserToScale); - callingUserPhotoView.setTranslationX(callingUserToX); - callingUserPhotoView.setTranslationY(callingUserToY); } ValueAnimator animator = ValueAnimator.ofFloat(enter ? 1f : 0, enter ? 0 : 1f); @@ -1327,11 +1578,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent currentUserTextureView.setScreenshareMiniProgress(v, false); } windowView.invalidate(); - callingUserPhotoView.setScaleX(callingUserScale); - callingUserPhotoView.setScaleY(callingUserScale); - callingUserPhotoView.setTranslationX(tx); - callingUserPhotoView.setTranslationY(ty); - callingUserPhotoView.setAlpha(1f - v); }); return animator; } @@ -1342,56 +1588,88 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } emojiExpanded = expanded; if (expanded) { - AndroidUtilities.runOnUIThread(hideUIRunnable); + if (SharedConfig.callEncryptionHintDisplayedCount < 2) { + SharedConfig.incrementCallEncryptionHintDisplayed(2); + } + encryptionTooltip.hide(); + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); hideUiRunnableWaiting = false; - float s1 = emojiLayout.getMeasuredWidth(); - float s2 = windowView.getMeasuredWidth() - AndroidUtilities.dp(128); - float scale = s2 / s1; - emojiLayout.animate().scaleX(scale).scaleY(scale) - .translationY(windowView.getHeight() / 2f - emojiLayout.getBottom()) - .setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT) - .setDuration(250) - .start(); - emojiRationalTextView.animate().setListener(null).cancel(); - if (emojiRationalTextView.getVisibility() != View.VISIBLE) { - emojiRationalTextView.setVisibility(View.VISIBLE); - emojiRationalTextView.setAlpha(0f); - } - emojiRationalTextView.animate().alpha(1f).setDuration(150).start(); - overlayBackground.animate().setListener(null).cancel(); - if (overlayBackground.getVisibility() != View.VISIBLE) { - overlayBackground.setVisibility(View.VISIBLE); - overlayBackground.setAlpha(0f); - overlayBackground.setShowBlackout(currentUserIsVideo || callingUserIsVideo, false); + if (callingUserPhotoViewMini.getVisibility() == View.VISIBLE) { + callingUserPhotoViewMini.animate().setStartDelay(0).translationY(AndroidUtilities.dp(48)).scaleY(0.1f).scaleX(0.1f).alpha(0f).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } - overlayBackground.animate().alpha(1f).setDuration(150).start(); + + hideEmojiLayout.animate().setListener(null).cancel(); + hideEmojiLayout.setVisibility(View.VISIBLE); + hideEmojiLayout.setAlpha(0f); + hideEmojiLayout.setScaleX(0.3f); + hideEmojiLayout.setScaleY(0.3f); + hideEmojiLayout.animate().alpha(1f).scaleY(1f).scaleX(1f).setDuration(340).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + + emojiLayout.animate().scaleX(1.72f).scaleY(1.72f) + .translationY(AndroidUtilities.dp(140)) + .setInterpolator(CubicBezierInterpolator.DEFAULT) + .setDuration(400) + .start(); + + emojiRationalLayout.animate().setListener(null).cancel(); + emojiRationalLayout.setVisibility(View.VISIBLE); + emojiRationalLayout.setTranslationY(-AndroidUtilities.dp(120)); + emojiRationalLayout.setScaleX(0.7f); + emojiRationalLayout.setScaleY(0.7f); + emojiRationalLayout.setAlpha(0f); + emojiRationalLayout.animate().alpha(1f).translationY(0).scaleX(1f).scaleY(1f).setDuration(400).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + for (BackupImageView emojiView : emojiViews) { + if (emojiView.animatedEmojiDrawable != null && emojiView.animatedEmojiDrawable.getImageReceiver() != null) { + emojiView.animatedEmojiDrawable.getImageReceiver().setAllowStartAnimation(true); + emojiView.animatedEmojiDrawable.getImageReceiver().startAnimation(); + } + } + } + }).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } else { + if (callingUserPhotoViewMini.getVisibility() == View.VISIBLE) { + callingUserPhotoViewMini.animate().setStartDelay(50).translationY(0).scaleX(1f).scaleY(1f).alpha(1f).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } + + hideEmojiLayout.animate().setListener(null).cancel(); + hideEmojiLayout.animate().alpha(0f).scaleY(0.3f).scaleX(0.3f).setDuration(230).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new HideViewAfterAnimation(hideEmojiLayout)).start(); + emojiLayout.animate().scaleX(1f).scaleY(1f) .translationY(0) .setInterpolator(CubicBezierInterpolator.DEFAULT) - .setDuration(150) + .setDuration(280) .start(); - if (emojiRationalTextView.getVisibility() != View.GONE) { - emojiRationalTextView.animate().alpha(0).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - VoIPService service = VoIPService.getSharedInstance(); - if (canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) { - AndroidUtilities.runOnUIThread(hideUIRunnable, 3000); - hideUiRunnableWaiting = true; + emojiRationalLayout.animate().setListener(null).cancel(); + emojiRationalLayout.animate().alpha(0f).scaleY(0.7f).scaleX(0.7f).translationY(-AndroidUtilities.dp(120)).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + startWaitingFoHideUi(); + for (BackupImageView emojiView : emojiViews) { + if (emojiView.animatedEmojiDrawable != null && emojiView.animatedEmojiDrawable.getImageReceiver() != null) { + emojiView.animatedEmojiDrawable.getImageReceiver().setAllowStartAnimation(false); + emojiView.animatedEmojiDrawable.getImageReceiver().stopAnimation(); } - emojiRationalTextView.setVisibility(View.GONE); } - }).setDuration(150).start(); + emojiRationalLayout.setVisibility(View.GONE); + } + }).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } + previousState = currentState; + updateViewState(); + } - overlayBackground.animate().alpha(0).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - overlayBackground.setVisibility(View.GONE); - } - }).setDuration(150).start(); + private void startWaitingFoHideUi() { + VoIPService service = VoIPService.getSharedInstance(); + if (service != null) { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; + if (canHideUI && uiVisible) { + AndroidUtilities.runOnUIThread(hideUIRunnable, 3000); + hideUiRunnableWaiting = true; } } } @@ -1405,26 +1683,19 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent boolean showAcceptDeclineView = false; boolean showTimer = false; boolean showReconnecting = false; - boolean showCallingAvatarMini = false; int statusLayoutOffset = 0; - VoIPService service = VoIPService.getSharedInstance(); + final VoIPService service = VoIPService.getSharedInstance(); switch (currentState) { case VoIPService.STATE_WAITING_INCOMING: showAcceptDeclineView = true; - lockOnScreen = true; - statusLayoutOffset = AndroidUtilities.dp(24); + lockOnScreen = false; acceptDeclineView.setRetryMod(false); if (service != null && service.privateCall.video) { - if (currentUserIsVideo && callingUser.photo != null) { - showCallingAvatarMini = true; - } else { - showCallingAvatarMini = false; - } - statusTextView.setText(LocaleController.getString("VoipInVideoCallBranding", R.string.VoipInVideoCallBranding), true, animated); + statusTextView.setText(LocaleController.getString("VoipInVideoCallBranding", R.string.VoipInVideoCallBranding), false, animated); acceptDeclineView.setTranslationY(-AndroidUtilities.dp(60)); } else { - statusTextView.setText(LocaleController.getString("VoipInCallBranding", R.string.VoipInCallBranding), true, animated); + statusTextView.setText(LocaleController.getString("VoipInCallBranding", R.string.VoipInCallBranding), false, animated); acceptDeclineView.setTranslationY(0); } break; @@ -1433,13 +1704,17 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent statusTextView.setText(LocaleController.getString("VoipConnecting", R.string.VoipConnecting), true, animated); break; case VoIPService.STATE_EXCHANGING_KEYS: - statusTextView.setText(LocaleController.getString("VoipExchangingKeys", R.string.VoipExchangingKeys), true, animated); + if (previousState != VoIPService.STATE_EXCHANGING_KEYS) { + statusTextView.setText(LocaleController.getString("VoipExchangingKeys", R.string.VoipExchangingKeys), true, animated); + } break; case VoIPService.STATE_WAITING: statusTextView.setText(LocaleController.getString("VoipWaiting", R.string.VoipWaiting), true, animated); break; case VoIPService.STATE_RINGING: - statusTextView.setText(LocaleController.getString("VoipRinging", R.string.VoipRinging), true, animated); + if (previousState != VoIPService.STATE_RINGING) { + statusTextView.setText(LocaleController.getString("VoipRinging", R.string.VoipRinging), true, animated); + } break; case VoIPService.STATE_REQUESTING: statusTextView.setText(LocaleController.getString("VoipRequesting", R.string.VoipRequesting), true, animated); @@ -1456,14 +1731,96 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent case VoIPService.STATE_ESTABLISHED: case VoIPService.STATE_RECONNECTING: updateKeyView(animated); - showTimer = true; if (currentState == VoIPService.STATE_RECONNECTING) { - showReconnecting = true; + showReconnecting = wasEstablished; + if (!wasEstablished && previousState != VoIPService.STATE_RECONNECTING) { + statusTextView.setText(LocaleController.getString("VoipConnecting", R.string.VoipConnecting), true, animated); + } + } else { + wasEstablished = true; + showTimer = true; } break; case VoIPService.STATE_ENDED: + boolean hasRate = service != null && service.hasRate(); currentUserTextureView.saveCameraLastBitmap(); - AndroidUtilities.runOnUIThread(() -> windowView.finish(), 200); + if (hasRate && !isFinished) { + final boolean uiVisibleLocal = uiVisible; + if (uiVisibleLocal) { + int[] locEndCall = new int[2]; + int w = AndroidUtilities.displaySize.x; + bottomEndCallBtn.getLocationOnScreen(locEndCall); + int marginCloseBtn = w - locEndCall[0] - (((bottomEndCallBtn.getMeasuredWidth() - AndroidUtilities.dp(52)) / 2)) - AndroidUtilities.dp(52); + ViewGroup.MarginLayoutParams lpCloseBtn = (ViewGroup.MarginLayoutParams) endCloseLayout.getLayoutParams(); + lpCloseBtn.rightMargin = marginCloseBtn; + lpCloseBtn.leftMargin = marginCloseBtn; + endCloseLayout.setTranslationY(locEndCall[1]); + endCloseLayout.setAlpha(1f); + endCloseLayout.setLayoutParams(lpCloseBtn); + buttonsLayout.animate().alpha(0f).setDuration(80).start(); + AndroidUtilities.runOnUIThread(() -> endCloseLayout.switchToClose(v -> { + AndroidUtilities.runOnUIThread(() -> windowView.finish()); + if (selectedRating > 0) { + service.sendCallRating(selectedRating); + } + }, true), 2); + } else { + buttonsLayout.setVisibility(View.GONE); + FrameLayout.LayoutParams lpCloseBtn = (FrameLayout.LayoutParams) endCloseLayout.getLayoutParams(); + lpCloseBtn.rightMargin = AndroidUtilities.dp(18); + lpCloseBtn.leftMargin = AndroidUtilities.dp(18); + lpCloseBtn.bottomMargin = AndroidUtilities.dp(36); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && lastInsets != null) { + lpCloseBtn.bottomMargin += lastInsets.getSystemWindowInsetBottom(); + } + lpCloseBtn.gravity = Gravity.BOTTOM; + endCloseLayout.setLayoutParams(lpCloseBtn); + endCloseLayout.animate().alpha(1f).setDuration(250).start(); + endCloseLayout.switchToClose(v -> { + AndroidUtilities.runOnUIThread(() -> windowView.finish()); + if (selectedRating > 0) { + service.sendCallRating(selectedRating); + } + }, false); + } + + rateCallLayout.setVisibility(View.VISIBLE); + rateCallLayout.show(count -> selectedRating = count); + if (emojiExpanded) { + emojiExpanded = false; + hideEmojiLayout.animate().alpha(0f).scaleY(0.3f).scaleX(0.3f).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new HideViewAfterAnimation(hideEmojiLayout)).start(); + emojiLayout.animate().scaleX(1f).scaleY(1f).translationY(0).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(250).start(); + emojiRationalLayout.animate().alpha(0f).scaleY(0.7f).scaleX(0.7f).translationY(-AndroidUtilities.dp(120)).setListener(new HideViewAfterAnimation(hideEmojiLayout)).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } + for (BackupImageView emojiView : emojiViews) { + emojiView.animate().alpha(0f).scaleX(0f).scaleY(0f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(250).start(); + } + callingUserTitle.animate().alpha(0f).setDuration(70).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + callingUserTitle.setText(LocaleController.getString("VoipCallEnded", R.string.VoipCallEnded)); + callingUserTitle.animate().alpha(1f).setDuration(70).setListener(null).start(); + } + }).start(); + speakerPhoneIcon.animate().alpha(0f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(250).start(); + speakerPhoneIcon.setVisibility(View.GONE); + statusTextView.showReconnect(false, true); + statusTextView.showBadConnection(false, true); + statusTextView.setDrawCallIcon(); + callingUserPhotoViewMini.onNeedRating(); + updateButtons(true); + bottomEndCallBtn.setVisibility(View.INVISIBLE); + callingUserMiniFloatingLayout.setAlpha(0f); + callingUserMiniFloatingLayout.setVisibility(View.GONE); + currentUserCameraFloatingLayout.setAlpha(0f); + currentUserCameraFloatingLayout.setVisibility(View.GONE); + if (previewDialog != null) { + previewDialog.dismiss(false, false); + } + notificationsLayout.animate().alpha(0f).setDuration(250).start(); + } else { + AndroidUtilities.runOnUIThread(() -> windowView.finish(), 200); + } break; case VoIPService.STATE_FAILED: statusTextView.setText(LocaleController.getString("VoipFailed", R.string.VoipFailed), false, animated); @@ -1533,6 +1890,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent return; } + boolean wasVideo = callingUserIsVideo || currentUserIsVideo; if (service != null) { callingUserIsVideo = service.getRemoteVideoState() == Instance.VIDEO_STATE_ACTIVE; currentUserIsVideo = service.getVideoState(false) == Instance.VIDEO_STATE_ACTIVE || service.getVideoState(false) == Instance.VIDEO_STATE_PAUSED; @@ -1548,7 +1906,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (callingUserIsVideo) { if (!switchingToPip) { - callingUserPhotoView.setAlpha(1f); + gradientLayout.setAlpha(1f); } if (animated) { callingUserTextureView.animate().alpha(1f).setDuration(250).start(); @@ -1562,10 +1920,9 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } if (currentUserIsVideo || callingUserIsVideo) { - fillNavigationBar(true, animated); + gradientLayout.setVisibility(View.INVISIBLE); } else { - fillNavigationBar(false, animated); - callingUserPhotoView.setVisibility(View.VISIBLE); + gradientLayout.setVisibility(View.VISIBLE); if (animated) { callingUserTextureView.animate().alpha(0f).setDuration(250).start(); } else { @@ -1580,8 +1937,8 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent boolean showCallingUserVideoMini = currentUserIsVideo && cameraForceExpanded; - showCallingUserAvatarMini(showCallingAvatarMini, animated); - statusLayoutOffset += callingUserPhotoViewMini.getTag() == null ? 0 : AndroidUtilities.dp(135) + AndroidUtilities.dp(12); + showCallingUserAvatarMini(animated, wasVideo); + statusLayoutOffset = callingUserPhotoViewMini.getTag() == null ? 0 : AndroidUtilities.dp(135) + AndroidUtilities.dp(12); showAcceptDeclineView(showAcceptDeclineView, animated); windowView.setLockOnScreen(lockOnScreen || deviceIsLocked); canHideUI = (currentState == VoIPService.STATE_ESTABLISHED) && (currentUserIsVideo || callingUserIsVideo); @@ -1589,26 +1946,24 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent showUi(true); } - if (uiVisible && canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) { + if (uiVisible && canHideUI && !hideUiRunnableWaiting && service != null) { AndroidUtilities.runOnUIThread(hideUIRunnable, 3000); hideUiRunnableWaiting = true; - } else if (service != null && service.isMicMute()) { - AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); - hideUiRunnableWaiting = false; - } - if (!uiVisible) { - statusLayoutOffset -= AndroidUtilities.dp(50); } if (animated) { - if (lockOnScreen || !uiVisible) { - if (backIcon.getVisibility() != View.VISIBLE) { - backIcon.setVisibility(View.VISIBLE); - backIcon.setAlpha(0f); - } - backIcon.animate().alpha(0f).start(); + if (currentState == VoIPService.STATE_ENDED) { + backIcon.animate().alpha(0f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(250).start(); } else { - backIcon.animate().alpha(1f).start(); + if (lockOnScreen || !uiVisible) { + if (backIcon.getVisibility() != View.VISIBLE) { + backIcon.setVisibility(View.VISIBLE); + backIcon.setAlpha(0f); + } + backIcon.animate().alpha(0f).start(); + } else { + backIcon.animate().alpha(1f).start(); + } } notificationsLayout.animate().translationY(-AndroidUtilities.dp(16) - (uiVisible ? AndroidUtilities.dp(80) : 0)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } else { @@ -1629,16 +1984,40 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent statusTextView.showReconnect(showReconnecting, animated); + if (callingUserPhotoViewMini.getVisibility() == View.VISIBLE && emojiExpanded) { + statusLayoutOffset += AndroidUtilities.dp(24); + Layout layout = emojiRationalTextView.getLayout(); + if (layout != null) { + int lines = layout.getLineCount(); + if (lines > 2) { + statusLayoutOffset += AndroidUtilities.dp(20) * (lines - 2); + } + } + } + + if (currentState == VoIPService.STATE_ENDED && (!currentUserIsVideo && !callingUserIsVideo)) { + statusLayoutOffset -= AndroidUtilities.dp(24); + } + + if (currentUserIsVideo || callingUserIsVideo) { + statusLayoutOffset -= AndroidUtilities.dp(60); + } + if (animated) { + if (emojiExpanded && (currentUserIsVideo || callingUserIsVideo)) { + statusLayout.animate().setStartDelay(0).alpha(0f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } else { + statusLayout.animate().setStartDelay(250).alpha(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } if (statusLayoutOffset != statusLayoutAnimateToOffset) { - statusLayout.animate().translationY(statusLayoutOffset).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + statusLayout.animate().setStartDelay(currentState == VoIPService.STATE_ENDED ? 250 : 0).translationY(statusLayoutOffset).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } } else { statusLayout.setTranslationY(statusLayoutOffset); } statusLayoutAnimateToOffset = statusLayoutOffset; - overlayBackground.setShowBlackout(currentUserIsVideo || callingUserIsVideo, animated); - canSwitchToPip = (currentState != VoIPService.STATE_ENDED && currentState != VoIPService.STATE_BUSY) && (currentUserIsVideo || callingUserIsVideo); + boolean isScreencast = service != null && service.isScreencast(); + canSwitchToPip = (currentState != VoIPService.STATE_ENDED && currentState != VoIPService.STATE_BUSY) && ((currentUserIsVideo && !isScreencast) || callingUserIsVideo); int floatingViewsOffset; if (service != null) { @@ -1652,20 +2031,25 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (animated) { notificationsLayout.beforeLayoutChanges(); } + if (service.isMicMute()) { + notificationsLayout.addNotification(R.drawable.calls_mute_mini, LocaleController.getString(R.string.VoipMyMicrophoneState), "self-muted", animated); + } else { + notificationsLayout.removeNotification("self-muted"); + } if ((currentUserIsVideo || callingUserIsVideo) && (currentState == VoIPService.STATE_ESTABLISHED || currentState == VoIPService.STATE_RECONNECTING) && service.getCallDuration() > 500) { if (service.getRemoteAudioState() == Instance.AUDIO_STATE_MUTED) { - notificationsLayout.addNotification(R.drawable.calls_mute_mini, LocaleController.formatString("VoipUserMicrophoneIsOff", R.string.VoipUserMicrophoneIsOff, UserObject.getFirstName(callingUser)), "muted", animated); + notificationsLayout.addNotification(R.drawable.calls_mute_mini, LocaleController.formatString("VoipUserMicrophoneIsOff", R.string.VoipUserMicrophoneIsOff, notificationsLayout.ellipsize(UserObject.getFirstName(callingUser))), "muted", animated); } else { notificationsLayout.removeNotification("muted"); } if (service.getRemoteVideoState() == Instance.VIDEO_STATE_INACTIVE) { - notificationsLayout.addNotification(R.drawable.calls_camera_mini, LocaleController.formatString("VoipUserCameraIsOff", R.string.VoipUserCameraIsOff, UserObject.getFirstName(callingUser)), "video", animated); + notificationsLayout.addNotification(R.drawable.calls_camera_mini, LocaleController.formatString("VoipUserCameraIsOff", R.string.VoipUserCameraIsOff, notificationsLayout.ellipsize(UserObject.getFirstName(callingUser))), "video", animated); } else { notificationsLayout.removeNotification("video"); } } else { if (service.getRemoteAudioState() == Instance.AUDIO_STATE_MUTED) { - notificationsLayout.addNotification(R.drawable.calls_mute_mini, LocaleController.formatString("VoipUserMicrophoneIsOff", R.string.VoipUserMicrophoneIsOff, UserObject.getFirstName(callingUser)), "muted", animated); + notificationsLayout.addNotification(R.drawable.calls_mute_mini, LocaleController.formatString("VoipUserMicrophoneIsOff", R.string.VoipUserMicrophoneIsOff, notificationsLayout.ellipsize(UserObject.getFirstName(callingUser))), "muted", animated); } else { notificationsLayout.removeNotification("muted"); } @@ -1674,7 +2058,9 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (notificationsLayout.getChildCount() == 0 && callingUserIsVideo && service.privateCall != null && !service.privateCall.video && !service.sharedUIParams.tapToVideoTooltipWasShowed) { service.sharedUIParams.tapToVideoTooltipWasShowed = true; - tapToVideoTooltip.showForView(bottomButtons[1], true); + tapToVideoTooltip.setTranslationY(-(fragmentView.getMeasuredHeight() - buttonsLayout.getY() + AndroidUtilities.dp(6))); + tapToVideoTooltip.setJointPx(0, buttonsLayout.getX() + bottomVideoBtn.getX() + AndroidUtilities.dp(14)); + tapToVideoTooltip.show(); } else if (notificationsLayout.getChildCount() != 0) { tapToVideoTooltip.hide(); } @@ -1710,7 +2096,14 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserMiniFloatingLayout.setScaleY(0.5f); } callingUserMiniFloatingLayout.animate().setListener(null).cancel(); - callingUserMiniFloatingLayout.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).setStartDelay(150).start(); + callingUserMiniFloatingLayout.isAppearing = true; + callingUserMiniFloatingLayout.animate() + .alpha(1f).scaleX(1f).scaleY(1f) + .setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).setStartDelay(150) + .withEndAction(() -> { + callingUserMiniFloatingLayout.isAppearing = false; + callingUserMiniFloatingLayout.invalidate(); + }).start(); callingUserMiniFloatingLayout.setTag(1); } else if (!showCallingUserVideoMini && callingUserMiniFloatingLayout.getTag() != null) { callingUserMiniFloatingLayout.setIsActive(false); @@ -1729,29 +2122,42 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserMiniFloatingLayout.restoreRelativePosition(); updateSpeakerPhoneIcon(); - } - private void fillNavigationBar(boolean fill, boolean animated) { - if (switchingToPip) { - return; - } - if (!animated) { - if (naviagtionBarAnimator != null) { - naviagtionBarAnimator.cancel(); + if (currentState == VoIPService.STATE_ESTABLISHED) { + callingUserPhotoViewMini.onConnected(); + if (!gradientLayout.isConnectedCalled()) { + int[] loc = new int[2]; + callingUserPhotoViewMini.getLocationOnScreen(loc); + boolean animatedSwitch = previousState != -1; + gradientLayout.switchToCallConnected(loc[0] + AndroidUtilities.dp(106), loc[1] + AndroidUtilities.dp(106), animatedSwitch); } - fillNaviagtionBarValue = fill ? 1 : 0; - overlayBottomPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * (fill ? 1f : 0.5f)))); - } else if (fill != fillNaviagtionBar) { - if (naviagtionBarAnimator != null) { - naviagtionBarAnimator.cancel(); - } - naviagtionBarAnimator = ValueAnimator.ofFloat(fillNaviagtionBarValue, fill ? 1 : 0); - naviagtionBarAnimator.addUpdateListener(navigationBarAnimationListener); - naviagtionBarAnimator.setDuration(300); - naviagtionBarAnimator.setInterpolator(new LinearInterpolator()); - naviagtionBarAnimator.start(); } - fillNaviagtionBar = fill; + boolean isVideoMode = currentUserIsVideo || callingUserIsVideo; + voIpSnowView.setState(isVideoMode); + backgroundProvider.setHasVideo(isVideoMode); + + if (callingUserIsVideo && !wasVideo && isNearEar) { + isNearEar = false; + if (service != null) { + service.playStartRecordSound(); + } + } + + if (!isVideoMode) { + if (topShadow.getVisibility() != View.INVISIBLE) { + topShadow.setVisibility(View.INVISIBLE); + bottomShadow.setVisibility(View.INVISIBLE); + } + } else { + if (topShadow.getVisibility() != View.VISIBLE) { + topShadow.setVisibility(View.VISIBLE); + bottomShadow.setVisibility(View.VISIBLE); + } + } + AndroidUtilities.cancelRunOnUIThread(stopAnimatingBgRunnable); + if (currentState == VoIPService.STATE_ESTABLISHED) { + AndroidUtilities.runOnUIThread(stopAnimatingBgRunnable, 10000); + } } private void showUi(boolean show) { @@ -1759,12 +2165,15 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent uiVisibilityAnimator.cancel(); } + int notificationsLayoutStartDelay = 0; if (!show && uiVisible) { - speakerPhoneIcon.animate().alpha(0).translationY(-AndroidUtilities.dp(50)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - backIcon.animate().alpha(0).translationY(-AndroidUtilities.dp(50)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - emojiLayout.animate().alpha(0).translationY(-AndroidUtilities.dp(50)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - statusLayout.animate().alpha(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - buttonsLayout.animate().alpha(0).translationY(AndroidUtilities.dp(50)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + notificationsLayoutStartDelay = 150; + speakerPhoneIcon.animate().alpha(0).translationY(-AndroidUtilities.dp(10)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + backIcon.animate().alpha(0).translationY(-AndroidUtilities.dp(10)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + emojiLayout.animate().alpha(0).translationY(-AndroidUtilities.dp(10)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + callingUserTitle.animate().alpha(0).setDuration(150).translationY(-AndroidUtilities.dp(10)).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + statusTextView.animate().alpha(0).setDuration(150).translationY(-AndroidUtilities.dp(10)).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + buttonsLayout.animate().alpha(0).translationY(AndroidUtilities.dp(10)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); bottomShadow.animate().alpha(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); topShadow.animate().alpha(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); uiVisibilityAnimator = ValueAnimator.ofFloat(uiVisibilityAlpha, 0); @@ -1774,12 +2183,15 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); hideUiRunnableWaiting = false; buttonsLayout.setEnabled(false); + encryptionTooltip.hide(); } else if (show && !uiVisible) { tapToVideoTooltip.hide(); + encryptionTooltip.hide(); + callingUserTitle.animate().alpha(1f).setDuration(150).translationY(0).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + statusTextView.animate().alpha(1f).setDuration(150).translationY(0).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); speakerPhoneIcon.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); backIcon.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); emojiLayout.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - statusLayout.animate().alpha(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); buttonsLayout.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); bottomShadow.animate().alpha(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); topShadow.animate().alpha(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); @@ -1792,7 +2204,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent uiVisible = show; windowView.requestFullscreen(!show); - notificationsLayout.animate().translationY(-AndroidUtilities.dp(16) - (uiVisible ? AndroidUtilities.dp(80) : 0)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + notificationsLayout.animate().translationY(-AndroidUtilities.dp(16) - (uiVisible ? AndroidUtilities.dp(80) : 0)).setDuration(150).setStartDelay(notificationsLayoutStartDelay).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); } private void showFloatingLayout(int state, boolean animated) { @@ -1877,17 +2289,33 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent currentUserCameraFloatingLayout.setTag(state); } - private void showCallingUserAvatarMini(boolean show, boolean animated) { + private void showCallingUserAvatarMini(boolean animated, boolean wasVideo) { + boolean noVideo = !currentUserIsVideo && !callingUserIsVideo; if (animated) { - if (show && callingUserPhotoViewMini.getTag() == null) { + if (noVideo && callingUserPhotoViewMini.getTag() == null) { callingUserPhotoViewMini.animate().setListener(null).cancel(); callingUserPhotoViewMini.setVisibility(View.VISIBLE); - callingUserPhotoViewMini.setAlpha(0); - callingUserPhotoViewMini.setTranslationY(-AndroidUtilities.dp(135)); - callingUserPhotoViewMini.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); - } else if (!show && callingUserPhotoViewMini.getTag() != null) { + if (!emojiExpanded) { + if (wasVideo) { + callingUserPhotoViewMini.setAlpha(0f); + callingUserPhotoViewMini.animate().alpha(1f).translationY(0).scaleY(1f).scaleX(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } else { + callingUserPhotoViewMini.setAlpha(0); + callingUserPhotoViewMini.setTranslationY(-AndroidUtilities.dp(135)); + callingUserPhotoViewMini.animate().alpha(1f).translationY(0).scaleY(1f).scaleX(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } + } else { + if (wasVideo) { + callingUserPhotoViewMini.setAlpha(0f); + callingUserPhotoViewMini.setTranslationY(AndroidUtilities.dp(48)); + callingUserPhotoViewMini.setScaleX(0.1f); + callingUserPhotoViewMini.setScaleY(0.1f); + } + } + } else if (!noVideo && callingUserPhotoViewMini.getTag() != null) { callingUserPhotoViewMini.animate().setListener(null).cancel(); - callingUserPhotoViewMini.animate().alpha(0).translationY(-AndroidUtilities.dp(135)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT) + callingUserPhotoViewMini.setTranslationY(0); + callingUserPhotoViewMini.animate().alpha(0).setDuration(150).scaleX(0.1f).scaleY(0.1f).setInterpolator(CubicBezierInterpolator.DEFAULT) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -1899,9 +2327,11 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent callingUserPhotoViewMini.animate().setListener(null).cancel(); callingUserPhotoViewMini.setTranslationY(0); callingUserPhotoViewMini.setAlpha(1f); - callingUserPhotoViewMini.setVisibility(show ? View.VISIBLE : View.GONE); + callingUserPhotoViewMini.setScaleX(1f); + callingUserPhotoViewMini.setScaleY(1f); + callingUserPhotoViewMini.setVisibility(noVideo ? View.VISIBLE : View.GONE); } - callingUserPhotoViewMini.setTag(show ? 1 : null); + callingUserPhotoViewMini.setTag(noVideo ? 1 : null); } private void updateKeyView(boolean animated) { @@ -1926,18 +2356,39 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } byte[] sha256 = Utilities.computeSHA256(auth_key, 0, auth_key.length); String[] emoji = EncryptionKeyEmojifier.emojifyForCall(sha256); + + List documents = new ArrayList<>(); + List drawables = new ArrayList<>(); for (int i = 0; i < 4; i++) { Emoji.preloadEmoji(emoji[i]); Emoji.EmojiDrawable drawable = Emoji.getEmojiDrawable(emoji[i]); if (drawable != null) { - drawable.setBounds(0, 0, AndroidUtilities.dp(22), AndroidUtilities.dp(22)); + drawable.setBounds(0, 0, AndroidUtilities.dp(40), AndroidUtilities.dp(40)); drawable.preload(); - emojiViews[i].setImageDrawable(drawable); - emojiViews[i].setContentDescription(emoji[i]); + int[] emojiOnly = new int[1]; + TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + paint.setTextSize(AndroidUtilities.dp(28)); + CharSequence txt = emoji[i]; + txt = Emoji.replaceEmoji(txt, paint.getFontMetricsInt(), false, emojiOnly); + TLRPC.Document doc1 = replaceEmojiToLottieFrame(txt, emojiOnly); + drawables.add(drawable); + if (doc1 != null) { + documents.add(doc1); + } emojiViews[i].setVisibility(View.GONE); } emojiDrawables[i] = drawable; } + if (documents.size() == 4) { + for (int i = 0; i < documents.size(); i++) { + emojiViews[i].setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_EMOJI_CALL, currentAccount, documents.get(i))); + emojiViews[i].getImageReceiver().clearImage(); + } + } else { + for (int i = 0; i < drawables.size(); i++) { + emojiViews[i].setImageDrawable(drawables.get(i)); + } + } checkEmojiLoaded(animated); } @@ -1957,11 +2408,19 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent emojiViews[i].setVisibility(View.VISIBLE); if (animated) { emojiViews[i].setAlpha(0f); - emojiViews[i].setTranslationY(AndroidUtilities.dp(30)); - emojiViews[i].animate().alpha(1f).translationY(0f).setDuration(200).setStartDelay(20 * i).start(); + emojiViews[i].setScaleX(0f); + emojiViews[i].setScaleY(0f); + emojiViews[i].animate().alpha(1f).scaleX(1f).scaleY(1f).setInterpolator(CubicBezierInterpolator.EASE_OUT_BACK).setDuration(250).start(); } } } + encryptionTooltip.postDelayed(() -> { + if (SharedConfig.callEncryptionHintDisplayedCount < 2) { + SharedConfig.incrementCallEncryptionHintDisplayed(1); + encryptionTooltip.setTranslationY(emojiLayout.getY() + AndroidUtilities.dp(36)); + encryptionTooltip.show(); + } + }, 1000); } } @@ -2002,91 +2461,123 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent Visibility visibility = new Visibility() { @Override public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { - ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, AndroidUtilities.dp(100), 0); + PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, AndroidUtilities.dp(100), 0); + PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0f, 1f); + PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat(View.SCALE_X, 0f, 1f); + ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3); if (view instanceof VoIPToggleButton) { view.setTranslationY(AndroidUtilities.dp(100)); + view.setScaleX(0f); + view.setScaleY(0f); animator.setStartDelay(((VoIPToggleButton) view).animationDelay); } + if (view instanceof VoIpSwitchLayout) { + view.setTranslationY(AndroidUtilities.dp(100)); + view.setScaleX(0f); + view.setScaleY(0f); + animator.setStartDelay(((VoIpSwitchLayout) view).animationDelay); + } return animator; } @Override public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { - return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, view.getTranslationY(), AndroidUtilities.dp(100)); + PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, view.getTranslationY(), AndroidUtilities.dp(100)); + PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat(View.SCALE_Y, view.getScaleY(), 0f); + PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat(View.SCALE_X, view.getScaleX(), 0f); + return ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3); } }; transitionSet - .addTransition(visibility.setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT)) - .addTransition(new ChangeBounds().setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT)); + .addTransition(visibility.setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT)) + .addTransition(new ChangeBounds().setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT)); transitionSet.excludeChildren(VoIPToggleButton.class, true); + transitionSet.excludeChildren(VoIpSwitchLayout.class, true); TransitionManager.beginDelayedTransition(buttonsLayout, transitionSet); } + if (currentState == VoIPService.STATE_ENDED) { + bottomSpeakerBtn.setVisibility(View.GONE); + bottomVideoBtn.setVisibility(View.GONE); + bottomMuteBtn.setVisibility(View.GONE); + bottomEndCallBtn.setVisibility(View.GONE); + return; + } + if (currentState == VoIPService.STATE_WAITING_INCOMING || currentState == VoIPService.STATE_BUSY) { if (service.privateCall != null && service.privateCall.video && currentState == VoIPService.STATE_WAITING_INCOMING) { if (!service.isScreencast() && (currentUserIsVideo || callingUserIsVideo)) { - setFrontalCameraAction(bottomButtons[0], service, animated); + setFrontalCameraAction(bottomSpeakerBtn, service, animated); if (uiVisible) { speakerPhoneIcon.animate().alpha(1f).start(); } } else { - setSpeakerPhoneAction(bottomButtons[0], service, animated); + setSpeakerPhoneAction(bottomSpeakerBtn, service, animated); speakerPhoneIcon.animate().alpha(0).start(); } - setVideoAction(bottomButtons[1], service, animated); - setMicrophoneAction(bottomButtons[2], service, animated); + setVideoAction(bottomVideoBtn, service, false); + setMicrohoneAction(bottomMuteBtn, service, animated); } else { - bottomButtons[0].setVisibility(View.GONE); - bottomButtons[1].setVisibility(View.GONE); - bottomButtons[2].setVisibility(View.GONE); + bottomSpeakerBtn.setVisibility(View.GONE); + bottomVideoBtn.setVisibility(View.GONE); + bottomMuteBtn.setVisibility(View.GONE); } - bottomButtons[3].setVisibility(View.GONE); + bottomEndCallBtn.setVisibility(View.GONE); } else { if (instance == null) { return; } if (!service.isScreencast() && (currentUserIsVideo || callingUserIsVideo)) { - setFrontalCameraAction(bottomButtons[0], service, animated); + setFrontalCameraAction(bottomSpeakerBtn, service, animated); if (uiVisible) { speakerPhoneIcon.setTag(1); speakerPhoneIcon.animate().alpha(1f).start(); } } else { - setSpeakerPhoneAction(bottomButtons[0], service, animated); + setSpeakerPhoneAction(bottomSpeakerBtn, service, animated); speakerPhoneIcon.setTag(null); speakerPhoneIcon.animate().alpha(0f).start(); } - setVideoAction(bottomButtons[1], service, animated); - setMicrophoneAction(bottomButtons[2], service, animated); + setVideoAction(bottomVideoBtn, service, false); + setMicrohoneAction(bottomMuteBtn, service, animated); - bottomButtons[3].setData(R.drawable.calls_decline, Color.WHITE, 0xFFF01D2C, LocaleController.getString("VoipEndCall", R.string.VoipEndCall), false, animated); - bottomButtons[3].setOnClickListener(view -> { + bottomEndCallBtn.setData(R.drawable.calls_decline, Color.WHITE, 0xFFF01D2C, LocaleController.getString("VoipEndCall2", R.string.VoipEndCall2), false, animated); + bottomEndCallBtn.setOnClickListener(view -> { if (VoIPService.getSharedInstance() != null) { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; VoIPService.getSharedInstance().hangUp(); } }); } int animationDelay = 0; - for (int i = 0; i < 4; i++) { - if (bottomButtons[i].getVisibility() == View.VISIBLE) { - bottomButtons[i].animationDelay = animationDelay; - animationDelay += 16; - } + if (bottomSpeakerBtn.getVisibility() == View.VISIBLE) { + bottomSpeakerBtn.animationDelay = animationDelay; + animationDelay += 16; + } + if (bottomVideoBtn.getVisibility() == View.VISIBLE) { + bottomVideoBtn.animationDelay = animationDelay; + animationDelay += 16; + } + if (bottomMuteBtn.getVisibility() == View.VISIBLE) { + bottomMuteBtn.animationDelay = animationDelay; + animationDelay += 16; + } + if (bottomEndCallBtn.getVisibility() == View.VISIBLE) { + bottomEndCallBtn.animationDelay = animationDelay; } updateSpeakerPhoneIcon(); } - private void setMicrophoneAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { - if (service.isMicMute()) { - bottomButton.setData(R.drawable.calls_unmute, Color.BLACK, Color.WHITE, LocaleController.getString("VoipUnmute", R.string.VoipUnmute), true, animated); - } else { - bottomButton.setData(R.drawable.calls_unmute, Color.WHITE, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipMute", R.string.VoipMute), false, animated); - } + private void setMicrohoneAction(VoIpSwitchLayout bottomButton, VoIPService service, boolean animated) { + bottomButton.setType(VoIpSwitchLayout.Type.MICRO, service.isMicMute()); currentUserCameraFloatingLayout.setMuted(service.isMicMute(), animated); - bottomButton.setOnClickListener(view -> { + bottomButton.setOnBtnClickedListener((view) -> { final VoIPService serviceInstance = VoIPService.getSharedInstance(); if (serviceInstance != null) { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; final boolean micMute = !serviceInstance.isMicMute(); if (accessibilityManager.isTouchExplorationEnabled()) { final String text; @@ -2104,7 +2595,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent }); } - private void setVideoAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { + private void setVideoAction(VoIpSwitchLayout bottomButton, VoIPService service, boolean fast) { boolean isVideoAvailable; if (currentUserIsVideo || callingUserIsVideo) { isVideoAvailable = true; @@ -2113,12 +2604,17 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } if (isVideoAvailable) { if (currentUserIsVideo) { - bottomButton.setData(service.isScreencast() ? R.drawable.calls_sharescreen : R.drawable.calls_video, Color.WHITE, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipStopVideo", R.string.VoipStopVideo), false, animated); + if (service.isScreencast()) { + bottomButton.setType(VoIpSwitchLayout.Type.VIDEO, false, fast); + } else { + bottomButton.setType(VoIpSwitchLayout.Type.VIDEO, false, fast); + } } else { - bottomButton.setData(R.drawable.calls_video, Color.BLACK, Color.WHITE, LocaleController.getString("VoipStartVideo", R.string.VoipStartVideo), true, animated); + bottomButton.setType(VoIpSwitchLayout.Type.VIDEO, true, fast); } - bottomButton.setCrossOffset(-AndroidUtilities.dpf2(3.5f)); - bottomButton.setOnClickListener(view -> { + bottomButton.setOnBtnClickedListener(view -> { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, 102); } else { @@ -2138,7 +2634,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent }); bottomButton.setEnabled(true); } else { - bottomButton.setData(R.drawable.calls_video, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.5f)), ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), "Video", false, animated); + bottomButton.setType(VoIpSwitchLayout.Type.VIDEO, true); bottomButton.setOnClickListener(null); bottomButton.setEnabled(false); } @@ -2149,9 +2645,10 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (service == null) { return; } + VoipAudioManager vam = VoipAudioManager.get(); if (service.isBluetoothOn()) { speakerPhoneIcon.setImageResource(R.drawable.calls_bluetooth); - } else if (service.isSpeakerphoneOn()) { + } else if (vam.isSpeakerphoneOn()) { speakerPhoneIcon.setImageResource(R.drawable.calls_speaker); } else { if (service.isHeadsetPlugged()) { @@ -2162,42 +2659,47 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } } - private void setSpeakerPhoneAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { + private void setSpeakerPhoneAction(VoIpSwitchLayout bottomButton, VoIPService service, boolean animated) { + final int selectedSpeaker; + VoipAudioManager vam = VoipAudioManager.get(); if (service.isBluetoothOn()) { - bottomButton.setData(R.drawable.calls_bluetooth, Color.WHITE, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipAudioRoutingBluetooth", R.string.VoipAudioRoutingBluetooth), false, animated); - bottomButton.setChecked(false, animated); - } else if (service.isSpeakerphoneOn()) { - bottomButton.setData(R.drawable.calls_speaker, Color.BLACK, Color.WHITE, LocaleController.getString("VoipSpeaker", R.string.VoipSpeaker), false, animated); - bottomButton.setChecked(true, animated); + selectedSpeaker = 2; + bottomButton.setType(VoIpSwitchLayout.Type.BLUETOOTH, false); + } else if (vam.isSpeakerphoneOn()) { + selectedSpeaker = 0; + bottomButton.setType(VoIpSwitchLayout.Type.SPEAKER, true); } else { - bottomButton.setData(R.drawable.calls_speaker, Color.WHITE, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipSpeaker", R.string.VoipSpeaker), false, animated); - bottomButton.setChecked(false, animated); + selectedSpeaker = 1; + bottomButton.setType(VoIpSwitchLayout.Type.SPEAKER, false); } - bottomButton.setCheckableForAccessibility(true); bottomButton.setEnabled(true); - bottomButton.setOnClickListener(view -> { + bottomButton.setOnBtnClickedListener(view -> { if (VoIPService.getSharedInstance() != null) { - VoIPService.getSharedInstance().toggleSpeakerphoneOrShowRouteSheet(activity, false); + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; + VoIPService.getSharedInstance().toggleSpeakerphoneOrShowRouteSheet(activity, false, selectedSpeaker); + setSpeakerPhoneAction(bottomButton, service, true); } }); } - private void setFrontalCameraAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { + private void setFrontalCameraAction(VoIpSwitchLayout bottomButton, VoIPService service, boolean animated) { if (!currentUserIsVideo) { - bottomButton.setData(R.drawable.calls_flip, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.5f)), ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipFlip", R.string.VoipFlip), false, animated); - bottomButton.setOnClickListener(null); + bottomButton.setType(VoIpSwitchLayout.Type.CAMERA, false); + bottomButton.setOnBtnClickedListener(null); bottomButton.setEnabled(false); } else { bottomButton.setEnabled(true); - if (!service.isFrontFaceCamera()) { - bottomButton.setData(R.drawable.calls_flip, Color.BLACK, Color.WHITE, LocaleController.getString("VoipFlip", R.string.VoipFlip), false, animated); + if (service.isFrontFaceCamera()) { + bottomButton.setType(VoIpSwitchLayout.Type.CAMERA, !service.isSwitchingCamera()); } else { - bottomButton.setData(R.drawable.calls_flip, Color.WHITE, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipFlip", R.string.VoipFlip), false, animated); + bottomButton.setType(VoIpSwitchLayout.Type.CAMERA, service.isSwitchingCamera()); } - - bottomButton.setOnClickListener(view -> { + bottomButton.setOnBtnClickedListener(view -> { final VoIPService serviceInstance = VoIPService.getSharedInstance(); if (serviceInstance != null) { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; if (accessibilityManager.isTouchExplorationEnabled()) { final String text; if (service.isFrontFaceCamera()) { @@ -2207,6 +2709,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent } view.announceForAccessibility(text); } + bottomButton.setType(VoIpSwitchLayout.Type.CAMERA, !service.isFrontFaceCamera()); serviceInstance.switchCamera(); } }); @@ -2240,7 +2743,9 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent service.switchCamera(); } windowView.setLockOnScreen(true); - previewDialog = new PrivateVideoPreviewDialog(fragmentView.getContext(), false, true) { + int[] locVideoButton = new int[2]; + bottomVideoBtn.getLocationOnScreen(locVideoButton); + previewDialog = new PrivateVideoPreviewDialogNew(fragmentView.getContext(), locVideoButton[0], locVideoButton[1]) { @Override public void onDismiss(boolean screencast, boolean apply) { previewDialog = null; @@ -2251,6 +2756,10 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (service != null && !screencast) { service.requestVideoCall(false); service.setVideoState(false, Instance.VIDEO_STATE_ACTIVE); + service.switchToSpeaker(); + } + if (service != null) { + setVideoAction(bottomVideoBtn, service, true); } } else { if (service != null) { @@ -2260,6 +2769,34 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent previousState = currentState; updateViewState(); } + + @Override + protected void afterOpened() { + gradientLayout.lockDrawing = true; + gradientLayout.invalidate(); + } + + @Override + protected void beforeClosed() { + gradientLayout.lockDrawing = false; + gradientLayout.invalidate(); + } + + @Override + protected int[] getFloatingViewLocation() { + int[] loc = new int[2]; + int[] result = new int[3]; + currentUserCameraFloatingLayout.getLocationOnScreen(loc); + result[0] = loc[0]; + result[1] = loc[1]; + result[2] = currentUserCameraFloatingLayout.getMeasuredWidth(); + return result; + } + + @Override + protected boolean isHasVideoOnMainScreen() { + return callingUserIsVideo; + } }; if (lastInsets != null) { previewDialog.setBottomPadding(lastInsets.getSystemWindowInsetBottom()); @@ -2301,7 +2838,11 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent return; } if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - VoIPService.getSharedInstance().acceptIncomingCall(); + runAcceptCallAnimation(() -> { + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().acceptIncomingCall(); + } + }); } else { if (!activity.shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) { VoIPService.getSharedInstance().declineIncomingCall(); @@ -2361,9 +2902,6 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent if (canSwitchToPip && hasPermissionsToPip) { int h = instance.windowView.getMeasuredHeight(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { - h -= instance.lastInsets.getSystemWindowInsetBottom(); - } VoIPPiPView.show(instance.activity, instance.currentAccount, instance.windowView.getMeasuredWidth(), h, VoIPPiPView.ANIMATION_ENTER_TYPE_SCALE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && instance.lastInsets != null) { VoIPPiPView.topInset = instance.lastInsets.getSystemWindowInsetTop(); @@ -2419,4 +2957,22 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent }).show(); } } + + public TLRPC.Document replaceEmojiToLottieFrame(CharSequence text, int[] emojiOnly) { + if (!(text instanceof Spannable)) { + return null; + } + Spannable spannable = (Spannable) text; + Emoji.EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), Emoji.EmojiSpan.class); + AnimatedEmojiSpan[] aspans = spannable.getSpans(0, spannable.length(), AnimatedEmojiSpan.class); + + if (spans == null || (emojiOnly == null ? 0 : emojiOnly[0]) - spans.length - (aspans == null ? 0 : aspans.length) > 0) { + return null; + } + + for (Emoji.EmojiSpan span : spans) { + return MediaDataController.getInstance(currentAccount).getEmojiAnimatedSticker(span.emoji); + } + return null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoiceMessageEnterTransition.java b/TMessagesProj/src/main/java/org/telegram/ui/VoiceMessageEnterTransition.java index 7b17cdf7c..3ae3356b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoiceMessageEnterTransition.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoiceMessageEnterTransition.java @@ -147,30 +147,35 @@ public class VoiceMessageEnterTransition implements MessageEnterTransitionContai canvas.drawCircle(cx, cy, radius, circlePaint); canvas.save(); - float scale = radius / toRadius; canvas.scale(scale, scale, cx, cy); - canvas.translate(cx - messageView.getRadialProgress().getProgressRect().centerX(), cy - messageView.getRadialProgress().getProgressRect().centerY()); - + float tx = cx - messageView.getRadialProgress().getProgressRect().centerX(); + float ty = cy - messageView.getRadialProgress().getProgressRect().centerY(); + canvas.translate(tx, ty); messageView.getRadialProgress().setOverrideAlpha(progress); messageView.getRadialProgress().setDrawBackground(false); - messageView.getRadialProgress().draw(canvas); + messageView.drawVoiceOnce(canvas, progress, () -> { + messageView.getRadialProgress().draw(canvas); + canvas.translate(-tx, -ty); + canvas.scale(1f / scale, 1f / scale, cx, cy); + if (recordCircle != null) { + recordCircle.drawIcon(canvas, (int) fromCx, (int) fromCy, 1f - moveProgress); + } + canvas.scale(scale, scale, cx, cy); + canvas.translate(tx, ty); + }); messageView.getRadialProgress().setDrawBackground(true); messageView.getRadialProgress().setOverrideAlpha(1f); canvas.restore(); - if (container.getMeasuredHeight() > 0) { - gradientMatrix.setTranslate(0, clipBottom); - gradientShader.setLocalMatrix(gradientMatrix); +// if (container.getMeasuredHeight() > 0) { +// gradientMatrix.setTranslate(0, clipBottom); +// gradientShader.setLocalMatrix(gradientMatrix); // canvas.drawRect(0, clipBottom, container.getMeasuredWidth(), container.getMeasuredHeight(), gradientPaint); - } +// } //restore clipRect // canvas.restore(); - - if (recordCircle != null) { - recordCircle.drawIcon(canvas, (int) fromCx, (int) fromCy, 1f - moveProgress); - } } private int getThemedColor(int key) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java index ffcf9a5ee..15bd5296c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java @@ -96,6 +96,8 @@ public class WallpapersListActivity extends BaseFragment implements Notification private int resetSectionRow; private int resetRow; private int resetInfoRow; + private int galleryRow; + private int galleryHintRow; private int currentType; private final long dialogId; @@ -272,6 +274,15 @@ public class WallpapersListActivity extends BaseFragment implements Notification public final static int TYPE_ALL = 0; public final static int TYPE_COLOR = 1; + public final static int TYPE_CHANNEL_PATTERNS = 2; + public final static int TYPE_CHANNEL_CUSTOM = 3; + + public static class EmojiWallpaper { + public final String emoticon; + public EmojiWallpaper(String emoticon) { + this.emoticon = emoticon; + } + } public static class ColorWallpaper { @@ -418,7 +429,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification @Override public boolean onFragmentCreate() { - if (currentType == TYPE_ALL) { + if (currentType == TYPE_ALL || currentType == TYPE_CHANNEL_PATTERNS) { NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.wallpapersDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didSetNewWallpapper); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.wallpapersNeedReload); @@ -447,7 +458,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification @Override public void onFragmentDestroy() { - if (currentType == TYPE_ALL) { + if (currentType == TYPE_ALL || currentType == TYPE_CHANNEL_PATTERNS) { searchAdapter.onDestroy(); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.wallpapersDidLoad); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); @@ -473,7 +484,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new FileWallpaper("", file, file), bitmap); themePreviewActivity.setDialogId(dialogId); if (dialogId != 0) { - themePreviewActivity.setDelegate(WallpapersListActivity.this::removeSelfFromStack); + themePreviewActivity.setDelegate(wallPaper -> WallpapersListActivity.this.removeSelfFromStack()); } presentFragment(themePreviewActivity, gallery); } @@ -488,9 +499,11 @@ public class WallpapersListActivity extends BaseFragment implements Notification actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); if (currentType == TYPE_ALL) { - actionBar.setTitle(LocaleController.getString("ChatBackground", R.string.ChatBackground)); + actionBar.setTitle(LocaleController.getString(R.string.ChatBackground)); + } else if (currentType == TYPE_CHANNEL_PATTERNS) { + actionBar.setTitle("Channel Wallpaper"); } else if (currentType == TYPE_COLOR) { - actionBar.setTitle(LocaleController.getString("SelectColorTitle", R.string.SelectColorTitle)); + actionBar.setTitle(LocaleController.getString(R.string.SelectColorTitle)); } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -901,6 +914,9 @@ public class WallpapersListActivity extends BaseFragment implements Notification } private boolean onItemLongClick(WallpaperCell view, Object object, int index) { + if (currentType == TYPE_CHANNEL_PATTERNS || currentType == TYPE_CHANNEL_CUSTOM) { + return false; + } Object originalObject = object; if (object instanceof ColorWallpaper) { ColorWallpaper colorWallpaper = (ColorWallpaper) object; @@ -970,7 +986,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification } }; if (currentType == TYPE_COLOR || dialogId != 0) { - wallpaperActivity.setDelegate(WallpapersListActivity.this::removeSelfFromStack); + wallpaperActivity.setDelegate(wallPaper -> WallpapersListActivity.this.removeSelfFromStack()); } if (selectedBackgroundSlug.equals(slug)) { wallpaperActivity.setInitialModes(selectedBackgroundBlurred, selectedBackgroundMotion, selectedIntensity); @@ -1025,7 +1041,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification ArrayList arrayList = (ArrayList) args[0]; patterns.clear(); patternsDict.clear(); - if (currentType != TYPE_COLOR) { + if (currentType != TYPE_COLOR && currentType != TYPE_CHANNEL_PATTERNS) { wallPapers.clear(); localWallPapers.clear(); localDict.clear(); @@ -1045,7 +1061,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification patternsDict.put(wallPaper.document.id, wallPaper); } allWallPapersDict.put(wallPaper.slug, wallPaper); - if (currentType != TYPE_COLOR && (!wallPaper.pattern || wallPaper.settings != null && wallPaper.settings.background_color != 0)) { + if (currentType != TYPE_COLOR && (!wallPaper.pattern || wallPaper.settings != null && wallPaper.settings.background_color != 0) && (currentType != TYPE_CHANNEL_PATTERNS || wallPaper.pattern)) { if (!Theme.isCurrentThemeDark() && wallPaper.settings != null && wallPaper.settings.intensity < 0) { continue; } @@ -1124,7 +1140,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification TLRPC.TL_account_wallPapers res = (TLRPC.TL_account_wallPapers) response; patterns.clear(); patternsDict.clear(); - if (currentType != TYPE_COLOR) { + if (currentType != TYPE_COLOR && currentType != TYPE_CHANNEL_PATTERNS) { wallPapers.clear(); allWallPapersDict.clear(); allWallPapers.clear(); @@ -1142,7 +1158,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification patterns.add(wallPaper); patternsDict.put(wallPaper.document.id, wallPaper); } - if (currentType != TYPE_COLOR && (!wallPaper.pattern || wallPaper.settings != null && wallPaper.settings.background_color != 0)) { + if (currentType != TYPE_COLOR && (!wallPaper.pattern || wallPaper.settings != null && wallPaper.settings.background_color != 0) && (currentType != TYPE_CHANNEL_PATTERNS || wallPaper.pattern)) { if (!Theme.isCurrentThemeDark() && wallPaper.settings != null && wallPaper.settings.intensity < 0) { continue; } @@ -1179,7 +1195,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification } private void fillWallpapersWithCustom() { - if (currentType != TYPE_ALL) { + if (currentType != TYPE_ALL && currentType != TYPE_CHANNEL_PATTERNS) { return; } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -1374,10 +1390,20 @@ public class WallpapersListActivity extends BaseFragment implements Notification uploadImageRow = rowCount++; setColorRow = rowCount++; sectionRow = rowCount++; + galleryRow = -1; + galleryHintRow = -1; + } else if (currentType == TYPE_CHANNEL_PATTERNS) { + uploadImageRow = -1; + setColorRow = -1; + sectionRow = -1; + galleryRow = rowCount++; + galleryHintRow = rowCount++; } else { uploadImageRow = -1; setColorRow = -1; sectionRow = -1; + galleryRow = -1; + galleryHintRow = -1; } if (!wallPapers.isEmpty()) { totalWallpaperRows = (int) Math.ceil(wallPapers.size() / (float) columnsCount); @@ -1875,6 +1901,9 @@ public class WallpapersListActivity extends BaseFragment implements Notification textCell.setTextAndIcon(LocaleController.getString("SetColor", R.string.SetColor), R.drawable.msg_palette, true); } else if (position == resetRow) { textCell.setText(LocaleController.getString("ResetChatBackgrounds", R.string.ResetChatBackgrounds), false); + } else if (position == galleryRow) { + textCell.setTextAndIcon("Choose from gallery", R.drawable.msg_background, false); + textCell.setLockLevel(false, 10); } break; } @@ -1882,6 +1911,8 @@ public class WallpapersListActivity extends BaseFragment implements Notification TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; if (position == resetInfoRow) { cell.setText(LocaleController.getString("ResetChatBackgroundsInfo", R.string.ResetChatBackgroundsInfo)); + } else if (position == galleryHintRow) { + cell.setText("Upload your own background for the channel."); } break; } @@ -1956,11 +1987,11 @@ public class WallpapersListActivity extends BaseFragment implements Notification @Override public int getItemViewType(int position) { - if (position == uploadImageRow || position == setColorRow || position == resetRow) { + if (position == uploadImageRow || position == galleryRow || position == setColorRow || position == resetRow) { return 0; } else if (position == sectionRow || position == resetSectionRow) { return 1; - } else if (position == resetInfoRow) { + } else if (position == resetInfoRow || position == galleryHintRow) { return 3; } else { return 2; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_name.png new file mode 100644 index 000000000..662f51caf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_name.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_profile.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_profile.png new file mode 100644 index 000000000..dc3298392 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_cover.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_cover.png new file mode 100644 index 000000000..0f7e5f628 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_cover.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_custombg.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_custombg.png new file mode 100644 index 000000000..707a0f35e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_custombg.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links.png new file mode 100644 index 000000000..3758211e1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links2.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links2.png new file mode 100644 index 000000000..16e8585e1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_links2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_reactions.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_reactions.png new file mode 100644 index 000000000..aff27dbab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_reactions.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_status.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_status.png new file mode 100644 index 000000000..0b23197bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_stories.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_stories.png new file mode 100644 index 000000000..daeb0abfd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_stories.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_wallpaper.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_wallpaper.png new file mode 100644 index 000000000..1873851bb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_gift.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_gift.png new file mode 100644 index 000000000..ce511f8cf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_gift.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts.png new file mode 100644 index 000000000..019053596 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts3.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts3.png new file mode 100644 index 000000000..ac87d66d3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reposts3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_forward_story.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_forward_story.png new file mode 100644 index 000000000..46c001119 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_forward_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_bluetooth.png new file mode 100644 index 000000000..e467aa35d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_bluetooth.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_earpiece.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_earpiece.png new file mode 100644 index 000000000..846bd6949 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_earpiece.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize.png new file mode 100644 index 000000000..e0a9fd274 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize_shadow.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize_shadow.png new file mode 100644 index 000000000..409f662ea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_minimize_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_speaker.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_speaker.png new file mode 100644 index 000000000..9f0fdec20 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_speaker.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_name.png new file mode 100644 index 000000000..49a4e707a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_name.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_profile.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_profile.png new file mode 100644 index 000000000..dd4933933 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_cover.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_cover.png new file mode 100644 index 000000000..b43120dda Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_cover.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_custombg.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_custombg.png new file mode 100644 index 000000000..9ab59e359 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_custombg.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links.png new file mode 100644 index 000000000..b71a5e05a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links2.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links2.png new file mode 100644 index 000000000..07e4e8b6f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_links2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_reactions.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_reactions.png new file mode 100644 index 000000000..0952e8e4b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_reactions.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_status.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_status.png new file mode 100644 index 000000000..3db161145 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_stories.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_stories.png new file mode 100644 index 000000000..aafa5eefa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_stories.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_wallpaper.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_wallpaper.png new file mode 100644 index 000000000..2c8208d3f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_gift.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_gift.png new file mode 100644 index 000000000..02d9fa3e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_gift.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts.png new file mode 100644 index 000000000..2cecdc856 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts3.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts3.png new file mode 100644 index 000000000..e8c64ff62 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reposts3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_forward_story.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_forward_story.png new file mode 100644 index 000000000..a871596cf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_forward_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_bluetooth.png new file mode 100644 index 000000000..dae338222 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_bluetooth.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_earpiece.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_earpiece.png new file mode 100644 index 000000000..c4ed82f91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_earpiece.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize.png new file mode 100644 index 000000000..c1a2ff8c9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize_shadow.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize_shadow.png new file mode 100644 index 000000000..3075eb64f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_minimize_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_speaker.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_speaker.png new file mode 100644 index 000000000..8a16c35f2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_speaker.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_name.png new file mode 100644 index 000000000..e0e0b64b2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_name.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_profile.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_profile.png new file mode 100644 index 000000000..c323be696 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_cover.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_cover.png new file mode 100644 index 000000000..1998d60f1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_cover.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_custombg.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_custombg.png new file mode 100644 index 000000000..1ce9d9c8a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_custombg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links.png new file mode 100644 index 000000000..2bf1895d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links2.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links2.png new file mode 100644 index 000000000..6f7f64799 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_links2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_reactions.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_reactions.png new file mode 100644 index 000000000..4203ca32d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_reactions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_status.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_status.png new file mode 100644 index 000000000..cb4008be7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_stories.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_stories.png new file mode 100644 index 000000000..ea5f32b63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_stories.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_wallpaper.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_wallpaper.png new file mode 100644 index 000000000..2c8ad96ea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_gift.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_gift.png new file mode 100644 index 000000000..ddec20589 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_gift.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts.png new file mode 100644 index 000000000..68b8b4279 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts3.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts3.png new file mode 100644 index 000000000..ebe9271c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reposts3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_forward_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_forward_story.png new file mode 100644 index 000000000..475754e90 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_forward_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_bluetooth.png new file mode 100644 index 000000000..9453e9f6e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_bluetooth.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_earpiece.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_earpiece.png new file mode 100644 index 000000000..252f23fa0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_earpiece.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize.png new file mode 100644 index 000000000..80a9cd3cb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize_shadow.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize_shadow.png new file mode 100644 index 000000000..90e845364 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_minimize_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_speaker.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_speaker.png new file mode 100644 index 000000000..88b012a68 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_speaker.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_name.png new file mode 100644 index 000000000..42c182487 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_name.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_profile.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_profile.png new file mode 100644 index 000000000..e7bd4f1d0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_cover.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_cover.png new file mode 100644 index 000000000..d330b2a1c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_cover.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_custombg.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_custombg.png new file mode 100644 index 000000000..3ecd90676 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_custombg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links.png new file mode 100644 index 000000000..f29163fb7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links2.png new file mode 100644 index 000000000..5727755e4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_links2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_reactions.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_reactions.png new file mode 100644 index 000000000..3950e404e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_reactions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_status.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_status.png new file mode 100644 index 000000000..07cdfec3d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_stories.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_stories.png new file mode 100644 index 000000000..9a7105fa9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_stories.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_wallpaper.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_wallpaper.png new file mode 100644 index 000000000..76661a8dc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_gift.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_gift.png new file mode 100644 index 000000000..5fd55a426 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_gift.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts.png new file mode 100644 index 000000000..c61144e18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts3.png new file mode 100644 index 000000000..d939853aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reposts3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_forward_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_forward_story.png new file mode 100644 index 000000000..0e4a9ac8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_forward_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_bluetooth.png new file mode 100644 index 000000000..dba97c207 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_bluetooth.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_earpiece.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_earpiece.png new file mode 100644 index 000000000..fb44e4cd1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_earpiece.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize.png new file mode 100644 index 000000000..6ca69d674 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize_shadow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize_shadow.png new file mode 100644 index 000000000..9ed27ff2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_minimize_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_speaker.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_speaker.png new file mode 100644 index 000000000..cb7dc121d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_speaker.png differ diff --git a/TMessagesProj/src/main/res/drawable/icon_2_background.xml b/TMessagesProj/src/main/res/drawable/icon_2_background.xml index d1440713e..279e6595b 100644 --- a/TMessagesProj/src/main/res/drawable/icon_2_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_2_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_2_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_2_background_round.xml index 5a8cc155f..be67c4790 100644 --- a/TMessagesProj/src/main/res/drawable/icon_2_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_2_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_2_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_2_background_sa.png deleted file mode 100644 index 424fc20ae..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_2_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_3_background.xml b/TMessagesProj/src/main/res/drawable/icon_3_background.xml index d00445b9d..249080bb1 100644 --- a/TMessagesProj/src/main/res/drawable/icon_3_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_3_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_3_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_3_background_round.xml index 3e2c38cff..b0d5d41e7 100644 --- a/TMessagesProj/src/main/res/drawable/icon_3_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_3_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_3_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_3_background_sa.png deleted file mode 100644 index 72b85d15d..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_3_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_3_background_sa.xml b/TMessagesProj/src/main/res/drawable/icon_3_background_sa.xml new file mode 100644 index 000000000..314f0a65f --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/icon_3_background_sa.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_4_background.xml b/TMessagesProj/src/main/res/drawable/icon_4_background.xml index b65238aa6..0e4598e96 100644 --- a/TMessagesProj/src/main/res/drawable/icon_4_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_4_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_4_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_4_background_round.xml index b2ccb6d31..b75253ac3 100644 --- a/TMessagesProj/src/main/res/drawable/icon_4_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_4_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_4_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_4_background_sa.png deleted file mode 100644 index f89e3fc0a..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_4_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_4_background_sa.xml b/TMessagesProj/src/main/res/drawable/icon_4_background_sa.xml new file mode 100644 index 000000000..133636088 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/icon_4_background_sa.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_5_background.xml b/TMessagesProj/src/main/res/drawable/icon_5_background.xml index 9df3154c3..25ea13714 100644 --- a/TMessagesProj/src/main/res/drawable/icon_5_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_5_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_5_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_5_background_round.xml index 7c2df592b..430c08476 100644 --- a/TMessagesProj/src/main/res/drawable/icon_5_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_5_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_5_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_5_background_sa.png deleted file mode 100644 index 862664b5e..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_5_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_5_background_sa.xml b/TMessagesProj/src/main/res/drawable/icon_5_background_sa.xml new file mode 100644 index 000000000..353fba3a7 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/icon_5_background_sa.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_6_background.xml b/TMessagesProj/src/main/res/drawable/icon_6_background.xml index 2630ccb36..749c55699 100644 --- a/TMessagesProj/src/main/res/drawable/icon_6_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_6_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_6_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_6_background_round.xml index deab3c4cb..c0765ce06 100644 --- a/TMessagesProj/src/main/res/drawable/icon_6_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_6_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_6_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_6_background_sa.png deleted file mode 100644 index 6e3cfe2d8..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_6_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_6_background_sa.xml b/TMessagesProj/src/main/res/drawable/icon_6_background_sa.xml new file mode 100644 index 000000000..d5756c752 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/icon_6_background_sa.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_background.xml b/TMessagesProj/src/main/res/drawable/icon_background.xml index 27feec428..a2d43618a 100644 --- a/TMessagesProj/src/main/res/drawable/icon_background.xml +++ b/TMessagesProj/src/main/res/drawable/icon_background.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_background_round.xml b/TMessagesProj/src/main/res/drawable/icon_background_round.xml index 444b6f188..4de8cca77 100644 --- a/TMessagesProj/src/main/res/drawable/icon_background_round.xml +++ b/TMessagesProj/src/main/res/drawable/icon_background_round.xml @@ -1,9 +1,5 @@ - - - - - - + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_background_sa.png b/TMessagesProj/src/main/res/drawable/icon_background_sa.png deleted file mode 100644 index 686a7d70e..000000000 Binary files a/TMessagesProj/src/main/res/drawable/icon_background_sa.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable/icon_background_sa.xml b/TMessagesProj/src/main/res/drawable/icon_background_sa.xml new file mode 100644 index 000000000..d3a1ae4cc --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/icon_background_sa.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/icon_plane.xml b/TMessagesProj/src/main/res/drawable/icon_plane.xml index acbeff5e6..8afd524eb 100644 --- a/TMessagesProj/src/main/res/drawable/icon_plane.xml +++ b/TMessagesProj/src/main/res/drawable/icon_plane.xml @@ -1,10 +1,10 @@ + android:width="90dp" + android:height="90dp" + android:viewportWidth="90" + android:viewportHeight="90"> [ + a.getAttribute('property') || a.getAttribute('name') || a.getAttribute('http-equiv'), + a.content + ]) + .concat([ + ['image', (document.querySelector('article[data-testid=tweet]:first-child div[data-testid=tweetPhoto] img') || {src:null}).src] + ]) + .filter(([k, v]) => k && v) +) \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/rate.json b/TMessagesProj/src/main/res/raw/rate.json new file mode 100644 index 000000000..eee84206d --- /dev/null +++ b/TMessagesProj/src/main/res/raw/rate.json @@ -0,0 +1 @@ +{"v":"5.10.1","fr":60,"ip":0,"op":90,"w":512,"h":512,"nm":"EFFECT_1","ddd":0,"assets":[{"id":"comp_0","nm":"placeholder_","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Star Copy 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.002,255.999,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[370,370,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.85,-0.59],[0,0],[1.56,2.27],[-0.43,1.45],[0,0],[0.83,0.63],[0,0],[-1.68,2.19],[-1.52,0.04],[0,0],[-0.34,0.98],[0,0],[-2.6,-0.92],[-0.5,-1.43],[0,0],[-1.04,-0.02],[0,0],[0.07,-2.76],[1.21,-0.92],[0,0],[-0.3,-0.99],[0,0],[2.65,-0.79],[1.24,0.86],[0,0]],"o":[[0,0],[-2.27,1.57],[-0.86,-1.25],[0,0],[0.3,-0.99],[0,0],[-2.19,-1.68],[0.92,-1.2],[0,0],[1.03,-0.02],[0,0],[0.92,-2.6],[1.43,0.5],[0,0],[0.35,0.98],[0,0],[2.76,0.07],[-0.03,1.52],[0,0],[-0.82,0.63],[0,0],[0.78,2.65],[-1.45,0.43],[0,0],[-0.86,-0.59]],"v":[[-1.418,22.006],[-14.768,31.206],[-21.718,29.936],[-22.398,25.666],[-17.768,10.126],[-18.648,7.426],[-31.528,-2.424],[-32.458,-9.434],[-28.608,-11.394],[-12.398,-11.794],[-10.108,-13.464],[-4.718,-28.754],[1.662,-31.804],[4.712,-28.754],[10.102,-13.464],[12.402,-11.794],[28.612,-11.394],[33.482,-6.274],[31.522,-2.424],[18.642,7.426],[17.772,10.126],[22.402,25.666],[19.032,31.886],[14.772,31.206],[1.422,22.006]],"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":[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":"Star Copy 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1440,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"star_4","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":20,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":17,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":14,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":11,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"star_1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":22,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":14.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":22,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.273,"s":[0]},{"t":20,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":6,"op":24,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":19,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":11.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":19,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.273,"s":[0]},{"t":17,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":14,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":21,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[79.087,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[116.913,96.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[98,115.413,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":16,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":8.7265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[98,96.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":16,"s":[98,77.587,0]}],"ix":2,"l":2},"a":{"a":0,"k":[209,-183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[75.652,75.652,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":[[209,-183.5],[209,-219.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.273,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":11,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":18,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"placeholder_1","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":39,"s":[100]},{"t":46.884765625,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.504,"y":0.922},"o":{"x":0.195,"y":0.205},"t":1,"s":[252.091,237.615,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.46,"y":1},"o":{"x":0.279,"y":0.04},"t":11,"s":[233.908,167.9,0],"to":[0,0,0],"ti":[0,0,0]},{"t":57,"s":[224.408,531.598,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":2,"s":[12,12,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[20,20,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":34,"s":[28,28,100]},{"t":45,"s":[4,4,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":1,"op":44,"st":-35,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"placeholder_2","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[100]},{"t":51,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.109,"y":0.548},"o":{"x":0.02,"y":0},"t":1,"s":[232.612,242.312,0],"to":[10.707,-41.715,0],"ti":[-38.374,0.791,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.474,"y":0.378},"t":11,"s":[301.744,107.351,0],"to":[43.367,-0.894,0],"ti":[-12.625,-246.426,0]},{"t":59,"s":[428.813,563.068,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":1,"s":[-8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[-14,14,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":41,"s":[-21,21,100]},{"t":50,"s":[-4,4,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":1,"op":47,"st":-119,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"placeholder_3","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":45,"s":[100]},{"t":53.8671875,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.417,"y":0.808},"o":{"x":0.137,"y":0.309},"t":2,"s":[230.521,219.86,0],"to":[-14.958,-20.45,0],"ti":[37.448,-4.406,0]},{"i":{"x":0.434,"y":1},"o":{"x":0.385,"y":0.212},"t":15,"s":[111.774,115.421,0],"to":[-42.843,5.041,0],"ti":[0,0,0]},{"t":71.47265625,"s":[33.914,525.091,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,-5]},"t":2,"s":[15,15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,6.583]},"o":{"x":[0.167,0.167,0.167],"y":[0.175,0.175,-3.333]},"t":40,"s":[24,24,100]},{"t":53,"s":[5,5,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":2,"op":51,"st":2,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"placeholder_4","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":53,"s":[100]},{"t":63,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.266,"y":0.874},"o":{"x":0.02,"y":0},"t":5,"s":[256.959,251.56,0],"to":[-18.201,-59.818,0],"ti":[35.75,1.133,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.556,"y":0.158},"t":17,"s":[193.976,78.891,0],"to":[-53.216,3.549,0],"ti":[0,0,0]},{"t":72,"s":[143.866,595.231,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[-12,12,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":51,"s":[-24,24,100]},{"t":61,"s":[-4,4,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":6,"op":59,"st":3,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"placeholder_5","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":58,"s":[100]},{"t":68.109375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.069,"y":0.731},"o":{"x":0.02,"y":0},"t":3,"s":[281.869,229.212,0],"to":[14.597,-73.616,0],"ti":[-41.626,1.096,0]},{"i":{"x":0.705,"y":1},"o":{"x":0.466,"y":0.207},"t":18,"s":[354.524,42.391,0],"to":[50.945,-1.349,0],"ti":[-11.393,-177.824,0]},{"t":74,"s":[450.127,531.605,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":3,"s":[8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[15,15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":55.842,"s":[20,20,100]},{"t":67,"s":[7,7,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":3,"op":65,"st":-1,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"placeholder_6","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":64,"s":[100]},{"t":75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.02,"y":0},"t":3,"s":[242.551,249.491,0],"to":[0,0,0],"ti":[-14.652,1.25,0]},{"i":{"x":0.767,"y":0.698},"o":{"x":0.43,"y":0},"t":19,"s":[252.146,35.091,0],"to":[15.073,-1.286,0],"ti":[0.606,-106.051,0]},{"t":77,"s":[280.793,601.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":5,"s":[-10,10,100]},{"i":{"x":[0.45,0.45,0.45],"y":[1,1,1]},"o":{"x":[0.27,0.27,0.27],"y":[0,0,0]},"t":60,"s":[-24,24,100]},{"t":73,"s":[-8,5,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":3,"op":70,"st":-88,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"placeholder_7","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":48,"s":[100]},{"t":58,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.109,"y":0.78},"o":{"x":0.02,"y":0},"t":6,"s":[251.612,222.312,0],"to":[5.707,-35.715,0],"ti":[-29.498,-0.693,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.474,"y":0.154},"t":17,"s":[287.744,95.351,0],"to":[38.182,0.896,0],"ti":[-12.625,-187.426,0]},{"t":65,"s":[354.813,543.068,0]}],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[14,14,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":48,"s":[17,17,100]},{"t":58,"s":[5,5,100]}],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":6,"op":54,"st":-42,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Points","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[100]},{"t":35,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-5]},{"t":35,"s":[0]}],"ix":10},"p":{"a":0,"k":[256.959,254.547,0],"ix":2,"l":2},"a":{"a":0,"k":[0.5,3.5,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.107,0.107,0.347],"y":[0,0,0]},"t":-2,"s":[9.8,9.8,100]},{"i":{"x":[0.708,0.708,0.479],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":9,"s":[25.2,25.2,100]},{"t":35,"s":[29.96,29.96,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.226,-9.469],[9.469,7.226],[-7.226,9.469],[-9.469,-7.226]],"o":[[-7.226,9.469],[-9.469,-7.226],[7.226,-9.469],[9.469,7.226]],"v":[[385.072,18.248],[354.843,22.31],[350.781,-7.919],[381.011,-11.981]],"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":[367.391,4.348],"ix":2},"a":{"a":0,"k":[367.391,4.348],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.317,0.317],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.496,0.496],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[11.805,-1.586],[1.586,11.805],[-11.805,1.586],[-1.586,-11.805]],"o":[[-11.805,1.586],[-1.586,-11.805],[11.805,-1.586],[1.586,11.805]],"v":[[261.231,286.312],[236.984,267.809],[255.487,243.561],[279.735,262.064]],"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":[256.522,264.13],"ix":2},"a":{"a":0,"k":[256.522,264.13],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.317,0.317],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.496,0.496],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"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":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.469,7.226],[-7.226,9.469],[-9.469,-7.226],[7.226,-9.469]],"o":[[-9.469,-7.226],[7.226,-9.469],[9.469,7.226],[-7.226,9.469]],"v":[[-14.927,388.164],[-18.989,357.934],[11.24,353.873],[15.302,384.102]],"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":[-4.348,370.652],"ix":2},"a":{"a":0,"k":[-4.348,370.652],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"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":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.586,11.805],[-11.805,1.586],[-1.586,-11.805],[11.805,-1.586]],"o":[[-1.586,-11.805],[11.805,-1.586],[1.586,11.805],[-11.805,1.586]],"v":[[-282.221,264.91],[-263.717,240.663],[-239.47,259.166],[-257.973,283.413]],"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":[-263.043,260.87],"ix":2},"a":{"a":0,"k":[-263.043,260.87],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"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":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.226,9.469],[-9.469,-7.226],[7.226,-9.469],[9.469,7.226]],"o":[[7.226,-9.469],[9.469,7.226],[-7.226,9.469],[-9.469,-7.226]],"v":[[-384.072,-11.248],[-353.843,-15.31],[-349.781,14.919],[-380.011,18.981]],"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":[-369.565,0],"ix":2},"a":{"a":0,"k":[-369.565,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.805,1.586],[-1.586,-11.805],[11.805,-1.586],[1.586,11.805]],"o":[[11.805,-1.586],[1.586,11.805],[-11.805,1.586],[-1.586,-11.805]],"v":[[-260.819,-278.542],[-236.571,-260.039],[-255.075,-235.791],[-279.322,-254.295]],"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":[-259.783,-258.696],"ix":2},"a":{"a":0,"k":[-259.783,-258.696],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-9.469,-7.226],[7.226,-9.469],[9.469,7.226],[-7.226,9.469]],"o":[[9.469,7.226],[-7.226,9.469],[-9.469,-7.226],[7.226,-9.469]],"v":[[15.927,-381.164],[19.989,-350.934],[-10.24,-346.873],[-14.302,-377.102]],"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,-365.217],"ix":2},"a":{"a":0,"k":[0,-365.217],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.586,-11.805],[11.805,-1.586],[1.586,11.805],[-11.805,1.586]],"o":[[1.586,11.805],[-11.805,1.586],[-1.586,-11.805],[11.805,-1.586]],"v":[[283.221,-257.91],[264.717,-233.663],[240.47,-252.166],[258.973,-276.413]],"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":[257.609,-254.348],"ix":2},"a":{"a":0,"k":[257.609,-254.348],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":-2,"s":[150,150]},{"i":{"x":[0.3,0.3],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[100,100]},{"t":35,"s":[40,40]}],"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 8","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":34,"st":-2,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Circle 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[100]},{"t":35,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[257,254.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-2.049,6.248,0],"ix":1,"l":2},"s":{"a":0,"k":[28,28,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.05,"y":0},"t":0,"s":[{"i":[[0,-17.536],[17.536,0],[0,17.536],[-17.536,0]],"o":[[0,17.536],[-17.536,0],[0,-17.536],[17.536,0]],"v":[[29.703,6.248],[-2.049,38],[-33.801,6.248],[-2.049,-25.504]],"c":true}]},{"t":35,"s":[{"i":[[0,-196.476],[196.476,0],[0,196.476],[-196.476,0]],"o":[[0,196.476],[-196.476,0],[0,-196.476],[196.476,0]],"v":[[353.703,6.248],[-2.049,362],[-357.801,6.248],[-2.049,-349.504]],"c":true}]}],"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":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.05],"y":[0]},"t":0,"s":[120]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[18]},{"t":35,"s":[6]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":34,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[380,318,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[34,34,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":72,"op":89,"st":72,"bm":0},{"ddd":0,"ind":11,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[196,436,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[47,47,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":69,"op":87,"st":69,"bm":0},{"ddd":0,"ind":12,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65,445,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[43,43,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":64,"op":82,"st":64,"bm":0},{"ddd":0,"ind":13,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[310,133,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[23,23,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":61,"op":79,"st":61,"bm":0},{"ddd":0,"ind":14,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[327,77,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[42,42,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":63,"op":81,"st":63,"bm":0},{"ddd":0,"ind":15,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[435,215,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[23,23,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":59,"op":77,"st":59,"bm":0},{"ddd":0,"ind":16,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[436,56,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[32,32,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":55,"op":73,"st":55,"bm":0},{"ddd":0,"ind":17,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[236,196,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[23,23,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":47,"op":65,"st":47,"bm":0},{"ddd":0,"ind":18,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[148,229,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[47,47,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":52,"op":70,"st":52,"bm":0},{"ddd":0,"ind":19,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63,368,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[29,29,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":50,"op":68,"st":50,"bm":0},{"ddd":0,"ind":20,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[315,429,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[29,29,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":48,"op":66,"st":48,"bm":0},{"ddd":0,"ind":21,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116,53,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[29,29,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":46,"op":64,"st":46,"bm":0},{"ddd":0,"ind":22,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[446,392,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[34,34,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":42,"op":60,"st":42,"bm":0},{"ddd":0,"ind":23,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[456,368,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[47,47,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":39,"op":57,"st":39,"bm":0},{"ddd":0,"ind":24,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[190,299,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[47,47,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":34,"op":52,"st":34,"bm":0},{"ddd":0,"ind":25,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[433,48,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[34,34,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":31,"op":49,"st":31,"bm":0},{"ddd":0,"ind":26,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[333,452,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[42,42,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":33,"op":51,"st":33,"bm":0},{"ddd":0,"ind":27,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[71,146,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[47,47,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":29,"op":47,"st":29,"bm":0},{"ddd":0,"ind":28,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102,64,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[33,33,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":26,"op":44,"st":26,"bm":0},{"ddd":0,"ind":29,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[123,360,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":15,"op":33,"st":15,"bm":0},{"ddd":0,"ind":30,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[231,153,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":18,"op":36,"st":18,"bm":0},{"ddd":0,"ind":31,"ty":0,"nm":"star_4","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[385,254,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[48,48,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":13,"op":31,"st":13,"bm":0},{"ddd":0,"ind":32,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[426,439,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[43,43,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":10,"op":28,"st":10,"bm":0},{"ddd":0,"ind":33,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[456,131,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[33,33,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":15,"op":33,"st":15,"bm":0},{"ddd":0,"ind":34,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[91,322,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[33,33,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":8,"op":26,"st":8,"bm":0},{"ddd":0,"ind":35,"ty":0,"nm":"star_1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[372,115,0],"ix":2,"l":2},"a":{"a":0,"k":[100,100,0],"ix":1,"l":2},"s":{"a":0,"k":[42,42,100],"ix":6,"l":2}},"ao":0,"w":200,"h":200,"ip":0,"op":18,"st":0,"bm":0},{"ddd":0,"ind":36,"ty":3,"nm":"NULL CONTROL 42","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":32,"ix":10},"p":{"a":0,"k":[403.775,95.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.632,79.632,100],"ix":6,"l":2}},"ao":0,"ip":36,"op":53,"st":-33,"bm":0},{"ddd":0,"ind":37,"ty":4,"nm":"Shape Layer 145","parent":36,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[0,0]},{"t":52,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[8]},{"t":52,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":42,"op":53,"st":25,"ct":1,"bm":0},{"ddd":0,"ind":38,"ty":4,"nm":"Shape Layer 144","parent":36,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[0,0]},{"t":49,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44,"s":[8]},{"t":49,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":39,"op":50,"st":22,"ct":1,"bm":0},{"ddd":0,"ind":39,"ty":4,"nm":"Shape Layer 143","parent":36,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[0,0]},{"t":46,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41,"s":[8]},{"t":46,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":47,"st":19,"ct":1,"bm":0},{"ddd":0,"ind":40,"ty":3,"nm":"NULL CONTROL 41","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":149,"ix":10},"p":{"a":0,"k":[170.775,405.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":69,"op":86,"st":0,"bm":0},{"ddd":0,"ind":41,"ty":4,"nm":"Shape Layer 142","parent":40,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[0,0]},{"t":85,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[8]},{"t":85,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":75,"op":86,"st":58,"ct":1,"bm":0},{"ddd":0,"ind":42,"ty":4,"nm":"Shape Layer 141","parent":40,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[0,0]},{"t":82,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":77,"s":[8]},{"t":82,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":72,"op":83,"st":55,"ct":1,"bm":0},{"ddd":0,"ind":43,"ty":4,"nm":"Shape Layer 140","parent":40,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[0,0]},{"t":79,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":74,"s":[8]},{"t":79,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":69,"op":80,"st":52,"ct":1,"bm":0},{"ddd":0,"ind":44,"ty":3,"nm":"NULL CONTROL 40","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[361.667,296.006,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[64.144,64.144,100],"ix":6,"l":2}},"ao":0,"ip":56,"op":79,"st":3,"bm":0},{"ddd":0,"ind":45,"ty":4,"nm":"Shape Layer 139","parent":44,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[0,0]},{"t":78,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":69,"s":[20]},{"t":78,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":64,"op":79,"st":47,"ct":1,"bm":0},{"ddd":0,"ind":46,"ty":4,"nm":"Shape Layer 138","parent":44,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[0,0]},{"t":73,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":64,"s":[20]},{"t":73,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":59,"op":74,"st":42,"ct":1,"bm":0},{"ddd":0,"ind":47,"ty":4,"nm":"Shape Layer 137","parent":44,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[0,0]},{"t":70,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[20]},{"t":70,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":56,"op":71,"st":39,"ct":1,"bm":0},{"ddd":0,"ind":48,"ty":3,"nm":"NULL CONTROL 39","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-194,"ix":10},"p":{"a":0,"k":[104.849,283.658,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.053,79.053,100],"ix":6,"l":2}},"ao":0,"ip":49,"op":68,"st":7,"bm":0},{"ddd":0,"ind":49,"ty":4,"nm":"circles_water 60","parent":48,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[0,0]},{"t":67,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[8]},{"t":67,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":57,"op":68,"st":40,"ct":1,"bm":0},{"ddd":0,"ind":50,"ty":4,"nm":"circles_water 59","parent":48,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[0,0]},{"t":64,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59,"s":[8]},{"t":64,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":54,"op":65,"st":37,"ct":1,"bm":0},{"ddd":0,"ind":51,"ty":4,"nm":"circles_water 58","parent":48,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[0,0]},{"t":65,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":56,"s":[8]},{"t":65,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":51,"op":66,"st":34,"ct":1,"bm":0},{"ddd":0,"ind":52,"ty":4,"nm":"circles_water 57","parent":48,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[0,0]},{"t":59,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[8]},{"t":59,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":49,"op":60,"st":32,"ct":1,"bm":0},{"ddd":0,"ind":53,"ty":3,"nm":"NULL CONTROL 38","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-201,"ix":10},"p":{"a":0,"k":[161.993,160.558,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[109.232,109.232,100],"ix":6,"l":2}},"ao":0,"ip":39,"op":56,"st":-33,"bm":0},{"ddd":0,"ind":54,"ty":4,"nm":"Shape Layer 136","parent":53,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[0,0]},{"t":55,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50,"s":[8]},{"t":55,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":45,"op":56,"st":28,"ct":1,"bm":0},{"ddd":0,"ind":55,"ty":4,"nm":"Shape Layer 135","parent":53,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[0,0]},{"t":52,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[8]},{"t":52,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":42,"op":53,"st":25,"ct":1,"bm":0},{"ddd":0,"ind":56,"ty":4,"nm":"Shape Layer 134","parent":53,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[0,0]},{"t":49,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44,"s":[8]},{"t":49,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":39,"op":50,"st":22,"ct":1,"bm":0},{"ddd":0,"ind":57,"ty":3,"nm":"NULL CONTROL 37","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":28,"ix":10},"p":{"a":0,"k":[135.919,409.814,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[45.483,45.483,100],"ix":6,"l":2}},"ao":0,"ip":28,"op":51,"st":-25,"bm":0},{"ddd":0,"ind":58,"ty":4,"nm":"Shape Layer 133","parent":57,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[0,0]},{"t":50,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41,"s":[20]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":51,"st":19,"ct":1,"bm":0},{"ddd":0,"ind":59,"ty":4,"nm":"Shape Layer 132","parent":57,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[0,0]},{"t":45,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":36,"s":[20]},{"t":45,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":46,"st":14,"ct":1,"bm":0},{"ddd":0,"ind":60,"ty":4,"nm":"Shape Layer 131","parent":57,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[0,0]},{"t":42,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[20]},{"t":42,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":43,"st":11,"ct":1,"bm":0},{"ddd":0,"ind":61,"ty":3,"nm":"NULL CONTROL 36","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":104,"ix":10},"p":{"a":0,"k":[429.936,406.449,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[63.273,63.273,100],"ix":6,"l":2}},"ao":0,"ip":41,"op":62,"st":-1,"bm":0},{"ddd":0,"ind":62,"ty":4,"nm":"circles_water 56","parent":61,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50.334,"s":[0,0]},{"t":62,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":56.166,"s":[8]},{"t":62,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":49,"op":62,"st":32,"ct":1,"bm":0},{"ddd":0,"ind":63,"ty":4,"nm":"circles_water 55","parent":61,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46.834,"s":[0,0]},{"t":58.5,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52.666,"s":[8]},{"t":58.5,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":46,"op":59,"st":29,"ct":1,"bm":0},{"ddd":0,"ind":64,"ty":4,"nm":"circles_water 54","parent":61,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43.334,"s":[0,0]},{"t":59.666015625,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49.166,"s":[8]},{"t":59.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":43,"op":60,"st":26,"ct":1,"bm":0},{"ddd":0,"ind":65,"ty":4,"nm":"circles_water 53","parent":61,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[0,0]},{"t":52.666015625,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46.834,"s":[8]},{"t":52.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":41,"op":54,"st":24,"ct":1,"bm":0},{"ddd":0,"ind":66,"ty":3,"nm":"NULL CONTROL 35","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-6,"ix":10},"p":{"a":0,"k":[354.201,369.74,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[91.776,91.776,100],"ix":6,"l":2}},"ao":0,"ip":28,"op":45,"st":-44,"bm":0},{"ddd":0,"ind":67,"ty":4,"nm":"Shape Layer 130","parent":66,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[0,0]},{"t":44,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[8]},{"t":44,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":34,"op":45,"st":17,"ct":1,"bm":0},{"ddd":0,"ind":68,"ty":4,"nm":"Shape Layer 129","parent":66,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[0,0]},{"t":41,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":36,"s":[8]},{"t":41,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":42,"st":14,"ct":1,"bm":0},{"ddd":0,"ind":69,"ty":4,"nm":"Shape Layer 128","parent":66,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[0,0]},{"t":38,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[8]},{"t":38,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":39,"st":11,"ct":1,"bm":0},{"ddd":0,"ind":70,"ty":3,"nm":"NULL CONTROL 34","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":115,"ix":10},"p":{"a":0,"k":[116.24,118.527,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[60.561,60.561,100],"ix":6,"l":2}},"ao":0,"ip":13,"op":36,"st":-40,"bm":0},{"ddd":0,"ind":71,"ty":4,"nm":"Shape Layer 127","parent":70,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[0,0]},{"t":35,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26,"s":[20]},{"t":35,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":21,"op":36,"st":4,"ct":1,"bm":0},{"ddd":0,"ind":72,"ty":4,"nm":"Shape Layer 126","parent":70,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[0,0]},{"t":30,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[20]},{"t":30,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":16,"op":31,"st":-1,"ct":1,"bm":0},{"ddd":0,"ind":73,"ty":4,"nm":"Shape Layer 125","parent":70,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"t":27,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[20]},{"t":27,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":13,"op":28,"st":-4,"ct":1,"bm":0},{"ddd":0,"ind":74,"ty":3,"nm":"NULL CONTROL 33","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":118,"ix":10},"p":{"a":0,"k":[234.893,318.753,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[73.409,73.409,100],"ix":6,"l":2}},"ao":0,"ip":38,"op":59,"st":-4,"bm":0},{"ddd":0,"ind":75,"ty":4,"nm":"circles_water 52","parent":74,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47.334,"s":[0,0]},{"t":63,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":53.166,"s":[20]},{"t":63,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":46,"op":64,"st":29,"ct":1,"bm":0},{"ddd":0,"ind":76,"ty":4,"nm":"circles_water 51","parent":74,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43.834,"s":[0,0]},{"t":59,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49.666,"s":[20]},{"t":59,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":43,"op":61,"st":26,"ct":1,"bm":0},{"ddd":0,"ind":77,"ty":4,"nm":"circles_water 50","parent":74,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40.334,"s":[0,0]},{"t":61,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46.166,"s":[20]},{"t":61,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":62,"st":23,"ct":1,"bm":0},{"ddd":0,"ind":78,"ty":4,"nm":"circles_water 49","parent":74,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[0,0]},{"t":54,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43.834,"s":[20]},{"t":54,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":38,"op":56,"st":21,"ct":1,"bm":0},{"ddd":0,"ind":79,"ty":3,"nm":"NULL CONTROL 32","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-19,"ix":10},"p":{"a":0,"k":[310.614,163.154,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[83.285,83.285,100],"ix":6,"l":2}},"ao":0,"ip":32,"op":51,"st":-10,"bm":0},{"ddd":0,"ind":80,"ty":4,"nm":"circles_water 48","parent":79,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[0,0]},{"t":54,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[20]},{"t":54,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":56,"st":23,"ct":1,"bm":0},{"ddd":0,"ind":81,"ty":4,"nm":"circles_water 47","parent":79,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[0,0]},{"t":51,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[20]},{"t":51,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":53,"st":20,"ct":1,"bm":0},{"ddd":0,"ind":82,"ty":4,"nm":"circles_water 46","parent":79,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[0,0]},{"t":52,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[20]},{"t":52,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":34,"op":54,"st":17,"ct":1,"bm":0},{"ddd":0,"ind":83,"ty":4,"nm":"circles_water 45","parent":79,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[0,0]},{"t":46,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[20]},{"t":46,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":32,"op":48,"st":15,"ct":1,"bm":0},{"ddd":0,"ind":84,"ty":3,"nm":"NULL CONTROL 31","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":112,"ix":10},"p":{"a":0,"k":[201.906,230.732,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[68.667,68.667,100],"ix":6,"l":2}},"ao":0,"ip":25,"op":42,"st":-47,"bm":0},{"ddd":0,"ind":85,"ty":4,"nm":"Shape Layer 124","parent":84,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[0,0]},{"t":41,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":36,"s":[20]},{"t":41,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":42,"st":14,"ct":1,"bm":0},{"ddd":0,"ind":86,"ty":4,"nm":"Shape Layer 123","parent":84,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[0,0]},{"t":38,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[20]},{"t":38,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":39,"st":11,"ct":1,"bm":0},{"ddd":0,"ind":87,"ty":4,"nm":"Shape Layer 122","parent":84,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[0,0]},{"t":35,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[20]},{"t":35,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":25,"op":36,"st":8,"ct":1,"bm":0},{"ddd":0,"ind":88,"ty":3,"nm":"NULL CONTROL 30","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[255.736,330.597,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[62.687,62.687,100],"ix":6,"l":2}},"ao":0,"ip":9,"op":32,"st":-44,"bm":0},{"ddd":0,"ind":89,"ty":4,"nm":"Shape Layer 121","parent":88,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[0,0]},{"t":31,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[18]},{"t":31,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":17,"op":32,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":90,"ty":4,"nm":"Shape Layer 120","parent":88,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[0,0]},{"t":26,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[18]},{"t":26,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":27,"st":-5,"ct":1,"bm":0},{"ddd":0,"ind":91,"ty":4,"nm":"Shape Layer 119","parent":88,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[0,0]},{"t":23,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[18]},{"t":23,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":24,"st":-8,"ct":1,"bm":0},{"ddd":0,"ind":92,"ty":3,"nm":"NULL CONTROL 29","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300.927,201.64,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[55.198,55.198,100],"ix":6,"l":2}},"ao":0,"ip":5,"op":24,"st":-37,"bm":0},{"ddd":0,"ind":93,"ty":4,"nm":"circles_water 44","parent":92,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"t":23,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[20]},{"t":23,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":13,"op":24,"st":-4,"ct":1,"bm":0},{"ddd":0,"ind":94,"ty":4,"nm":"circles_water 43","parent":92,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[0,0]},{"t":20,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[20]},{"t":20,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":21,"st":-7,"ct":1,"bm":0},{"ddd":0,"ind":95,"ty":4,"nm":"circles_water 42","parent":92,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[0,0]},{"t":21,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[20]},{"t":21,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":7,"op":22,"st":-10,"ct":1,"bm":0},{"ddd":0,"ind":96,"ty":4,"nm":"circles_water 41","parent":92,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[0,0]},{"t":15,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[20]},{"t":15,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":16,"st":-12,"ct":1,"bm":0},{"ddd":0,"ind":97,"ty":3,"nm":"NULL CONTROL 28","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":32,"ix":10},"p":{"a":0,"k":[403.775,95.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.632,79.632,100],"ix":6,"l":2}},"ao":0,"ip":34,"op":51,"st":-35,"bm":0},{"ddd":0,"ind":98,"ty":4,"nm":"Shape Layer 118","parent":97,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[0,0]},{"t":50,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[8]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":51,"st":23,"ct":1,"bm":0},{"ddd":0,"ind":99,"ty":4,"nm":"Shape Layer 117","parent":97,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[0,0]},{"t":47,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[8]},{"t":47,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":48,"st":20,"ct":1,"bm":0},{"ddd":0,"ind":100,"ty":4,"nm":"Shape Layer 116","parent":97,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[0,0]},{"t":44,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[8]},{"t":44,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":34,"op":45,"st":17,"ct":1,"bm":0},{"ddd":0,"ind":101,"ty":3,"nm":"NULL CONTROL 27","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":149,"ix":10},"p":{"a":0,"k":[170.775,405.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":67,"op":84,"st":-2,"bm":0},{"ddd":0,"ind":102,"ty":4,"nm":"Shape Layer 115","parent":101,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":83,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[8]},{"t":83,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":73,"op":84,"st":56,"ct":1,"bm":0},{"ddd":0,"ind":103,"ty":4,"nm":"Shape Layer 114","parent":101,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":80,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":75,"s":[8]},{"t":80,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":81,"st":53,"ct":1,"bm":0},{"ddd":0,"ind":104,"ty":4,"nm":"Shape Layer 113","parent":101,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[0,0]},{"t":77,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":72,"s":[8]},{"t":77,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":67,"op":78,"st":50,"ct":1,"bm":0},{"ddd":0,"ind":105,"ty":3,"nm":"NULL CONTROL 26","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[361.667,296.006,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[64.144,64.144,100],"ix":6,"l":2}},"ao":0,"ip":54,"op":77,"st":1,"bm":0},{"ddd":0,"ind":106,"ty":4,"nm":"Shape Layer 112","parent":105,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[0,0]},{"t":76,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":67,"s":[20]},{"t":76,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":62,"op":77,"st":45,"ct":1,"bm":0},{"ddd":0,"ind":107,"ty":4,"nm":"Shape Layer 111","parent":105,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[0,0]},{"t":71,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[20]},{"t":71,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":57,"op":72,"st":40,"ct":1,"bm":0},{"ddd":0,"ind":108,"ty":4,"nm":"Shape Layer 110","parent":105,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[0,0]},{"t":68,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59,"s":[20]},{"t":68,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":54,"op":69,"st":37,"ct":1,"bm":0},{"ddd":0,"ind":109,"ty":3,"nm":"NULL CONTROL 25","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-194,"ix":10},"p":{"a":0,"k":[104.849,283.658,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.053,79.053,100],"ix":6,"l":2}},"ao":0,"ip":47,"op":66,"st":5,"bm":0},{"ddd":0,"ind":110,"ty":4,"nm":"circles_water 40","parent":109,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[0,0]},{"t":65,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[8]},{"t":65,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":55,"op":66,"st":38,"ct":1,"bm":0},{"ddd":0,"ind":111,"ty":4,"nm":"circles_water 39","parent":109,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[0,0]},{"t":62,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[8]},{"t":62,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":52,"op":63,"st":35,"ct":1,"bm":0},{"ddd":0,"ind":112,"ty":4,"nm":"circles_water 38","parent":109,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[0,0]},{"t":63,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[8]},{"t":63,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":49,"op":64,"st":32,"ct":1,"bm":0},{"ddd":0,"ind":113,"ty":4,"nm":"circles_water 37","parent":109,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[0,0]},{"t":57,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[8]},{"t":57,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":47,"op":58,"st":30,"ct":1,"bm":0},{"ddd":0,"ind":114,"ty":3,"nm":"NULL CONTROL 24","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-201,"ix":10},"p":{"a":0,"k":[161.993,160.558,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[109.232,109.232,100],"ix":6,"l":2}},"ao":0,"ip":37,"op":54,"st":-35,"bm":0},{"ddd":0,"ind":115,"ty":4,"nm":"Shape Layer 109","parent":114,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[0,0]},{"t":53,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":48,"s":[8]},{"t":53,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":43,"op":54,"st":26,"ct":1,"bm":0},{"ddd":0,"ind":116,"ty":4,"nm":"Shape Layer 108","parent":114,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[0,0]},{"t":50,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[8]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":40,"op":51,"st":23,"ct":1,"bm":0},{"ddd":0,"ind":117,"ty":4,"nm":"Shape Layer 107","parent":114,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[0,0]},{"t":47,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[8]},{"t":47,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":48,"st":20,"ct":1,"bm":0},{"ddd":0,"ind":118,"ty":3,"nm":"NULL CONTROL 23","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":28,"ix":10},"p":{"a":0,"k":[135.919,409.814,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[45.483,45.483,100],"ix":6,"l":2}},"ao":0,"ip":26,"op":49,"st":-27,"bm":0},{"ddd":0,"ind":119,"ty":4,"nm":"Shape Layer 106","parent":118,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[0,0]},{"t":48,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[20]},{"t":48,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":34,"op":49,"st":17,"ct":1,"bm":0},{"ddd":0,"ind":120,"ty":4,"nm":"Shape Layer 105","parent":118,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[0,0]},{"t":43,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[20]},{"t":43,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":44,"st":12,"ct":1,"bm":0},{"ddd":0,"ind":121,"ty":4,"nm":"Shape Layer 104","parent":118,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[0,0]},{"t":40,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[20]},{"t":40,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":41,"st":9,"ct":1,"bm":0},{"ddd":0,"ind":122,"ty":3,"nm":"NULL CONTROL 22","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":104,"ix":10},"p":{"a":0,"k":[429.936,406.449,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[63.273,63.273,100],"ix":6,"l":2}},"ao":0,"ip":39,"op":60,"st":-3,"bm":0},{"ddd":0,"ind":123,"ty":4,"nm":"circles_water 36","parent":122,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48.334,"s":[0,0]},{"t":60,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54.166,"s":[8]},{"t":60,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":47,"op":60,"st":30,"ct":1,"bm":0},{"ddd":0,"ind":124,"ty":4,"nm":"circles_water 35","parent":122,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44.834,"s":[0,0]},{"t":56.5,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.666,"s":[8]},{"t":56.5,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":57,"st":27,"ct":1,"bm":0},{"ddd":0,"ind":125,"ty":4,"nm":"circles_water 34","parent":122,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41.334,"s":[0,0]},{"t":57.666015625,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47.166,"s":[8]},{"t":57.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":41,"op":58,"st":24,"ct":1,"bm":0},{"ddd":0,"ind":126,"ty":4,"nm":"circles_water 33","parent":122,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[0,0]},{"t":50.666015625,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44.834,"s":[8]},{"t":50.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":39,"op":52,"st":22,"ct":1,"bm":0},{"ddd":0,"ind":127,"ty":3,"nm":"NULL CONTROL 21","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-6,"ix":10},"p":{"a":0,"k":[354.201,369.74,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[91.776,91.776,100],"ix":6,"l":2}},"ao":0,"ip":26,"op":43,"st":-46,"bm":0},{"ddd":0,"ind":128,"ty":4,"nm":"Shape Layer 103","parent":127,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[0,0]},{"t":42,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[8]},{"t":42,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":32,"op":43,"st":15,"ct":1,"bm":0},{"ddd":0,"ind":129,"ty":4,"nm":"Shape Layer 102","parent":127,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[0,0]},{"t":39,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[8]},{"t":39,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":40,"st":12,"ct":1,"bm":0},{"ddd":0,"ind":130,"ty":4,"nm":"Shape Layer 101","parent":127,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[0,0]},{"t":36,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[8]},{"t":36,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":37,"st":9,"ct":1,"bm":0},{"ddd":0,"ind":131,"ty":3,"nm":"NULL CONTROL 20","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":115,"ix":10},"p":{"a":0,"k":[116.24,118.527,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[60.561,60.561,100],"ix":6,"l":2}},"ao":0,"ip":11,"op":34,"st":-42,"bm":0},{"ddd":0,"ind":132,"ty":4,"nm":"Shape Layer 100","parent":131,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[0,0]},{"t":33,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[20]},{"t":33,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":19,"op":34,"st":2,"ct":1,"bm":0},{"ddd":0,"ind":133,"ty":4,"nm":"Shape Layer 99","parent":131,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[0,0]},{"t":28,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[20]},{"t":28,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":14,"op":29,"st":-3,"ct":1,"bm":0},{"ddd":0,"ind":134,"ty":4,"nm":"Shape Layer 98","parent":131,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[0,0]},{"t":25,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[20]},{"t":25,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":11,"op":26,"st":-6,"ct":1,"bm":0},{"ddd":0,"ind":135,"ty":3,"nm":"NULL CONTROL 19","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":118,"ix":10},"p":{"a":0,"k":[234.893,318.753,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[73.409,73.409,100],"ix":6,"l":2}},"ao":0,"ip":36,"op":57,"st":-6,"bm":0},{"ddd":0,"ind":136,"ty":4,"nm":"circles_water 32","parent":135,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45.334,"s":[0,0]},{"t":61,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51.166,"s":[20]},{"t":61,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":44,"op":62,"st":27,"ct":1,"bm":0},{"ddd":0,"ind":137,"ty":4,"nm":"circles_water 31","parent":135,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41.834,"s":[0,0]},{"t":57,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47.666,"s":[20]},{"t":57,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":41,"op":59,"st":24,"ct":1,"bm":0},{"ddd":0,"ind":138,"ty":4,"nm":"circles_water 30","parent":135,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38.334,"s":[0,0]},{"t":59,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44.166,"s":[20]},{"t":59,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":38,"op":60,"st":21,"ct":1,"bm":0},{"ddd":0,"ind":139,"ty":4,"nm":"circles_water 29","parent":135,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[0,0]},{"t":52,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41.834,"s":[20]},{"t":52,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":54,"st":19,"ct":1,"bm":0},{"ddd":0,"ind":140,"ty":3,"nm":"NULL CONTROL 18","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-19,"ix":10},"p":{"a":0,"k":[310.614,163.154,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[83.285,83.285,100],"ix":6,"l":2}},"ao":0,"ip":30,"op":49,"st":-12,"bm":0},{"ddd":0,"ind":141,"ty":4,"nm":"circles_water 28","parent":140,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[0,0]},{"t":52,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[20]},{"t":52,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":38,"op":54,"st":21,"ct":1,"bm":0},{"ddd":0,"ind":142,"ty":4,"nm":"circles_water 27","parent":140,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[0,0]},{"t":49,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[20]},{"t":49,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":35,"op":51,"st":18,"ct":1,"bm":0},{"ddd":0,"ind":143,"ty":4,"nm":"circles_water 26","parent":140,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[0,0]},{"t":50,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[20]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":32,"op":52,"st":15,"ct":1,"bm":0},{"ddd":0,"ind":144,"ty":4,"nm":"circles_water 25","parent":140,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[0,0]},{"t":44,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[20]},{"t":44,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":46,"st":13,"ct":1,"bm":0},{"ddd":0,"ind":145,"ty":3,"nm":"NULL CONTROL 17","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":112,"ix":10},"p":{"a":0,"k":[201.906,230.732,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[68.667,68.667,100],"ix":6,"l":2}},"ao":0,"ip":23,"op":40,"st":-49,"bm":0},{"ddd":0,"ind":146,"ty":4,"nm":"Shape Layer 97","parent":145,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[0,0]},{"t":39,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[20]},{"t":39,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":40,"st":12,"ct":1,"bm":0},{"ddd":0,"ind":147,"ty":4,"nm":"Shape Layer 96","parent":145,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[0,0]},{"t":36,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[20]},{"t":36,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":37,"st":9,"ct":1,"bm":0},{"ddd":0,"ind":148,"ty":4,"nm":"Shape Layer 95","parent":145,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[0,0]},{"t":33,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[20]},{"t":33,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":23,"op":34,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":149,"ty":3,"nm":"NULL CONTROL 16","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[255.736,330.597,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[62.687,62.687,100],"ix":6,"l":2}},"ao":0,"ip":7,"op":30,"st":-46,"bm":0},{"ddd":0,"ind":150,"ty":4,"nm":"Shape Layer 94","parent":149,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"t":29,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[18]},{"t":29,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":15,"op":30,"st":-2,"ct":1,"bm":0},{"ddd":0,"ind":151,"ty":4,"nm":"Shape Layer 93","parent":149,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[0,0]},{"t":24,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[18]},{"t":24,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":25,"st":-7,"ct":1,"bm":0},{"ddd":0,"ind":152,"ty":4,"nm":"Shape Layer 92","parent":149,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[0,0]},{"t":21,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[18]},{"t":21,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":7,"op":22,"st":-10,"ct":1,"bm":0},{"ddd":0,"ind":153,"ty":3,"nm":"NULL CONTROL 15","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300.927,201.64,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[55.198,55.198,100],"ix":6,"l":2}},"ao":0,"ip":3,"op":22,"st":-39,"bm":0},{"ddd":0,"ind":154,"ty":4,"nm":"circles_water 24","parent":153,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[0,0]},{"t":21,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[20]},{"t":21,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":11,"op":22,"st":-6,"ct":1,"bm":0},{"ddd":0,"ind":155,"ty":4,"nm":"circles_water 23","parent":153,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[0,0]},{"t":18,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[20]},{"t":18,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":19,"st":-9,"ct":1,"bm":0},{"ddd":0,"ind":156,"ty":4,"nm":"circles_water 22","parent":153,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[0,0]},{"t":19,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[20]},{"t":19,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":20,"st":-12,"ct":1,"bm":0},{"ddd":0,"ind":157,"ty":4,"nm":"circles_water 21","parent":153,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[0,0]},{"t":13,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[20]},{"t":13,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":14,"st":-14,"ct":1,"bm":0},{"ddd":0,"ind":158,"ty":3,"nm":"NULL CONTROL 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":32,"ix":10},"p":{"a":0,"k":[403.775,95.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.632,79.632,100],"ix":6,"l":2}},"ao":0,"ip":32,"op":49,"st":-37,"bm":0},{"ddd":0,"ind":159,"ty":4,"nm":"Shape Layer 91","parent":158,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[0,0]},{"t":48,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[8]},{"t":48,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":38,"op":49,"st":21,"ct":1,"bm":0},{"ddd":0,"ind":160,"ty":4,"nm":"Shape Layer 90","parent":158,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[0,0]},{"t":45,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[8]},{"t":45,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":35,"op":46,"st":18,"ct":1,"bm":0},{"ddd":0,"ind":161,"ty":4,"nm":"Shape Layer 89","parent":158,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[0,0]},{"t":42,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[8]},{"t":42,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":32,"op":43,"st":15,"ct":1,"bm":0},{"ddd":0,"ind":162,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":149,"ix":10},"p":{"a":0,"k":[170.775,405.984,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":65,"op":82,"st":-4,"bm":0},{"ddd":0,"ind":163,"ty":4,"nm":"Shape Layer 88","parent":162,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[141.175,96.966,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[0,0]},{"t":81,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":76,"s":[8]},{"t":81,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":71,"op":82,"st":54,"ct":1,"bm":0},{"ddd":0,"ind":164,"ty":4,"nm":"Shape Layer 87","parent":162,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[120.235,111.393,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":78,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[8]},{"t":78,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":68,"op":79,"st":51,"ct":1,"bm":0},{"ddd":0,"ind":165,"ty":4,"nm":"Shape Layer 86","parent":162,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-98,"ix":10},"p":{"a":0,"k":[88.825,133.033,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[94.767,94.767,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"t":75,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[8]},{"t":75,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":76,"st":48,"ct":1,"bm":0},{"ddd":0,"ind":166,"ty":3,"nm":"NULL CONTROL 13","sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[361.667,296.006,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[64.144,64.144,100],"ix":6,"l":2}},"ao":0,"ip":52,"op":75,"st":-1,"bm":0},{"ddd":0,"ind":167,"ty":4,"nm":"Shape Layer 85","parent":166,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"t":74,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[20]},{"t":74,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":75,"st":43,"ct":1,"bm":0},{"ddd":0,"ind":168,"ty":4,"nm":"Shape Layer 84","parent":166,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[0,0]},{"t":69,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[20]},{"t":69,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":55,"op":70,"st":38,"ct":1,"bm":0},{"ddd":0,"ind":169,"ty":4,"nm":"Shape Layer 83","parent":166,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[0,0]},{"t":66,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[20]},{"t":66,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":52,"op":67,"st":35,"ct":1,"bm":0},{"ddd":0,"ind":170,"ty":3,"nm":"NULL CONTROL 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-194,"ix":10},"p":{"a":0,"k":[104.849,283.658,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[79.053,79.053,100],"ix":6,"l":2}},"ao":0,"ip":45,"op":64,"st":3,"bm":0},{"ddd":0,"ind":171,"ty":4,"nm":"circles_water 20","parent":170,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[0,0]},{"t":63,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":58,"s":[8]},{"t":63,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":53,"op":64,"st":36,"ct":1,"bm":0},{"ddd":0,"ind":172,"ty":4,"nm":"circles_water 19","parent":170,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[0,0]},{"t":60,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[8]},{"t":60,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":50,"op":61,"st":33,"ct":1,"bm":0},{"ddd":0,"ind":173,"ty":4,"nm":"circles_water 18","parent":170,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[0,0]},{"t":61,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[8]},{"t":61,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":47,"op":62,"st":30,"ct":1,"bm":0},{"ddd":0,"ind":174,"ty":4,"nm":"circles_water 17","parent":170,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[0,0]},{"t":55,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50,"s":[8]},{"t":55,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":45,"op":56,"st":28,"ct":1,"bm":0},{"ddd":0,"ind":175,"ty":3,"nm":"NULL CONTROL 11","sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":-201,"ix":10},"p":{"a":0,"k":[161.993,160.558,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[109.232,109.232,100],"ix":6,"l":2}},"ao":0,"ip":35,"op":52,"st":-37,"bm":0},{"ddd":0,"ind":176,"ty":4,"nm":"Shape Layer 82","parent":175,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[0,0]},{"t":51,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46,"s":[8]},{"t":51,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":41,"op":52,"st":24,"ct":1,"bm":0},{"ddd":0,"ind":177,"ty":4,"nm":"Shape Layer 81","parent":175,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[0,0]},{"t":48,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[8]},{"t":48,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":38,"op":49,"st":21,"ct":1,"bm":0},{"ddd":0,"ind":178,"ty":4,"nm":"Shape Layer 80","parent":175,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[0,0]},{"t":45,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[8]},{"t":45,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":35,"op":46,"st":18,"ct":1,"bm":0},{"ddd":0,"ind":179,"ty":3,"nm":"NULL CONTROL 10","sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":28,"ix":10},"p":{"a":0,"k":[135.919,409.814,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[45.483,45.483,100],"ix":6,"l":2}},"ao":0,"ip":24,"op":47,"st":-29,"bm":0},{"ddd":0,"ind":180,"ty":4,"nm":"Shape Layer 79","parent":179,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[0,0]},{"t":46,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[20]},{"t":46,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":32,"op":47,"st":15,"ct":1,"bm":0},{"ddd":0,"ind":181,"ty":4,"nm":"Shape Layer 78","parent":179,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[0,0]},{"t":41,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[20]},{"t":41,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":27,"op":42,"st":10,"ct":1,"bm":0},{"ddd":0,"ind":182,"ty":4,"nm":"Shape Layer 77","parent":179,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[0,0]},{"t":38,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[20]},{"t":38,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":39,"st":7,"ct":1,"bm":0},{"ddd":0,"ind":183,"ty":3,"nm":"NULL CONTROL 9","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":104,"ix":10},"p":{"a":0,"k":[429.936,406.449,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[63.273,63.273,100],"ix":6,"l":2}},"ao":0,"ip":37,"op":58,"st":-5,"bm":0},{"ddd":0,"ind":184,"ty":4,"nm":"circles_water 16","parent":183,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46.334,"s":[0,0]},{"t":58,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52.166,"s":[8]},{"t":58,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":45,"op":58,"st":28,"ct":1,"bm":0},{"ddd":0,"ind":185,"ty":4,"nm":"circles_water 15","parent":183,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42.834,"s":[0,0]},{"t":54.5,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":48.666,"s":[8]},{"t":54.5,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":42,"op":55,"st":25,"ct":1,"bm":0},{"ddd":0,"ind":186,"ty":4,"nm":"circles_water 14","parent":183,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39.334,"s":[0,0]},{"t":55.666015625,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45.166,"s":[8]},{"t":55.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":39,"op":56,"st":22,"ct":1,"bm":0},{"ddd":0,"ind":187,"ty":4,"nm":"circles_water 13","parent":183,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[0,0]},{"t":48.666015625,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42.834,"s":[8]},{"t":48.666015625,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":50,"st":20,"ct":1,"bm":0},{"ddd":0,"ind":188,"ty":3,"nm":"NULL CONTROL 8","sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":-6,"ix":10},"p":{"a":0,"k":[354.201,369.74,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[91.776,91.776,100],"ix":6,"l":2}},"ao":0,"ip":24,"op":41,"st":-48,"bm":0},{"ddd":0,"ind":189,"ty":4,"nm":"Shape Layer 76","parent":188,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[0,0]},{"t":40,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[8]},{"t":40,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":41,"st":13,"ct":1,"bm":0},{"ddd":0,"ind":190,"ty":4,"nm":"Shape Layer 75","parent":188,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[0,0]},{"t":37,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[8]},{"t":37,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":27,"op":38,"st":10,"ct":1,"bm":0},{"ddd":0,"ind":191,"ty":4,"nm":"Shape Layer 74","parent":188,"sr":1,"ks":{"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[0,0]},{"t":34,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[8]},{"t":34,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":35,"st":7,"ct":1,"bm":0},{"ddd":0,"ind":192,"ty":3,"nm":"NULL CONTROL 7","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":115,"ix":10},"p":{"a":0,"k":[116.24,118.527,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[60.561,60.561,100],"ix":6,"l":2}},"ao":0,"ip":9,"op":32,"st":-44,"bm":0},{"ddd":0,"ind":193,"ty":4,"nm":"Shape Layer 73","parent":192,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[0,0]},{"t":31,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[20]},{"t":31,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":17,"op":32,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":194,"ty":4,"nm":"Shape Layer 72","parent":192,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[0,0]},{"t":26,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[20]},{"t":26,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":27,"st":-5,"ct":1,"bm":0},{"ddd":0,"ind":195,"ty":4,"nm":"Shape Layer 71","parent":192,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[0,0]},{"t":23,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[20]},{"t":23,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":24,"st":-8,"ct":1,"bm":0},{"ddd":0,"ind":196,"ty":3,"nm":"NULL CONTROL 6","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":118,"ix":10},"p":{"a":0,"k":[234.893,318.753,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[73.409,73.409,100],"ix":6,"l":2}},"ao":0,"ip":34,"op":55,"st":-8,"bm":0},{"ddd":0,"ind":197,"ty":4,"nm":"circles_water 12","parent":196,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43.334,"s":[0,0]},{"t":59,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49.166,"s":[20]},{"t":59,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":42,"op":60,"st":25,"ct":1,"bm":0},{"ddd":0,"ind":198,"ty":4,"nm":"circles_water 11","parent":196,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39.834,"s":[0,0]},{"t":55,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45.666,"s":[20]},{"t":55,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":39,"op":57,"st":22,"ct":1,"bm":0},{"ddd":0,"ind":199,"ty":4,"nm":"circles_water 10","parent":196,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36.334,"s":[0,0]},{"t":57,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42.166,"s":[20]},{"t":57,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":58,"st":19,"ct":1,"bm":0},{"ddd":0,"ind":200,"ty":4,"nm":"circles_water 9","parent":196,"sr":1,"ks":{"o":{"a":0,"k":80,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[0,0]},{"t":50,"s":[100,100]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39.834,"s":[20]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":34,"op":52,"st":17,"ct":1,"bm":0},{"ddd":0,"ind":201,"ty":3,"nm":"NULL CONTROL 5","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-19,"ix":10},"p":{"a":0,"k":[310.614,163.154,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[83.285,83.285,100],"ix":6,"l":2}},"ao":0,"ip":28,"op":47,"st":-14,"bm":0},{"ddd":0,"ind":202,"ty":4,"nm":"circles_water 8","parent":201,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[0,0]},{"t":50,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41,"s":[20]},{"t":50,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":52,"st":19,"ct":1,"bm":0},{"ddd":0,"ind":203,"ty":4,"nm":"circles_water 7","parent":201,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[0,0]},{"t":47,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":38,"s":[20]},{"t":47,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":33,"op":49,"st":16,"ct":1,"bm":0},{"ddd":0,"ind":204,"ty":4,"nm":"circles_water 6","parent":201,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[0,0]},{"t":48,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[20]},{"t":48,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":50,"st":13,"ct":1,"bm":0},{"ddd":0,"ind":205,"ty":4,"nm":"circles_water 5","parent":201,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[0,0]},{"t":42,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[20]},{"t":42,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":44,"st":11,"ct":1,"bm":0},{"ddd":0,"ind":206,"ty":3,"nm":"NULL CONTROL 3","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":112,"ix":10},"p":{"a":0,"k":[201.906,230.732,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[68.667,68.667,100],"ix":6,"l":2}},"ao":0,"ip":21,"op":38,"st":-51,"bm":0},{"ddd":0,"ind":207,"ty":4,"nm":"Shape Layer 70","parent":206,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,145,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[0,0]},{"t":37,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[20]},{"t":37,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":27,"op":38,"st":10,"ct":1,"bm":0},{"ddd":0,"ind":208,"ty":4,"nm":"Shape Layer 69","parent":206,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,121,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[0,0]},{"t":34,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[20]},{"t":34,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":35,"st":7,"ct":1,"bm":0},{"ddd":0,"ind":209,"ty":4,"nm":"Shape Layer 68","parent":206,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,85,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[0,0]},{"t":31,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26,"s":[20]},{"t":31,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":21,"op":32,"st":4,"ct":1,"bm":0},{"ddd":0,"ind":210,"ty":3,"nm":"NULL CONTROL 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-38,"ix":10},"p":{"a":0,"k":[255.736,330.597,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[62.687,62.687,100],"ix":6,"l":2}},"ao":0,"ip":5,"op":28,"st":-48,"bm":0},{"ddd":0,"ind":211,"ty":4,"nm":"Shape Layer 67","parent":210,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[116.5,159.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"t":27,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[18]},{"t":27,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":13,"op":28,"st":-4,"ct":1,"bm":0},{"ddd":0,"ind":212,"ty":4,"nm":"Shape Layer 66","parent":210,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.5,102.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[0,0]},{"t":22,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[18]},{"t":22,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":23,"st":-9,"ct":1,"bm":0},{"ddd":0,"ind":213,"ty":4,"nm":"Shape Layer 65","parent":210,"sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.5,70.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[0,0]},{"t":19,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[18]},{"t":19,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":20,"st":-12,"ct":1,"bm":0},{"ddd":0,"ind":214,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300.927,201.64,0],"ix":2,"l":2},"a":{"a":0,"k":[115,115,0],"ix":1,"l":2},"s":{"a":0,"k":[55.198,55.198,100],"ix":6,"l":2}},"ao":0,"ip":1,"op":20,"st":-41,"bm":0},{"ddd":0,"ind":215,"ty":4,"nm":"circles_water 4","parent":214,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,86.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[0,0]},{"t":19,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[20]},{"t":19,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":9,"op":20,"st":-8,"ct":1,"bm":0},{"ddd":0,"ind":216,"ty":4,"nm":"circles_water 3","parent":214,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.5,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[0,0]},{"t":16,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[20]},{"t":16,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":17,"st":-11,"ct":1,"bm":0},{"ddd":0,"ind":217,"ty":4,"nm":"circles_water 2","parent":214,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95.5,118.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[0,0]},{"t":17,"s":[82,82]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[20]},{"t":17,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":18,"st":-14,"ct":1,"bm":0},{"ddd":0,"ind":218,"ty":4,"nm":"circles_water","parent":214,"sr":1,"ks":{"o":{"a":0,"k":70,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.5,143.5,0],"ix":2,"l":2},"a":{"a":0,"k":[142.291,-161.709,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[0,0]},{"t":11,"s":[51,51]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[20]},{"t":11,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.291,-161.709],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":12,"st":-16,"ct":1,"bm":0}],"markers":[{"tm":-2,"cm":"1","dr":0},{"tm":88,"cm":"2","dr":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/speaker_to_bt.json b/TMessagesProj/src/main/res/raw/speaker_to_bt.json new file mode 100644 index 000000000..90a6ba022 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/speaker_to_bt.json @@ -0,0 +1 @@ +{"v":"5.10.1","fr":60,"ip":0,"op":60,"w":156,"h":156,"nm":"speaker_to_bt","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Top 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1.004]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.689]},"o":{"x":[0.167],"y":[0.083]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.638]},"o":{"x":[0.167],"y":[0.114]},"t":2,"s":[-0.042]},{"i":{"x":[0.833],"y":[0.808]},"o":{"x":[0.167],"y":[0.108]},"t":3,"s":[-0.157]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.148]},"t":4,"s":[-0.54]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.162]},"t":5,"s":[-1.038]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.256]},"t":6,"s":[-1.564]},{"i":{"x":[0.833],"y":[0.942]},"o":{"x":[0.167],"y":[0.144]},"t":7,"s":[-1.817]},{"i":{"x":[0.833],"y":[0.368]},"o":{"x":[0.167],"y":[-0.195]},"t":8,"s":[-2.167]},{"i":{"x":[0.833],"y":[0.785]},"o":{"x":[0.167],"y":[0.096]},"t":9,"s":[-2.062]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.136]},"t":10,"s":[-1.374]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.23]},"t":11,"s":[-0.289]},{"i":{"x":[0.833],"y":[0.839]},"o":{"x":[0.167],"y":[0.124]},"t":12,"s":[0.327]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":13,"s":[1.583]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.269]},"t":14,"s":[2.759]},{"i":{"x":[0.833],"y":[0.854]},"o":{"x":[0.167],"y":[0.132]},"t":15,"s":[3.288]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.193]},"t":16,"s":[4.193]},{"i":{"x":[0.833],"y":[0.834]},"o":{"x":[0.167],"y":[0.302]},"t":17,"s":[4.879]},{"i":{"x":[0.833],"y":[1.096]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[5.14]},{"i":{"x":[0.833],"y":[0.84]},"o":{"x":[0.167],"y":[0.045]},"t":19,"s":[5.401]},{"i":{"x":[0.833],"y":[0.706]},"o":{"x":[0.167],"y":[0.173]},"t":20,"s":[4.839]},{"i":{"x":[0.833],"y":[0.824]},"o":{"x":[0.167],"y":[0.116]},"t":21,"s":[4.319]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.158]},"t":22,"s":[3.002]},{"i":{"x":[0.833],"y":[0.762]},"o":{"x":[0.167],"y":[0.251]},"t":23,"s":[1.531]},{"i":{"x":[0.833],"y":[0.846]},"o":{"x":[0.167],"y":[0.128]},"t":24,"s":[0.802]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.182]},"t":25,"s":[-0.555]},{"i":{"x":[0.833],"y":[0.791]},"o":{"x":[0.167],"y":[0.282]},"t":26,"s":[-1.705]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.139]},"t":27,"s":[-2.186]},{"i":{"x":[0.833],"y":[0.93]},"o":{"x":[0.167],"y":[0.342]},"t":28,"s":[-2.912]},{"i":{"x":[0.833],"y":[0.264]},"o":{"x":[0.167],"y":[-0.443]},"t":29,"s":[-3.145]},{"i":{"x":[0.833],"y":[0.781]},"o":{"x":[0.167],"y":[0.094]},"t":30,"s":[-3.108]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.135]},"t":31,"s":[-2.818]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.229]},"t":32,"s":[-2.348]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.124]},"t":33,"s":[-2.08]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":34,"s":[-1.528]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.268]},"t":35,"s":[-1.009]},{"i":{"x":[0.833],"y":[0.853]},"o":{"x":[0.167],"y":[0.132]},"t":36,"s":[-0.775]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.193]},"t":37,"s":[-0.372]},{"i":{"x":[0.833],"y":[0.797]},"o":{"x":[0.167],"y":[0.301]},"t":38,"s":[-0.066]},{"i":{"x":[0.833],"y":[0.871]},"o":{"x":[0.167],"y":[0.141]},"t":39,"s":[0.051]},{"i":{"x":[0.833],"y":[0.897]},"o":{"x":[0.167],"y":[0.237]},"t":40,"s":[0.219]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.431]},"t":41,"s":[0.31]},{"i":{"x":[0.833],"y":[1.258]},"o":{"x":[0.167],"y":[0.345]},"t":42,"s":[0.332]},{"i":{"x":[0.833],"y":[0.85]},"o":{"x":[0.167],"y":[0.063]},"t":43,"s":[0.339]},{"i":{"x":[0.833],"y":[0.715]},"o":{"x":[0.167],"y":[0.187]},"t":44,"s":[0.31]},{"i":{"x":[0.833],"y":[0.827]},"o":{"x":[0.167],"y":[0.118]},"t":45,"s":[0.287]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.16]},"t":46,"s":[0.232]},{"i":{"x":[0.833],"y":[0.764]},"o":{"x":[0.167],"y":[0.254]},"t":47,"s":[0.172]},{"i":{"x":[0.833],"y":[0.847]},"o":{"x":[0.167],"y":[0.129]},"t":48,"s":[0.143]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.183]},"t":49,"s":[0.089]},{"i":{"x":[0.833],"y":[0.786]},"o":{"x":[0.167],"y":[0.285]},"t":50,"s":[0.045]},{"i":{"x":[0.833],"y":[0.862]},"o":{"x":[0.167],"y":[0.136]},"t":51,"s":[0.026]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.167],"y":[0.21]},"t":52,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.823]},"o":{"x":[0.167],"y":[0.337]},"t":53,"s":[-0.022]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.157]},"t":54,"s":[-0.029]},{"i":{"x":[0.833],"y":[0.981]},"o":{"x":[0.167],"y":[0.549]},"t":55,"s":[-0.036]},{"i":{"x":[0.833],"y":[0.564]},"o":{"x":[0.167],"y":[-0.024]},"t":56,"s":[-0.037]},{"i":{"x":[0.833],"y":[0.799]},"o":{"x":[0.167],"y":[0.103]},"t":57,"s":[-0.036]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.142]},"t":58,"s":[-0.032]},{"t":59,"s":[-0.026]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.713},"o":{"x":0.167,"y":0.167},"t":0,"s":[77.722,79.526,0],"to":[0,-0.053,0],"ti":[0,0.183,0]},{"i":{"x":0.833,"y":0.864},"o":{"x":0.167,"y":0.117},"t":1,"s":[77.722,79.208,0],"to":[0,-0.183,0],"ti":[0,0.211,0]},{"i":{"x":0.833,"y":0.736},"o":{"x":0.167,"y":0.216},"t":2,"s":[77.722,78.429,0],"to":[0,-0.211,0],"ti":[0,0.258,0]},{"i":{"x":0.833,"y":0.834},"o":{"x":0.167,"y":0.122},"t":3,"s":[77.722,77.94,0],"to":[0,-0.258,0],"ti":[0,0.351,0]},{"i":{"x":0.833,"y":0.856},"o":{"x":0.167,"y":0.168},"t":4,"s":[77.722,76.881,0],"to":[0,-0.351,0],"ti":[0,0.302,0]},{"i":{"x":0.833,"y":0.894},"o":{"x":0.167,"y":0.197},"t":5,"s":[77.722,75.834,0],"to":[0,-0.302,0],"ti":[0,0.118,0]},{"i":{"x":0.833,"y":0.567},"o":{"x":0.167,"y":0.388},"t":6,"s":[77.722,75.068,0],"to":[0,-0.118,0],"ti":[0,-0.156,0]},{"i":{"x":0.833,"y":0.849},"o":{"x":0.167,"y":0.103},"t":7,"s":[77.722,75.125,0],"to":[0,0.156,0],"ti":[0,-0.265,0]},{"i":{"x":0.833,"y":0.715},"o":{"x":0.167,"y":0.187},"t":8,"s":[77.722,76.004,0],"to":[0,0.265,0],"ti":[0,-0.404,0]},{"i":{"x":0.833,"y":0.827},"o":{"x":0.167,"y":0.118},"t":9,"s":[77.722,76.712,0],"to":[0,0.404,0],"ti":[0,-0.595,0]},{"i":{"x":0.833,"y":0.876},"o":{"x":0.167,"y":0.16},"t":10,"s":[77.722,78.426,0],"to":[0,0.595,0],"ti":[0,-0.46,0]},{"i":{"x":0.833,"y":0.763},"o":{"x":0.167,"y":0.254},"t":11,"s":[77.722,80.28,0],"to":[0,0.46,0],"ti":[0,-0.428,0]},{"i":{"x":0.833,"y":0.847},"o":{"x":0.167,"y":0.129},"t":12,"s":[77.722,81.184,0],"to":[0,0.428,0],"ti":[0,-0.508,0]},{"i":{"x":0.833,"y":0.882},"o":{"x":0.167,"y":0.183},"t":13,"s":[77.722,82.846,0],"to":[0,0.508,0],"ti":[0,-0.327,0]},{"i":{"x":0.833,"y":0.785},"o":{"x":0.167,"y":0.285},"t":14,"s":[77.722,84.232,0],"to":[0,0.327,0],"ti":[0,-0.246,0]},{"i":{"x":0.833,"y":0.875},"o":{"x":0.167,"y":0.136},"t":15,"s":[77.722,84.806,0],"to":[0,0.246,0],"ti":[0,-0.226,0]},{"i":{"x":0.833,"y":0.873},"o":{"x":0.167,"y":0.25},"t":16,"s":[77.722,85.708,0],"to":[0,0.226,0],"ti":[0,-0.042,0]},{"i":{"x":0.833,"y":0.524},"o":{"x":0.167,"y":0.244},"t":17,"s":[77.722,86.16,0],"to":[0,0.042,0],"ti":[0,0.217,0]},{"i":{"x":0.833,"y":0.79},"o":{"x":0.167,"y":0.101},"t":18,"s":[77.722,85.96,0],"to":[0,-0.217,0],"ti":[0,0.464,0]},{"i":{"x":0.833,"y":0.87},"o":{"x":0.167,"y":0.138},"t":19,"s":[77.722,84.857,0],"to":[0,-0.464,0],"ti":[0,0.437,0]},{"i":{"x":0.833,"y":0.748},"o":{"x":0.167,"y":0.232},"t":20,"s":[77.722,83.177,0],"to":[0,-0.437,0],"ti":[0,0.475,0]},{"i":{"x":0.833,"y":0.839},"o":{"x":0.167,"y":0.124},"t":21,"s":[77.722,82.236,0],"to":[0,-0.475,0],"ti":[0,0.614,0]},{"i":{"x":0.833,"y":0.879},"o":{"x":0.167,"y":0.173},"t":22,"s":[77.722,80.328,0],"to":[0,-0.614,0],"ti":[0,0.428,0]},{"i":{"x":0.833,"y":0.775},"o":{"x":0.167,"y":0.27},"t":23,"s":[77.722,78.552,0],"to":[0,-0.428,0],"ti":[0,0.358,0]},{"i":{"x":0.833,"y":0.858},"o":{"x":0.167,"y":0.132},"t":24,"s":[77.722,77.757,0],"to":[0,-0.358,0],"ti":[0,0.386,0]},{"i":{"x":0.833,"y":0.897},"o":{"x":0.167,"y":0.201},"t":25,"s":[77.722,76.403,0],"to":[0,-0.386,0],"ti":[0,0.197,0]},{"i":{"x":0.833,"y":0.886},"o":{"x":0.167,"y":0.441},"t":26,"s":[77.722,75.443,0],"to":[0,-0.197,0],"ti":[0,0.038,0]},{"i":{"x":0.833,"y":0.495},"o":{"x":0.167,"y":0.307},"t":27,"s":[77.722,75.22,0],"to":[0,-0.038,0],"ti":[0,-0.07,0]},{"i":{"x":0.833,"y":0.855},"o":{"x":0.167,"y":0.1},"t":28,"s":[77.722,75.218,0],"to":[0,0.07,0],"ti":[0,-0.122,0]},{"i":{"x":0.833,"y":0.722},"o":{"x":0.167,"y":0.196},"t":29,"s":[77.722,75.639,0],"to":[0,0.122,0],"ti":[0,-0.173,0]},{"i":{"x":0.833,"y":0.829},"o":{"x":0.167,"y":0.119},"t":30,"s":[77.722,75.95,0],"to":[0,0.173,0],"ti":[0,-0.249,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.167,"y":0.162},"t":31,"s":[77.722,76.677,0],"to":[0,0.249,0],"ti":[0,-0.189,0]},{"i":{"x":0.833,"y":0.765},"o":{"x":0.167,"y":0.256},"t":32,"s":[77.722,77.443,0],"to":[0,0.189,0],"ti":[0,-0.173,0]},{"i":{"x":0.833,"y":0.848},"o":{"x":0.167,"y":0.129},"t":33,"s":[77.722,77.812,0],"to":[0,0.173,0],"ti":[0,-0.204,0]},{"i":{"x":0.833,"y":0.883},"o":{"x":0.167,"y":0.185},"t":34,"s":[77.722,78.483,0],"to":[0,0.204,0],"ti":[0,-0.13,0]},{"i":{"x":0.833,"y":0.787},"o":{"x":0.167,"y":0.287},"t":35,"s":[77.722,79.035,0],"to":[0,0.13,0],"ti":[0,-0.096,0]},{"i":{"x":0.833,"y":0.863},"o":{"x":0.167,"y":0.137},"t":36,"s":[77.722,79.261,0],"to":[0,0.096,0],"ti":[0,-0.096,0]},{"i":{"x":0.833,"y":0.89},"o":{"x":0.167,"y":0.212},"t":37,"s":[77.722,79.612,0],"to":[0,0.096,0],"ti":[0,-0.05,0]},{"i":{"x":0.833,"y":0.828},"o":{"x":0.167,"y":0.344},"t":38,"s":[77.722,79.839,0],"to":[0,0.05,0],"ti":[0,-0.025,0]},{"i":{"x":0.833,"y":0.904},"o":{"x":0.167,"y":0.162},"t":39,"s":[77.722,79.912,0],"to":[0,0.025,0],"ti":[0,-0.014,0]},{"i":{"x":0.833,"y":0.807},"o":{"x":0.167,"y":0.617},"t":40,"s":[77.722,79.989,0],"to":[0,0.014,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.617},"o":{"x":0.167,"y":0.143},"t":41,"s":[77.722,79.996,0],"to":[0,-0.002,0],"ti":[0,0.012,0]},{"i":{"x":0.833,"y":0.805},"o":{"x":0.167,"y":0.107},"t":42,"s":[77.722,79.979,0],"to":[0,-0.012,0],"ti":[0,0.023,0]},{"i":{"x":0.833,"y":0.872},"o":{"x":0.167,"y":0.146},"t":43,"s":[77.722,79.921,0],"to":[0,-0.023,0],"ti":[0,0.02,0]},{"i":{"x":0.833,"y":0.753},"o":{"x":0.167,"y":0.239},"t":44,"s":[77.722,79.844,0],"to":[0,-0.02,0],"ti":[0,0.021,0]},{"i":{"x":0.833,"y":0.841},"o":{"x":0.167,"y":0.126},"t":45,"s":[77.722,79.802,0],"to":[0,-0.021,0],"ti":[0,0.026,0]},{"i":{"x":0.833,"y":0.88},"o":{"x":0.167,"y":0.176},"t":46,"s":[77.722,79.72,0],"to":[0,-0.026,0],"ti":[0,0.018,0]},{"i":{"x":0.833,"y":0.777},"o":{"x":0.167,"y":0.273},"t":47,"s":[77.722,79.646,0],"to":[0,-0.018,0],"ti":[0,0.014,0]},{"i":{"x":0.833,"y":0.856},"o":{"x":0.167,"y":0.133},"t":48,"s":[77.722,79.614,0],"to":[0,-0.014,0],"ti":[0,0.016,0]},{"i":{"x":0.833,"y":0.886},"o":{"x":0.167,"y":0.197},"t":49,"s":[77.722,79.56,0],"to":[0,-0.016,0],"ti":[0,0.009,0]},{"i":{"x":0.833,"y":0.803},"o":{"x":0.167,"y":0.31},"t":50,"s":[77.722,79.52,0],"to":[0,-0.009,0],"ti":[0,0.006,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.167,"y":0.145},"t":51,"s":[77.722,79.505,0],"to":[0,-0.006,0],"ti":[0,0.005,0]},{"i":{"x":0.833,"y":0.903},"o":{"x":0.167,"y":0.26},"t":52,"s":[77.722,79.485,0],"to":[0,-0.005,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.835},"o":{"x":0.167,"y":0.56},"t":53,"s":[77.722,79.476,0],"to":[0,-0.002,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.613},"o":{"x":0.167,"y":0.164},"t":54,"s":[77.722,79.475,0],"to":[0,0,0],"ti":[0,-0.001,0]},{"i":{"x":0.833,"y":0.861},"o":{"x":0.167,"y":0.106},"t":55,"s":[77.722,79.476,0],"to":[0,0.001,0],"ti":[0,-0.002,0]},{"i":{"x":0.833,"y":0.731},"o":{"x":0.167,"y":0.209},"t":56,"s":[77.722,79.482,0],"to":[0,0.002,0],"ti":[0,-0.002,0]},{"i":{"x":0.833,"y":0.832},"o":{"x":0.167,"y":0.121},"t":57,"s":[77.722,79.486,0],"to":[0,0.002,0],"ti":[0,-0.003,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.166},"t":58,"s":[77.722,79.495,0],"to":[0,0.003,0],"ti":[0,-0.001,0]},{"t":59,"s":[77.722,79.504,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-0.918,5,0],"ix":1,"l":2},"s":{"a":0,"k":[30.469,30.469,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Bluetooth Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.2],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":0,"s":[0,0,100]},{"t":20,"s":[328.205,328.205,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-17.75,20.5],[17.75,-15.5],[2.25,-31.5],[2.25,31.5],[17.75,15.5],[-17.75,-20.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":30,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":30,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[69.25,78],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"wave2","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0,0],[0,-12.307],[12.759,-6.613]],"o":[[12.759,6.613],[0,12.307],[0,0]],"v":[[-19.177,-28.707],[-0.039,-0.329],[-19.177,28.05]],"c":false}]},{"t":25,"s":[{"i":[[0,0],[0,-6.48],[4.153,-6.175]],"o":[[4.153,5.794],[0,6.48],[0,0]],"v":[[-3.115,-18.698],[3.115,-0.286],[-3.115,18.698]],"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":7.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":[108.267,78.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"wave1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.167},"t":5,"s":[{"i":[[0.5,0],[0,0],[0,0],[0,0],[-2.401,2.725],[0,5.188],[2.401,2.725]],"o":[[0,0],[0,0],[0,0],[0.5,0],[2.401,-2.725],[0,-5.188],[-2.401,-2.725]],"v":[[7,-16.704],[7,-8.362],[7,3.554],[7,15.471],[12.427,11.318],[17.103,-0.617],[12.427,-12.552]],"c":true}]},{"t":25,"s":[{"i":[[1.297,-1.308],[0,0],[-1.076,-1.085],[0,0],[-0.856,1.669],[-0.026,1.81],[0.896,1.763]],"o":[[0,0],[-1.076,1.085],[0,0],[1.297,1.308],[0.843,-1.646],[0.027,-1.924],[-0.856,-1.586]],"v":[[16.736,-6.202],[12.679,-2.112],[12.679,1.811],[16.736,5.901],[21.124,5.261],[22.426,0.002],[21.124,-5.617]],"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":[78,78],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Speaker Base","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.6,0.6,0.6],"y":[0,0,0]},"t":0,"s":[328.205,328.205,100]},{"t":15,"s":[0,0,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.198],[0,0],[-2.213,0],[0,0],[0,0],[0,3.557],[0,0],[2.534,-2.518],[0,0],[0,0]],"o":[[0,0],[0,2.198],[0,0],[0,0],[2.534,2.518],[0,0],[0,-3.557],[0,0],[0,0],[-2.213,0]],"v":[[-34,-8.59],[-34,7.397],[-29.977,11.394],[-19.908,11.394],[-6.672,24.544],[-1,22.914],[-1,-24.147],[-6.672,-25.777],[-19.908,-12.587],[-29.977,-12.587]],"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":[78,78],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/spoiler_compute.glsl b/TMessagesProj/src/main/res/raw/spoiler_compute.glsl deleted file mode 100644 index 12649abb0..000000000 --- a/TMessagesProj/src/main/res/raw/spoiler_compute.glsl +++ /dev/null @@ -1,39 +0,0 @@ -#version 310 es - -layout(local_size_x = 256) in; // This can be adjusted - -struct Particle { - vec2 position; - vec2 velocity; - float time; - float duration; -}; - -layout(std430, binding = 0) buffer ParticleBuffer { - Particle particles[]; -}; - -uniform float deltaTime; -uniform vec2 size; - -void main() { - uint id = gl_GlobalInvocationID.x; - - if (id >= uint(particles.length())) - return; - - Particle p = particles[id]; - - p.time += deltaTime * p.duration; - if (p.time >= 1.0) { - p.time = 0.0; - } - - p.velocity += vec2(.5, .5); - p.velocity *= .99; - - p.position += p.velocity; - p.position = fract(p.position / size) * size; - - particles[id] = p; -} diff --git a/TMessagesProj/src/main/res/raw/star_fill.json b/TMessagesProj/src/main/res/raw/star_fill.json new file mode 100644 index 000000000..cbaa4c8bf --- /dev/null +++ b/TMessagesProj/src/main/res/raw/star_fill.json @@ -0,0 +1 @@ +{"v":"5.10.0","fr":60,"ip":0,"op":180,"w":96,"h":96,"nm":"star","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ыефкк Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48,48,0],"ix":2,"l":2},"a":{"a":0,"k":[43,43,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[41.58,65.44],[28.227,74.618],[21.27,73.344],[20.594,69.091],[25.225,53.597],[24.348,50.905],[11.463,41.083],[10.529,34.095],[14.379,32.14],[30.595,31.742],[32.892,30.078],[38.283,14.83],[44.662,11.785],[47.718,14.83],[53.108,30.078],[55.405,31.742],[71.621,32.14],[76.498,37.246],[74.537,41.083],[61.652,50.905],[60.775,53.597],[65.406,69.091],[62.041,75.292],[57.773,74.618],[44.42,65.44]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[41.08,64.94],[27.727,74.118],[20.77,72.844],[20.094,68.591],[24.725,53.097],[23.848,50.405],[10.963,40.583],[10.029,33.595],[13.879,31.64],[30.095,31.242],[32.392,29.578],[37.783,14.33],[44.162,11.285],[47.218,14.33],[52.608,29.578],[54.905,31.242],[71.121,31.64],[75.998,36.746],[74.037,40.583],[61.152,50.405],[60.275,53.097],[64.906,68.591],[61.541,74.792],[57.273,74.118],[43.92,64.94]],"c":true},"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":37,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"ыефкк Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[43,43,0],"ix":2,"l":2},"a":{"a":0,"k":[43,43,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[-1.92,21.94],[-15.273,31.118],[-22.23,29.844],[-22.906,25.591],[-18.275,10.097],[-19.152,7.405],[-32.037,-2.417],[-32.971,-9.405],[-29.121,-11.36],[-12.905,-11.758],[-10.608,-13.422],[-5.217,-28.67],[1.162,-31.715],[4.218,-28.67],[9.608,-13.422],[11.905,-11.758],[28.121,-11.36],[32.998,-6.254],[31.037,-2.417],[18.152,7.405],[17.275,10.097],[21.906,25.591],[18.541,31.792],[14.273,31.118],[0.92,21.94]],"c":true},"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":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[43,43],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/star_stroke.json b/TMessagesProj/src/main/res/raw/star_stroke.json new file mode 100644 index 000000000..5a24482b4 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/star_stroke.json @@ -0,0 +1 @@ +{"v":"5.10.0","fr":60,"ip":0,"op":180,"w":96,"h":96,"nm":"star","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ыефкк Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[48,48,0],"ix":2,"l":2},"a":{"a":0,"k":[43,43,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[41.58,65.44],[28.227,74.618],[21.27,73.344],[20.594,69.091],[25.225,53.597],[24.348,50.905],[11.463,41.083],[10.529,34.095],[14.379,32.14],[30.595,31.742],[32.892,30.078],[38.283,14.83],[44.662,11.785],[47.718,14.83],[53.108,30.078],[55.405,31.742],[71.621,32.14],[76.498,37.246],[74.537,41.083],[61.652,50.905],[60.775,53.597],[65.406,69.091],[62.041,75.292],[57.773,74.618],[44.42,65.44]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[41.08,64.94],[27.727,74.118],[20.77,72.844],[20.094,68.591],[24.725,53.097],[23.848,50.405],[10.963,40.583],[10.029,33.595],[13.879,31.64],[30.095,31.242],[32.392,29.578],[37.783,14.33],[44.162,11.285],[47.218,14.33],[52.608,29.578],[54.905,31.242],[71.121,31.64],[75.998,36.746],[74.037,40.583],[61.152,50.405],[60.275,53.097],[64.906,68.591],[61.541,74.792],[57.273,74.118],[43.92,64.94]],"c":true},"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":6,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"ыефкк Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[43,43,0],"ix":2,"l":2},"a":{"a":0,"k":[43,43,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.855,-0.588],[0,0],[1.568,2.267],[-0.432,1.447],[0,0],[0.825,0.629],[0,0],[-1.678,2.187],[-1.514,0.037],[0,0],[-0.345,0.976],[0,0],[-2.605,-0.915],[-0.503,-1.424],[0,0],[-1.038,-0.025],[0,0],[0.068,-2.752],[1.203,-0.917],[0,0],[-0.296,-0.992],[0,0],[2.647,-0.786],[1.247,0.857],[0,0]],"o":[[0,0],[-2.274,1.563],[-0.86,-1.243],[0,0],[0.296,-0.992],[0,0],[-2.194,-1.673],[0.92,-1.199],[0,0],[1.038,-0.025],[0,0],[0.918,-2.597],[1.429,0.502],[0,0],[0.345,0.976],[0,0],[2.762,0.068],[-0.037,1.509],[0,0],[-0.825,0.629],[0,0],[0.789,2.639],[-1.452,0.431],[0,0],[-0.855,-0.588]],"v":[[-1.92,21.94],[-15.273,31.118],[-22.23,29.844],[-22.906,25.591],[-18.275,10.097],[-19.152,7.405],[-32.037,-2.417],[-32.971,-9.405],[-29.121,-11.36],[-12.905,-11.758],[-10.608,-13.422],[-5.217,-28.67],[1.162,-31.715],[4.218,-28.67],[9.608,-13.422],[11.905,-11.758],[28.121,-11.36],[32.998,-6.254],[31.037,-2.417],[18.152,7.405],[17.275,10.097],[21.906,25.591],[18.541,31.792],[14.273,31.118],[0.92,21.94]],"c":true},"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":6,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[43,43],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/thanos_fragment.glsl b/TMessagesProj/src/main/res/raw/thanos_fragment.glsl new file mode 100644 index 000000000..0e9afc1d9 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/thanos_fragment.glsl @@ -0,0 +1,18 @@ +#version 300 es + +precision highp float; + +in vec2 uvcenter; +in vec2 uvsize; +in float alpha; + +out vec4 fragColor; + +uniform sampler2D tex; + +void main() { + if (alpha <= 0.0) { + discard; + } + fragColor = texture(tex, uvcenter + gl_PointCoord * uvsize).rgba * alpha; +} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/thanos_vertex.glsl b/TMessagesProj/src/main/res/raw/thanos_vertex.glsl new file mode 100644 index 000000000..b7822055a --- /dev/null +++ b/TMessagesProj/src/main/res/raw/thanos_vertex.glsl @@ -0,0 +1,145 @@ +#version 300 es + +precision highp float; + +layout(location = 0) in vec2 inUV; +layout(location = 1) in vec2 inPosition; +layout(location = 2) in vec2 inVelocity; +layout(location = 3) in float inTime; + +out vec2 outUV; +out vec2 outPosition; +out vec2 outVelocity; +out float outTime; + +out vec2 uvcenter; +out vec2 uvsize; +out float alpha; + +uniform mat3 matrix; +uniform vec2 rectSize; +// uniform vec2 rectPos; + +uniform float reset; +uniform float time; +uniform float deltaTime; +uniform float particlesCount; +uniform vec2 size; +uniform vec3 gridSize; +uniform float seed; +uniform float longevity; +uniform float dp; +uniform vec2 offset; + +#define noiseScale 12.0 +#define noiseSpeed 0.6 +#define noiseMovement 3.0 +#define snapDuration 0.6 +#define velocityMult 0.99 +#define forceMult 18.31 +#define dampingMult 0.95 + +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; +} + +float particleEaseInValueAt(float fraction, float t) { + float windowSize = 0.8; + + float effectiveT = t; + float windowStartOffset = -windowSize; + float windowEndOffset = 1.0; + + float windowPosition = (1.0 - fraction) * windowStartOffset + fraction * windowEndOffset; + float windowT = max(0.0, min(windowSize, effectiveT - windowPosition)) / windowSize; + float localT = 1.0 - particleEaseInWindowFunction(windowT); + + return localT; +} + +void main() { + vec2 uv = inUV; + vec2 position = inPosition; + vec2 velocity = inVelocity; + float particleTime = inTime; + + float id = float(gl_VertexID); + if (reset > 0.) { + uv = vec2( + mod(id, gridSize.x), + floor(id / gridSize.x) + ) / 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; + 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; + particleTime = max(0.0, particleTime - 1.2 * deltaTime * effectFraction); + + outUV = uv; + outPosition = position; + outVelocity = velocity; + outTime = particleTime; + + alpha = max(0.0, min(0.55, particleTime) / 0.55); + gl_PointSize = (gridSize.z + 1.); + position.y = size.y - position.y; + gl_Position = vec4((position + offset) / size * 2.0 - vec2(1.0), 0.0, 1.0); + uvcenter = uv; + uvsize = (vec2(gridSize.z + 1.) / rectSize.xy); +} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/video_start.json b/TMessagesProj/src/main/res/raw/video_start.json new file mode 100644 index 000000000..f59fd293a --- /dev/null +++ b/TMessagesProj/src/main/res/raw/video_start.json @@ -0,0 +1 @@ +{"v":"5.10.1","fr":60,"ip":0,"op":60,"w":156,"h":156,"nm":"video_start","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Top 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.35]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.855]},"o":{"x":[0.167],"y":[0.096]},"t":1,"s":[0.042]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.195]},"t":2,"s":[0.328]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.119]},"t":3,"s":[0.54]},{"i":{"x":[0.833],"y":[0.839]},"o":{"x":[0.167],"y":[0.162]},"t":4,"s":[1.038]},{"i":{"x":[0.833],"y":[0.898]},"o":{"x":[0.167],"y":[0.172]},"t":5,"s":[1.564]},{"i":{"x":[0.833],"y":[1.207]},"o":{"x":[0.167],"y":[0.458]},"t":6,"s":[2.057]},{"i":{"x":[0.833],"y":[0.827]},"o":{"x":[0.167],"y":[0.059]},"t":7,"s":[2.167]},{"i":{"x":[0.833],"y":[0.697]},"o":{"x":[0.167],"y":[0.161]},"t":8,"s":[1.785]},{"i":{"x":[0.833],"y":[0.821]},"o":{"x":[0.167],"y":[0.115]},"t":9,"s":[1.374]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.156]},"t":10,"s":[0.289]},{"i":{"x":[0.833],"y":[0.76]},"o":{"x":[0.167],"y":[0.249]},"t":11,"s":[-0.957]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.128]},"t":12,"s":[-1.583]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.181]},"t":13,"s":[-2.759]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.281]},"t":14,"s":[-3.767]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.135]},"t":15,"s":[-4.193]},{"i":{"x":[0.833],"y":[0.888]},"o":{"x":[0.167],"y":[0.205]},"t":16,"s":[-4.879]},{"i":{"x":[0.833],"y":[0.814]},"o":{"x":[0.167],"y":[0.325]},"t":17,"s":[-5.351]},{"i":{"x":[0.833],"y":[0.937]},"o":{"x":[0.167],"y":[0.151]},"t":18,"s":[-5.513]},{"i":{"x":[0.833],"y":[0.375]},"o":{"x":[0.167],"y":[-0.262]},"t":19,"s":[-5.713]},{"i":{"x":[0.833],"y":[0.626]},"o":{"x":[0.167],"y":[0.096]},"t":20,"s":[-5.665]},{"i":{"x":[0.833],"y":[0.806]},"o":{"x":[0.167],"y":[0.107]},"t":21,"s":[-5.352]},{"i":{"x":[0.833],"y":[0.872]},"o":{"x":[0.167],"y":[0.146]},"t":22,"s":[-4.261]},{"i":{"x":[0.833],"y":[0.753]},"o":{"x":[0.167],"y":[0.24]},"t":23,"s":[-2.819]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.126]},"t":24,"s":[-2.05]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":25,"s":[-0.539]},{"i":{"x":[0.833],"y":[0.778]},"o":{"x":[0.167],"y":[0.274]},"t":26,"s":[0.821]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.133]},"t":27,"s":[1.416]},{"i":{"x":[0.833],"y":[0.898]},"o":{"x":[0.167],"y":[0.205]},"t":28,"s":[2.408]},{"i":{"x":[0.833],"y":[0.93]},"o":{"x":[0.167],"y":[0.46]},"t":29,"s":[3.089]},{"i":{"x":[0.833],"y":[-0.224]},"o":{"x":[0.167],"y":[-0.436]},"t":30,"s":[3.24]},{"i":{"x":[0.833],"y":[0.857]},"o":{"x":[0.167],"y":[0.089]},"t":31,"s":[3.216]},{"i":{"x":[0.833],"y":[0.724]},"o":{"x":[0.167],"y":[0.199]},"t":32,"s":[2.885]},{"i":{"x":[0.833],"y":[0.83]},"o":{"x":[0.167],"y":[0.119]},"t":33,"s":[2.647]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.163]},"t":34,"s":[2.097]},{"i":{"x":[0.833],"y":[0.766]},"o":{"x":[0.167],"y":[0.257]},"t":35,"s":[1.524]},{"i":{"x":[0.833],"y":[0.848]},"o":{"x":[0.167],"y":[0.129]},"t":36,"s":[1.249]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.185]},"t":37,"s":[0.751]},{"i":{"x":[0.833],"y":[0.788]},"o":{"x":[0.167],"y":[0.288]},"t":38,"s":[0.344]},{"i":{"x":[0.833],"y":[0.863]},"o":{"x":[0.167],"y":[0.137]},"t":39,"s":[0.178]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.213]},"t":40,"s":[-0.079]},{"i":{"x":[0.833],"y":[0.83]},"o":{"x":[0.167],"y":[0.347]},"t":41,"s":[-0.243]},{"i":{"x":[0.833],"y":[0.914]},"o":{"x":[0.167],"y":[0.164]},"t":42,"s":[-0.295]},{"i":{"x":[0.833],"y":[1.491]},"o":{"x":[0.167],"y":[2.434]},"t":43,"s":[-0.349]},{"i":{"x":[0.833],"y":[0.632]},"o":{"x":[0.167],"y":[0.071]},"t":44,"s":[-0.351]},{"i":{"x":[0.833],"y":[0.808]},"o":{"x":[0.167],"y":[0.108]},"t":45,"s":[-0.338]},{"i":{"x":[0.833],"y":[0.872]},"o":{"x":[0.167],"y":[0.147]},"t":46,"s":[-0.293]},{"i":{"x":[0.833],"y":[0.753]},"o":{"x":[0.167],"y":[0.24]},"t":47,"s":[-0.234]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.126]},"t":48,"s":[-0.203]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":49,"s":[-0.142]},{"i":{"x":[0.833],"y":[0.778]},"o":{"x":[0.167],"y":[0.274]},"t":50,"s":[-0.087]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":51,"s":[-0.063]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.198]},"t":52,"s":[-0.023]},{"i":{"x":[0.833],"y":[0.804]},"o":{"x":[0.167],"y":[0.311]},"t":53,"s":[0.006]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.145]},"t":54,"s":[0.017]},{"i":{"x":[0.833],"y":[0.904]},"o":{"x":[0.167],"y":[0.265]},"t":55,"s":[0.031]},{"i":{"x":[0.833],"y":[1.045]},"o":{"x":[0.167],"y":[0.647]},"t":56,"s":[0.038]},{"i":{"x":[0.833],"y":[0.658]},"o":{"x":[0.167],"y":[0.029]},"t":57,"s":[0.038]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.11]},"t":58,"s":[0.037]},{"t":59,"s":[0.032]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.713},"o":{"x":0.167,"y":0.167},"t":0,"s":[77.722,79.526,0],"to":[0,0.053,0],"ti":[0,-0.183,0]},{"i":{"x":0.833,"y":0.864},"o":{"x":0.167,"y":0.117},"t":1,"s":[77.722,79.844,0],"to":[0,0.183,0],"ti":[0,-0.211,0]},{"i":{"x":0.833,"y":0.736},"o":{"x":0.167,"y":0.216},"t":2,"s":[77.722,80.623,0],"to":[0,0.211,0],"ti":[0,-0.258,0]},{"i":{"x":0.833,"y":0.849},"o":{"x":0.167,"y":0.122},"t":3,"s":[77.722,81.112,0],"to":[0,0.258,0],"ti":[0,-0.32,0]},{"i":{"x":0.833,"y":0.881},"o":{"x":0.167,"y":0.186},"t":4,"s":[77.722,82.17,0],"to":[0,0.32,0],"ti":[0,-0.087,0]},{"i":{"x":0.833,"y":0.796},"o":{"x":0.167,"y":0.276},"t":5,"s":[77.722,83.03,0],"to":[0,0.087,0],"ti":[0,0.147,0]},{"i":{"x":0.833,"y":0.679},"o":{"x":0.167,"y":0.141},"t":6,"s":[77.722,82.69,0],"to":[0,-0.147,0],"ti":[0,0.348,0]},{"i":{"x":0.833,"y":0.868},"o":{"x":0.167,"y":0.112},"t":7,"s":[77.722,82.15,0],"to":[0,-0.348,0],"ti":[0,0.409,0]},{"i":{"x":0.833,"y":0.743},"o":{"x":0.167,"y":0.225},"t":8,"s":[77.722,80.604,0],"to":[0,-0.409,0],"ti":[0,0.468,0]},{"i":{"x":0.833,"y":0.837},"o":{"x":0.167,"y":0.123},"t":9,"s":[77.722,79.694,0],"to":[0,-0.468,0],"ti":[0,0.62,0]},{"i":{"x":0.833,"y":0.879},"o":{"x":0.167,"y":0.17},"t":10,"s":[77.722,77.793,0],"to":[0,-0.62,0],"ti":[0,0.442,0]},{"i":{"x":0.833,"y":0.772},"o":{"x":0.167,"y":0.266},"t":11,"s":[77.722,75.972,0],"to":[0,-0.442,0],"ti":[0,0.378,0]},{"i":{"x":0.833,"y":0.852},"o":{"x":0.167,"y":0.131},"t":12,"s":[77.722,75.142,0],"to":[0,-0.378,0],"ti":[0,0.425,0]},{"i":{"x":0.833,"y":0.884},"o":{"x":0.167,"y":0.191},"t":13,"s":[77.722,73.703,0],"to":[0,-0.425,0],"ti":[0,0.257,0]},{"i":{"x":0.833,"y":0.795},"o":{"x":0.167,"y":0.298},"t":14,"s":[77.722,72.593,0],"to":[0,-0.257,0],"ti":[0,0.176,0]},{"i":{"x":0.833,"y":0.87},"o":{"x":0.167,"y":0.14},"t":15,"s":[77.722,72.163,0],"to":[0,-0.176,0],"ti":[0,0.164,0]},{"i":{"x":0.833,"y":0.868},"o":{"x":0.167,"y":0.231},"t":16,"s":[77.722,71.535,0],"to":[0,-0.164,0],"ti":[0,0.042,0]},{"i":{"x":0.833,"y":0.396},"o":{"x":0.167,"y":0.227},"t":17,"s":[77.722,71.181,0],"to":[0,-0.042,0],"ti":[0,-0.232,0]},{"i":{"x":0.833,"y":0.774},"o":{"x":0.167,"y":0.097},"t":18,"s":[77.722,71.285,0],"to":[0,0.232,0],"ti":[0,-0.581,0]},{"i":{"x":0.833,"y":0.868},"o":{"x":0.167,"y":0.132},"t":19,"s":[77.722,72.57,0],"to":[0,0.581,0],"ti":[0,-0.579,0]},{"i":{"x":0.833,"y":0.744},"o":{"x":0.167,"y":0.227},"t":20,"s":[77.722,74.769,0],"to":[0,0.579,0],"ti":[0,-0.653,0]},{"i":{"x":0.833,"y":0.838},"o":{"x":0.167,"y":0.124},"t":21,"s":[77.722,76.045,0],"to":[0,0.653,0],"ti":[0,-0.859,0]},{"i":{"x":0.833,"y":0.879},"o":{"x":0.167,"y":0.171},"t":22,"s":[77.722,78.687,0],"to":[0,0.859,0],"ti":[0,-0.608,0]},{"i":{"x":0.833,"y":0.773},"o":{"x":0.167,"y":0.267},"t":23,"s":[77.722,81.197,0],"to":[0,0.608,0],"ti":[0,-0.517,0]},{"i":{"x":0.833,"y":0.853},"o":{"x":0.167,"y":0.132},"t":24,"s":[77.722,82.334,0],"to":[0,0.517,0],"ti":[0,-0.578,0]},{"i":{"x":0.833,"y":0.89},"o":{"x":0.167,"y":0.192},"t":25,"s":[77.722,84.298,0],"to":[0,0.578,0],"ti":[0,-0.332,0]},{"i":{"x":0.833,"y":0.878},"o":{"x":0.167,"y":0.341},"t":26,"s":[77.722,85.804,0],"to":[0,0.332,0],"ti":[0,-0.115,0]},{"i":{"x":0.833,"y":0.716},"o":{"x":0.167,"y":0.261},"t":27,"s":[77.722,86.29,0],"to":[0,0.115,0],"ti":[0,0.058,0]},{"i":{"x":0.833,"y":0.847},"o":{"x":0.167,"y":0.118},"t":28,"s":[77.722,86.491,0],"to":[0,-0.058,0],"ti":[0,0.168,0]},{"i":{"x":0.833,"y":0.712},"o":{"x":0.167,"y":0.183},"t":29,"s":[77.722,85.944,0],"to":[0,-0.168,0],"ti":[0,0.264,0]},{"i":{"x":0.833,"y":0.826},"o":{"x":0.167,"y":0.117},"t":30,"s":[77.722,85.485,0],"to":[0,-0.264,0],"ti":[0,0.392,0]},{"i":{"x":0.833,"y":0.876},"o":{"x":0.167,"y":0.16},"t":31,"s":[77.722,84.362,0],"to":[0,-0.392,0],"ti":[0,0.305,0]},{"i":{"x":0.833,"y":0.763},"o":{"x":0.167,"y":0.253},"t":32,"s":[77.722,83.135,0],"to":[0,-0.305,0],"ti":[0,0.285,0]},{"i":{"x":0.833,"y":0.847},"o":{"x":0.167,"y":0.128},"t":33,"s":[77.722,82.533,0],"to":[0,-0.285,0],"ti":[0,0.34,0]},{"i":{"x":0.833,"y":0.882},"o":{"x":0.167,"y":0.183},"t":34,"s":[77.722,81.423,0],"to":[0,-0.34,0],"ti":[0,0.219,0]},{"i":{"x":0.833,"y":0.785},"o":{"x":0.167,"y":0.284},"t":35,"s":[77.722,80.493,0],"to":[0,-0.219,0],"ti":[0,0.166,0]},{"i":{"x":0.833,"y":0.861},"o":{"x":0.167,"y":0.136},"t":36,"s":[77.722,80.107,0],"to":[0,-0.166,0],"ti":[0,0.169,0]},{"i":{"x":0.833,"y":0.889},"o":{"x":0.167,"y":0.209},"t":37,"s":[77.722,79.497,0],"to":[0,-0.169,0],"ti":[0,0.09,0]},{"i":{"x":0.833,"y":0.821},"o":{"x":0.167,"y":0.334},"t":38,"s":[77.722,79.09,0],"to":[0,-0.09,0],"ti":[0,0.048,0]},{"i":{"x":0.833,"y":0.899},"o":{"x":0.167,"y":0.156},"t":39,"s":[77.722,78.956,0],"to":[0,-0.048,0],"ti":[0,0.031,0]},{"i":{"x":0.833,"y":0.868},"o":{"x":0.167,"y":0.478},"t":40,"s":[77.722,78.801,0],"to":[0,-0.031,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.553},"o":{"x":0.167,"y":0.229},"t":41,"s":[77.722,78.768,0],"to":[0,-0.002,0],"ti":[0,-0.017,0]},{"i":{"x":0.833,"y":0.795},"o":{"x":0.167,"y":0.103},"t":42,"s":[77.722,78.786,0],"to":[0,0.017,0],"ti":[0,-0.034,0]},{"i":{"x":0.833,"y":0.871},"o":{"x":0.167,"y":0.141},"t":43,"s":[77.722,78.868,0],"to":[0,0.034,0],"ti":[0,-0.031,0]},{"i":{"x":0.833,"y":0.749},"o":{"x":0.167,"y":0.234},"t":44,"s":[77.722,78.987,0],"to":[0,0.031,0],"ti":[0,-0.033,0]},{"i":{"x":0.833,"y":0.84},"o":{"x":0.167,"y":0.125},"t":45,"s":[77.722,79.053,0],"to":[0,0.033,0],"ti":[0,-0.042,0]},{"i":{"x":0.833,"y":0.88},"o":{"x":0.167,"y":0.174},"t":46,"s":[77.722,79.186,0],"to":[0,0.042,0],"ti":[0,-0.029,0]},{"i":{"x":0.833,"y":0.775},"o":{"x":0.167,"y":0.271},"t":47,"s":[77.722,79.308,0],"to":[0,0.029,0],"ti":[0,-0.024,0]},{"i":{"x":0.833,"y":0.854},"o":{"x":0.167,"y":0.133},"t":48,"s":[77.722,79.362,0],"to":[0,0.024,0],"ti":[0,-0.027,0]},{"i":{"x":0.833,"y":0.885},"o":{"x":0.167,"y":0.195},"t":49,"s":[77.722,79.454,0],"to":[0,0.027,0],"ti":[0,-0.016,0]},{"i":{"x":0.833,"y":0.8},"o":{"x":0.167,"y":0.305},"t":50,"s":[77.722,79.523,0],"to":[0,0.016,0],"ti":[0,-0.01,0]},{"i":{"x":0.833,"y":0.874},"o":{"x":0.167,"y":0.143},"t":51,"s":[77.722,79.549,0],"to":[0,0.01,0],"ti":[0,-0.009,0]},{"i":{"x":0.833,"y":0.899},"o":{"x":0.167,"y":0.247},"t":52,"s":[77.722,79.585,0],"to":[0,0.009,0],"ti":[0,-0.004,0]},{"i":{"x":0.833,"y":0.884},"o":{"x":0.167,"y":0.484},"t":53,"s":[77.722,79.603,0],"to":[0,0.004,0],"ti":[0,-0.001,0]},{"i":{"x":0.833,"y":0.492},"o":{"x":0.167,"y":0.278},"t":54,"s":[77.722,79.607,0],"to":[0,0.001,0],"ti":[0,0.001,0]},{"i":{"x":0.833,"y":0.857},"o":{"x":0.167,"y":0.099},"t":55,"s":[77.722,79.607,0],"to":[0,-0.001,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.724},"o":{"x":0.167,"y":0.199},"t":56,"s":[77.722,79.598,0],"to":[0,-0.002,0],"ti":[0,0.003,0]},{"i":{"x":0.833,"y":0.83},"o":{"x":0.167,"y":0.119},"t":57,"s":[77.722,79.592,0],"to":[0,-0.003,0],"ti":[0,0.005,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.163},"t":58,"s":[77.722,79.579,0],"to":[0,-0.005,0],"ti":[0,0.002,0]},{"t":59,"s":[77.722,79.564,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-0.918,5,0],"ix":1,"l":2},"s":{"a":0,"k":[30.469,30.469,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"slash","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,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":[[-29,-29],[29,29]],"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":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[100]},{"t":17,"s":[0]}],"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":7,"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":[69,80],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"base","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.745,2.55],[0,0],[2.734,2.734],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[2.672,2.672],[0,0],[2.734,-2.734],[0,0],[0,0],[0,0]],"v":[[156.5,0.5],[156.5,156.5],[0.5,156.5],[0.5,21.398],[93.55,114.45],[103.261,114.632],[103.45,114.45],[103.45,104.55],[0.5,1.601],[0.5,0.5]],"c":true}]},{"t":17,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.745,2.55],[0,0],[2.734,2.734],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[2.672,2.672],[0,0],[2.734,-2.734],[0,0],[0,0],[0,0]],"v":[[156.5,0.5],[156.5,156.5],[0.5,156.5],[0.5,21.398],[33.55,54.45],[43.261,54.632],[43.45,54.45],[43.45,44.55],[0.5,1.601],[0.5,0.5]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,0],[0,-6.075],[0,0],[6.075,0],[0,0],[0,6.075],[0,0]],"o":[[0,0],[6.075,0],[0,0],[0,6.075],[0,0],[-6.075,0],[0,0],[0,-6.075]],"v":[[-24,-23],[7,-23],[18,-12],[18,12],[7,23],[-24,23],[-35,12],[-35,-12]],"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.5],[0,0],[-1.205,0.992],[0,0],[-1.149,-1.173],[0,-0.704],[0,0],[1.719,0],[0.569,0.461],[0,0]],"o":[[0,0],[0,-1.485],[0,0],[1.279,-1.054],[0.513,0.524],[0,0],[0,1.577],[-0.759,0],[0,0],[-1.225,-0.993]],"v":[[23.747,6.301],[23.747,-5.25],[25.64,-9.143],[36.808,-18.343],[41.203,-18.126],[42,-16.219],[42,17.124],[38.887,19.979],[36.826,19.263],[25.674,10.222]],"c":true},"ix":2},"nm":"Path 3","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":[78,78],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/video_stop.json b/TMessagesProj/src/main/res/raw/video_stop.json new file mode 100644 index 000000000..31b10a271 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/video_stop.json @@ -0,0 +1 @@ +{"v":"5.10.1","fr":60,"ip":0,"op":60,"w":156,"h":156,"nm":"video_stop","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Top 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1.004]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.689]},"o":{"x":[0.167],"y":[0.083]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.638]},"o":{"x":[0.167],"y":[0.114]},"t":2,"s":[-0.042]},{"i":{"x":[0.833],"y":[0.808]},"o":{"x":[0.167],"y":[0.108]},"t":3,"s":[-0.157]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.148]},"t":4,"s":[-0.54]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.162]},"t":5,"s":[-1.038]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.256]},"t":6,"s":[-1.564]},{"i":{"x":[0.833],"y":[0.942]},"o":{"x":[0.167],"y":[0.144]},"t":7,"s":[-1.817]},{"i":{"x":[0.833],"y":[0.368]},"o":{"x":[0.167],"y":[-0.195]},"t":8,"s":[-2.167]},{"i":{"x":[0.833],"y":[0.785]},"o":{"x":[0.167],"y":[0.096]},"t":9,"s":[-2.062]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.136]},"t":10,"s":[-1.374]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.23]},"t":11,"s":[-0.289]},{"i":{"x":[0.833],"y":[0.839]},"o":{"x":[0.167],"y":[0.124]},"t":12,"s":[0.327]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":13,"s":[1.583]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.269]},"t":14,"s":[2.759]},{"i":{"x":[0.833],"y":[0.854]},"o":{"x":[0.167],"y":[0.132]},"t":15,"s":[3.288]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.193]},"t":16,"s":[4.193]},{"i":{"x":[0.833],"y":[0.834]},"o":{"x":[0.167],"y":[0.302]},"t":17,"s":[4.879]},{"i":{"x":[0.833],"y":[1.096]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[5.14]},{"i":{"x":[0.833],"y":[0.84]},"o":{"x":[0.167],"y":[0.045]},"t":19,"s":[5.401]},{"i":{"x":[0.833],"y":[0.706]},"o":{"x":[0.167],"y":[0.173]},"t":20,"s":[4.839]},{"i":{"x":[0.833],"y":[0.824]},"o":{"x":[0.167],"y":[0.116]},"t":21,"s":[4.319]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.158]},"t":22,"s":[3.002]},{"i":{"x":[0.833],"y":[0.762]},"o":{"x":[0.167],"y":[0.251]},"t":23,"s":[1.531]},{"i":{"x":[0.833],"y":[0.846]},"o":{"x":[0.167],"y":[0.128]},"t":24,"s":[0.802]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.182]},"t":25,"s":[-0.555]},{"i":{"x":[0.833],"y":[0.791]},"o":{"x":[0.167],"y":[0.282]},"t":26,"s":[-1.705]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.139]},"t":27,"s":[-2.186]},{"i":{"x":[0.833],"y":[0.93]},"o":{"x":[0.167],"y":[0.342]},"t":28,"s":[-2.912]},{"i":{"x":[0.833],"y":[0.264]},"o":{"x":[0.167],"y":[-0.443]},"t":29,"s":[-3.145]},{"i":{"x":[0.833],"y":[0.781]},"o":{"x":[0.167],"y":[0.094]},"t":30,"s":[-3.108]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.135]},"t":31,"s":[-2.818]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.229]},"t":32,"s":[-2.348]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.124]},"t":33,"s":[-2.08]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":34,"s":[-1.528]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.268]},"t":35,"s":[-1.009]},{"i":{"x":[0.833],"y":[0.853]},"o":{"x":[0.167],"y":[0.132]},"t":36,"s":[-0.775]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.193]},"t":37,"s":[-0.372]},{"i":{"x":[0.833],"y":[0.797]},"o":{"x":[0.167],"y":[0.301]},"t":38,"s":[-0.066]},{"i":{"x":[0.833],"y":[0.871]},"o":{"x":[0.167],"y":[0.141]},"t":39,"s":[0.051]},{"i":{"x":[0.833],"y":[0.897]},"o":{"x":[0.167],"y":[0.237]},"t":40,"s":[0.219]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.431]},"t":41,"s":[0.31]},{"i":{"x":[0.833],"y":[1.258]},"o":{"x":[0.167],"y":[0.345]},"t":42,"s":[0.332]},{"i":{"x":[0.833],"y":[0.85]},"o":{"x":[0.167],"y":[0.063]},"t":43,"s":[0.339]},{"i":{"x":[0.833],"y":[0.715]},"o":{"x":[0.167],"y":[0.187]},"t":44,"s":[0.31]},{"i":{"x":[0.833],"y":[0.827]},"o":{"x":[0.167],"y":[0.118]},"t":45,"s":[0.287]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.16]},"t":46,"s":[0.232]},{"i":{"x":[0.833],"y":[0.764]},"o":{"x":[0.167],"y":[0.254]},"t":47,"s":[0.172]},{"i":{"x":[0.833],"y":[0.847]},"o":{"x":[0.167],"y":[0.129]},"t":48,"s":[0.143]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.183]},"t":49,"s":[0.089]},{"i":{"x":[0.833],"y":[0.786]},"o":{"x":[0.167],"y":[0.285]},"t":50,"s":[0.045]},{"i":{"x":[0.833],"y":[0.862]},"o":{"x":[0.167],"y":[0.136]},"t":51,"s":[0.026]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.167],"y":[0.21]},"t":52,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.823]},"o":{"x":[0.167],"y":[0.337]},"t":53,"s":[-0.022]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.157]},"t":54,"s":[-0.029]},{"i":{"x":[0.833],"y":[0.981]},"o":{"x":[0.167],"y":[0.549]},"t":55,"s":[-0.036]},{"i":{"x":[0.833],"y":[0.564]},"o":{"x":[0.167],"y":[-0.024]},"t":56,"s":[-0.037]},{"i":{"x":[0.833],"y":[0.799]},"o":{"x":[0.167],"y":[0.103]},"t":57,"s":[-0.036]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.142]},"t":58,"s":[-0.032]},{"t":59,"s":[-0.026]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.713},"o":{"x":0.167,"y":0.167},"t":0,"s":[77.722,79.526,0],"to":[0,-0.053,0],"ti":[0,0.183,0]},{"i":{"x":0.833,"y":0.864},"o":{"x":0.167,"y":0.117},"t":1,"s":[77.722,79.208,0],"to":[0,-0.183,0],"ti":[0,0.211,0]},{"i":{"x":0.833,"y":0.736},"o":{"x":0.167,"y":0.216},"t":2,"s":[77.722,78.429,0],"to":[0,-0.211,0],"ti":[0,0.258,0]},{"i":{"x":0.833,"y":0.834},"o":{"x":0.167,"y":0.122},"t":3,"s":[77.722,77.94,0],"to":[0,-0.258,0],"ti":[0,0.351,0]},{"i":{"x":0.833,"y":0.856},"o":{"x":0.167,"y":0.168},"t":4,"s":[77.722,76.881,0],"to":[0,-0.351,0],"ti":[0,0.302,0]},{"i":{"x":0.833,"y":0.894},"o":{"x":0.167,"y":0.197},"t":5,"s":[77.722,75.834,0],"to":[0,-0.302,0],"ti":[0,0.118,0]},{"i":{"x":0.833,"y":0.567},"o":{"x":0.167,"y":0.388},"t":6,"s":[77.722,75.068,0],"to":[0,-0.118,0],"ti":[0,-0.156,0]},{"i":{"x":0.833,"y":0.849},"o":{"x":0.167,"y":0.103},"t":7,"s":[77.722,75.125,0],"to":[0,0.156,0],"ti":[0,-0.265,0]},{"i":{"x":0.833,"y":0.715},"o":{"x":0.167,"y":0.187},"t":8,"s":[77.722,76.004,0],"to":[0,0.265,0],"ti":[0,-0.404,0]},{"i":{"x":0.833,"y":0.827},"o":{"x":0.167,"y":0.118},"t":9,"s":[77.722,76.712,0],"to":[0,0.404,0],"ti":[0,-0.595,0]},{"i":{"x":0.833,"y":0.876},"o":{"x":0.167,"y":0.16},"t":10,"s":[77.722,78.426,0],"to":[0,0.595,0],"ti":[0,-0.46,0]},{"i":{"x":0.833,"y":0.763},"o":{"x":0.167,"y":0.254},"t":11,"s":[77.722,80.28,0],"to":[0,0.46,0],"ti":[0,-0.428,0]},{"i":{"x":0.833,"y":0.847},"o":{"x":0.167,"y":0.129},"t":12,"s":[77.722,81.184,0],"to":[0,0.428,0],"ti":[0,-0.508,0]},{"i":{"x":0.833,"y":0.882},"o":{"x":0.167,"y":0.183},"t":13,"s":[77.722,82.846,0],"to":[0,0.508,0],"ti":[0,-0.327,0]},{"i":{"x":0.833,"y":0.785},"o":{"x":0.167,"y":0.285},"t":14,"s":[77.722,84.232,0],"to":[0,0.327,0],"ti":[0,-0.246,0]},{"i":{"x":0.833,"y":0.875},"o":{"x":0.167,"y":0.136},"t":15,"s":[77.722,84.806,0],"to":[0,0.246,0],"ti":[0,-0.226,0]},{"i":{"x":0.833,"y":0.873},"o":{"x":0.167,"y":0.25},"t":16,"s":[77.722,85.708,0],"to":[0,0.226,0],"ti":[0,-0.042,0]},{"i":{"x":0.833,"y":0.524},"o":{"x":0.167,"y":0.244},"t":17,"s":[77.722,86.16,0],"to":[0,0.042,0],"ti":[0,0.217,0]},{"i":{"x":0.833,"y":0.79},"o":{"x":0.167,"y":0.101},"t":18,"s":[77.722,85.96,0],"to":[0,-0.217,0],"ti":[0,0.464,0]},{"i":{"x":0.833,"y":0.87},"o":{"x":0.167,"y":0.138},"t":19,"s":[77.722,84.857,0],"to":[0,-0.464,0],"ti":[0,0.437,0]},{"i":{"x":0.833,"y":0.748},"o":{"x":0.167,"y":0.232},"t":20,"s":[77.722,83.177,0],"to":[0,-0.437,0],"ti":[0,0.475,0]},{"i":{"x":0.833,"y":0.839},"o":{"x":0.167,"y":0.124},"t":21,"s":[77.722,82.236,0],"to":[0,-0.475,0],"ti":[0,0.614,0]},{"i":{"x":0.833,"y":0.879},"o":{"x":0.167,"y":0.173},"t":22,"s":[77.722,80.328,0],"to":[0,-0.614,0],"ti":[0,0.428,0]},{"i":{"x":0.833,"y":0.775},"o":{"x":0.167,"y":0.27},"t":23,"s":[77.722,78.552,0],"to":[0,-0.428,0],"ti":[0,0.358,0]},{"i":{"x":0.833,"y":0.858},"o":{"x":0.167,"y":0.132},"t":24,"s":[77.722,77.757,0],"to":[0,-0.358,0],"ti":[0,0.386,0]},{"i":{"x":0.833,"y":0.897},"o":{"x":0.167,"y":0.201},"t":25,"s":[77.722,76.403,0],"to":[0,-0.386,0],"ti":[0,0.197,0]},{"i":{"x":0.833,"y":0.886},"o":{"x":0.167,"y":0.441},"t":26,"s":[77.722,75.443,0],"to":[0,-0.197,0],"ti":[0,0.038,0]},{"i":{"x":0.833,"y":0.495},"o":{"x":0.167,"y":0.307},"t":27,"s":[77.722,75.22,0],"to":[0,-0.038,0],"ti":[0,-0.07,0]},{"i":{"x":0.833,"y":0.855},"o":{"x":0.167,"y":0.1},"t":28,"s":[77.722,75.218,0],"to":[0,0.07,0],"ti":[0,-0.122,0]},{"i":{"x":0.833,"y":0.722},"o":{"x":0.167,"y":0.196},"t":29,"s":[77.722,75.639,0],"to":[0,0.122,0],"ti":[0,-0.173,0]},{"i":{"x":0.833,"y":0.829},"o":{"x":0.167,"y":0.119},"t":30,"s":[77.722,75.95,0],"to":[0,0.173,0],"ti":[0,-0.249,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.167,"y":0.162},"t":31,"s":[77.722,76.677,0],"to":[0,0.249,0],"ti":[0,-0.189,0]},{"i":{"x":0.833,"y":0.765},"o":{"x":0.167,"y":0.256},"t":32,"s":[77.722,77.443,0],"to":[0,0.189,0],"ti":[0,-0.173,0]},{"i":{"x":0.833,"y":0.848},"o":{"x":0.167,"y":0.129},"t":33,"s":[77.722,77.812,0],"to":[0,0.173,0],"ti":[0,-0.204,0]},{"i":{"x":0.833,"y":0.883},"o":{"x":0.167,"y":0.185},"t":34,"s":[77.722,78.483,0],"to":[0,0.204,0],"ti":[0,-0.13,0]},{"i":{"x":0.833,"y":0.787},"o":{"x":0.167,"y":0.287},"t":35,"s":[77.722,79.035,0],"to":[0,0.13,0],"ti":[0,-0.096,0]},{"i":{"x":0.833,"y":0.863},"o":{"x":0.167,"y":0.137},"t":36,"s":[77.722,79.261,0],"to":[0,0.096,0],"ti":[0,-0.096,0]},{"i":{"x":0.833,"y":0.89},"o":{"x":0.167,"y":0.212},"t":37,"s":[77.722,79.612,0],"to":[0,0.096,0],"ti":[0,-0.05,0]},{"i":{"x":0.833,"y":0.828},"o":{"x":0.167,"y":0.344},"t":38,"s":[77.722,79.839,0],"to":[0,0.05,0],"ti":[0,-0.025,0]},{"i":{"x":0.833,"y":0.904},"o":{"x":0.167,"y":0.162},"t":39,"s":[77.722,79.912,0],"to":[0,0.025,0],"ti":[0,-0.014,0]},{"i":{"x":0.833,"y":0.807},"o":{"x":0.167,"y":0.617},"t":40,"s":[77.722,79.989,0],"to":[0,0.014,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.617},"o":{"x":0.167,"y":0.143},"t":41,"s":[77.722,79.996,0],"to":[0,-0.002,0],"ti":[0,0.012,0]},{"i":{"x":0.833,"y":0.805},"o":{"x":0.167,"y":0.107},"t":42,"s":[77.722,79.979,0],"to":[0,-0.012,0],"ti":[0,0.023,0]},{"i":{"x":0.833,"y":0.872},"o":{"x":0.167,"y":0.146},"t":43,"s":[77.722,79.921,0],"to":[0,-0.023,0],"ti":[0,0.02,0]},{"i":{"x":0.833,"y":0.753},"o":{"x":0.167,"y":0.239},"t":44,"s":[77.722,79.844,0],"to":[0,-0.02,0],"ti":[0,0.021,0]},{"i":{"x":0.833,"y":0.841},"o":{"x":0.167,"y":0.126},"t":45,"s":[77.722,79.802,0],"to":[0,-0.021,0],"ti":[0,0.026,0]},{"i":{"x":0.833,"y":0.88},"o":{"x":0.167,"y":0.176},"t":46,"s":[77.722,79.72,0],"to":[0,-0.026,0],"ti":[0,0.018,0]},{"i":{"x":0.833,"y":0.777},"o":{"x":0.167,"y":0.273},"t":47,"s":[77.722,79.646,0],"to":[0,-0.018,0],"ti":[0,0.014,0]},{"i":{"x":0.833,"y":0.856},"o":{"x":0.167,"y":0.133},"t":48,"s":[77.722,79.614,0],"to":[0,-0.014,0],"ti":[0,0.016,0]},{"i":{"x":0.833,"y":0.886},"o":{"x":0.167,"y":0.197},"t":49,"s":[77.722,79.56,0],"to":[0,-0.016,0],"ti":[0,0.009,0]},{"i":{"x":0.833,"y":0.803},"o":{"x":0.167,"y":0.31},"t":50,"s":[77.722,79.52,0],"to":[0,-0.009,0],"ti":[0,0.006,0]},{"i":{"x":0.833,"y":0.877},"o":{"x":0.167,"y":0.145},"t":51,"s":[77.722,79.505,0],"to":[0,-0.006,0],"ti":[0,0.005,0]},{"i":{"x":0.833,"y":0.903},"o":{"x":0.167,"y":0.26},"t":52,"s":[77.722,79.485,0],"to":[0,-0.005,0],"ti":[0,0.002,0]},{"i":{"x":0.833,"y":0.835},"o":{"x":0.167,"y":0.56},"t":53,"s":[77.722,79.476,0],"to":[0,-0.002,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.613},"o":{"x":0.167,"y":0.164},"t":54,"s":[77.722,79.475,0],"to":[0,0,0],"ti":[0,-0.001,0]},{"i":{"x":0.833,"y":0.861},"o":{"x":0.167,"y":0.106},"t":55,"s":[77.722,79.476,0],"to":[0,0.001,0],"ti":[0,-0.002,0]},{"i":{"x":0.833,"y":0.731},"o":{"x":0.167,"y":0.209},"t":56,"s":[77.722,79.482,0],"to":[0,0.002,0],"ti":[0,-0.002,0]},{"i":{"x":0.833,"y":0.832},"o":{"x":0.167,"y":0.121},"t":57,"s":[77.722,79.486,0],"to":[0,0.002,0],"ti":[0,-0.003,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.166},"t":58,"s":[77.722,79.495,0],"to":[0,0.003,0],"ti":[0,-0.001,0]},{"t":59,"s":[77.722,79.504,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-0.918,5,0],"ix":1,"l":2},"s":{"a":0,"k":[30.469,30.469,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"slash","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,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":[[-29,-29],[29,29]],"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":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":3,"s":[0]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"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":[69,80],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"base","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.006,-0.008,0],"ix":2,"l":2},"a":{"a":0,"k":[78,78,0],"ix":1,"l":2},"s":{"a":0,"k":[328.205,328.205,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.6,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.745,2.55],[0,0],[2.734,2.734],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[2.672,2.672],[0,0],[2.734,-2.734],[0,0],[0,0],[0,0]],"v":[[156.5,0.5],[156.5,156.5],[0.5,156.5],[0.5,21.398],[33.55,54.45],[43.261,54.632],[43.45,54.45],[43.45,44.55],[0.5,1.601],[0.5,0.5]],"c":true}]},{"t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.745,2.55],[0,0],[2.734,2.734],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[2.672,2.672],[0,0],[2.734,-2.734],[0,0],[0,0],[0,0]],"v":[[156.5,0.5],[156.5,156.5],[0.5,156.5],[0.5,21.398],[93.55,114.45],[103.261,114.632],[103.45,114.45],[103.45,104.55],[0.5,1.601],[0.5,0.5]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,0],[0,-6.075],[0,0],[6.075,0],[0,0],[0,6.075],[0,0]],"o":[[0,0],[6.075,0],[0,0],[0,6.075],[0,0],[-6.075,0],[0,0],[0,-6.075]],"v":[[-24,-23],[7,-23],[18,-12],[18,12],[7,23],[-24,23],[-35,12],[-35,-12]],"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.5],[0,0],[-1.205,0.992],[0,0],[-1.149,-1.173],[0,-0.704],[0,0],[1.719,0],[0.569,0.461],[0,0]],"o":[[0,0],[0,-1.485],[0,0],[1.279,-1.054],[0.513,0.524],[0,0],[0,1.577],[-0.759,0],[0,0],[-1.225,-0.993]],"v":[[23.747,6.301],[23.747,-5.25],[25.64,-9.143],[36.808,-18.343],[41.203,-18.126],[42,-16.219],[42,17.124],[38.887,19.979],[36.826,19.263],[25.674,10.222]],"c":true},"ix":2},"nm":"Path 3","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":[78,78],"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}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index f2c3d2f8a..486ef9e39 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -241,6 +241,7 @@ Select Chat Choose Bot Choose User + Choose Users Choose Group Choose Channel Select Chats @@ -988,6 +989,14 @@ un1 disabled anti-spam un1 changed channel color from %1$s to %2$s un1 changed channel emoji from %1$s to %2$s + un1 changed channel color and icon from %1$s to %2$s + un1 changed channel profile color and icon from %1$s to %2$s + un1 changed channel emoji status from %1$s to %2$s + un1 changed channel emoji status to %2$s + un1 changed channel emoji status from %1$s to %2$s (for %3$s) + un1 changed channel emoji status to %2$s (for %3$s) + un1 changed channel wallpaper + un1 removed channel wallpaper none New Broadcast List @@ -1013,6 +1022,7 @@ Search Recent Files Free %1$s of %2$s Unknown error + Unknown error: %s Access error File size shouldn\'t be greater than %1$s Storage not mounted @@ -2183,7 +2193,7 @@ Motion Change Chat Background Change Your Color - Change Name Color + Appearance Chat Background Reset Chat Backgrounds Remove all uploaded chat backgrounds and restore the pre-installed ones. @@ -2272,6 +2282,7 @@ Terms of Service By signing up,\nyou agree to the *Terms of Service*. https://telegram.org/privacy + https://telegram.org/tos https://telegram.org/tos/mini-apps Delete language pack Are you sure you want to delete **%1$s** language pack? @@ -2448,6 +2459,8 @@ Other Paste Flip + Cut Out + Undo Cut Paste from clipboard Proxy Settings Proxy Details @@ -3604,6 +3617,8 @@ Close anyway Allow messaging Allow this bot to send you messages? + You can select maximum %1$d user. + You can select maximum %1$d users. Done Open @@ -3730,6 +3745,8 @@ Self-Destructing Video Photo has expired Video has expired + Round video has expired + Voice expired GIF Location Live Location @@ -4063,6 +4080,7 @@ Ongoing Voice Chat Ongoing Live Stream End call + End Call Another call in progress You currently have an ongoing call with **%1$s**. Would you like to hang up and start a new one with **%2$s**? End call with **%1$s** and start voice chat in **%2$s**? @@ -4399,6 +4417,13 @@ Record live stream Choose how to record this chat Start Recording + Rate this call + Please rate the quality of this call. + Encryption key of this call + This call is end to end encrypted + Weak network signal + Hide Emoji + Your microphone is turned off **Oops!** Telegram doesn\'t see any stream coming from your streaming app.\n\nPlease make sure you entered the right Server URL and Stream Key in your app. %1$s is currently not broadcasting live stream data to Telegram. @@ -5507,9 +5532,12 @@ Apply Theme Reset Theme No Theme + No Wallpaper You changed the chat theme to %1$s %1$s changed the chat theme to %2$s + %1$s changed the channel theme to %2$s %1$s disabled the chat theme + %1$s disabled the channel theme You disabled the chat theme Save changes? Do you want to apply the new theme for this chat? @@ -5916,12 +5944,43 @@ You need an official Telegram app to subscribe to **Telegram Premium**.\n\nOnce subscribed, you will be able to use the benefits of Telegram Premium in any apps that support it, including unofficial ones. Install official app Gift Subscription for %1$s + Gift %1$d Subscription for %2$s + Gift %1$d Subscriptions for %2$s -%1$d%% %1$s / month %1$s/month %1$s/year You can review the list of features and terms of use for Telegram Premium *here*. Gift Premium + Premium Gifting + Activate For Free + You already have Telegram Premium + You can activate this gift code after %1$s or **send the link** to a friend. + Use Gift + Gift Sent! + Gifts Sent! + **%1$s** + **%1$s**, **%2$s** + **%1$s**, **%2$s**, **%3$s** + %1$s have been notified about the gifts you purchased. + %2$s and **%1$d** other have been notified about the gifts you purchased. + %2$s and **%1$d** others have been notified about the gifts you purchased. + Give %1$s access to exclusive features. + Give %2$s and **%1$d** more friend access to exclusive features. + Give %2$s and **%1$d** more friends access to exclusive features. + They now have access to additional features. + **%1$s** now has access to additional features. + Frequent Contacts + Search people to gift Premium to... + You will receive ⚡ **%1$d** boost. + You will receive ⚡ **%1$d** boosts. + By gifting Telegram Premium you agree to the **Telegram Terms of Service** and %1$s + **Privacy Policy**. + Choose Recipients + Proceed + This link allows you or **anyone you choose** to activate a %1$s. + **Telegram Premium** subscription + What\'s included Gift Telegram Premium Let **%1$s** enjoy exclusive features of Telegram with **Telegram Premium**. Telegram Premium @@ -6325,6 +6384,12 @@ You shared a user with un2 You shared a chat with un2 You shared a channel with un2 + You shared a user with un2 + You shared a users with un2 + You shared a chat with un2 + You shared a chats with un2 + You shared a channel with un2 + You shared a channels with un2 Hide with spoiler Remove spoiler Update Public Photo @@ -6496,6 +6561,7 @@ Animated spoiler effect Night theme blur Zoom animations + Dust-effect deletion Animations in Calls Autoplay Videos Autoplay GIFs @@ -6631,6 +6697,7 @@ Set Background From Gallery Setting new wallpaper... You set a new wallpaper for this chat + Channel set a new wallpaper You set the same wallpaper for the chat %s set a new wallpaper for this chat %s set a new wallpaper for this chat @@ -6748,7 +6815,11 @@ Theme will also be applied for %s Background dimming Apply the wallpaper in this chat + Du Rove\'s Channel + Breaking News + Details to follow shortly.\nStay tuned! %s will be able to apply this wallpaper + All subscribers will see this wallpaper APPLY FOR THIS CHAT Remove Wallpaper Set a Color as Wallpaper @@ -7057,6 +7128,7 @@ Automatically enabled Disabled No one has viewed this story so far. + No one has reacted to this story so far. You are seeing this story because **%s** added you to their list of Close Friends Only some contacts **%s** selected can view this story. Only **%s’s** contacts can view this story. @@ -7065,6 +7137,7 @@ Saved Stories New Story Edit + Repost Allow Screenshots **Select people** who won’t see your stories. **%d people** won’t see your stories. @@ -7172,7 +7245,7 @@ Hide Stories Unhide Stories Subscribe to **Telegram Premium** to add links and text formatting to your stories. - Subscribe to **Telegram Premium** to add up to 5 reactions and tags to a story. + Subscribe to **Telegram Premium** to add up to %d reactions and tags to a story. Maximum Length Reach Increase this limit **%1$d** times to **%2$s** symbols by subscribing to __Telegram Premium.__ To unlock viewers’ lists for expired and saved stories, subscribe to **Telegram Premium.** @@ -7215,6 +7288,7 @@ Stealth Mode Is Active Please wait until the **Stealth Mode** is ready to use again. View Location > + View Message > Like Long tap for more reactions Add Reactions... @@ -7233,8 +7307,10 @@ You can select maximum %1$d reactions. All viewers Reactions First + Reposts First Newest First Choose the order for the 
list of viewers. + Choose the order for the 
list of reactions. None of your contacts viewed this story. Viewers You are in Stealth Mode now @@ -7248,10 +7324,11 @@ No views To unlock viewers’ lists for expired and saved stories, subscribe to **Telegram Premium.** %d like - %d likes - %d likes - %d likes %d likes + %d repost + %d reposts + %d reaction + %d reactions You can post **%1$d** stories in **24** hours.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. Sorry, you can’t post more than **%1$d** stories in **24** hours. You can post **%1$d** stories in a week.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. @@ -7365,6 +7442,7 @@ To be distributed %1$dm Giveaway + Giveaway results Channel started a giveaway The recipient will be selected when the giveaway ends. Incomplete Giveaway @@ -7437,11 +7515,22 @@ Gift link forwarded to **%1$s**. Gift link forwarded to **Saved Messages**. Premium Subscriptions Gifted + Enter Your Prize + Additional Prizes + Show Winners + Choose whether to make the list of winners public when the giveaway ends. + Turn this on if you want to give the winners your own prizes in addition to Premium subscriptions. + All prizes: **%1$d** %2$s with Telegram Premium subscriptions for %3$s. + All prizes: **%1$d** %2$s with Telegram Premium subscriptions for %3$s. + All prizes: **%1$d** Telegram Premium subscriptions for %2$s. + All prizes: **%1$d** Telegram Premium subscriptions for %2$s. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscription for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. This giveaway is sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers. + **%2$s** also included **%1$d** **%3$s** in the prizes. Admins of the channel are responsible for delivering these prizes. + **%2$s** also included **%1$d** **%3$s** in the prizes. Admins of the channel are responsible for delivering these prizes. On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s**. On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s**. On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s**. @@ -7583,12 +7672,15 @@ %d other channels %d other channels To boost **%1$s**, get more boosts by gifting **Telegram Premium** to a friend. + To boost **%2$s**, get **%1$d** more boost by gifting **Telegram Premium** to a friend. + To boost **%2$s**, get **%1$d** more boosts by gifting **Telegram Premium** to a friend. Reassign Boosts - To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boost. - To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts. - To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts. - To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts. - To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts. + To boost **%2$s**, reassign a previous boost or %3$s to a friend to get **%1$d** additional boost. + To boost **%2$s**, reassign a previous boost or %3$s to a friend to get **%1$d** additional boosts. + **gift Telegram Premium** + Send gifts **to your friends!** + Give Telegram Premium for Christmas. + You can gift Telegram Premium later in Settings Remove your boost from available in %1$s Duration of Premium subscriptions @@ -7597,6 +7689,14 @@ from %1$s **Winners Selection Date** **Giveaway Prizes** + **Winners Selected!** + **Winner** + **Winners** + All winners received gift links in private messages. + **And %1$d more!** + **And %1$d more!** + %1$d winner of the **Giveaway** was randomly selected by Telegram. + %1$d winners of the **Giveaway** were randomly selected by Telegram. **%1$d** Telegram Premium **%1$d** Telegram Premium **%1$d** Telegram Premium @@ -7612,7 +7712,10 @@ All subscribers of the channels: New subscribers of the channel: New subscribers of the channels: - You can’t add up more than 5 reactions tags to a story. + with + **%1$d** %2$s + **%1$d** %2$s + You can’t add up more than %d reactions tags to a story. Someone just got access to your messages! Yes, it’s me No, it’s not me! @@ -7635,6 +7738,7 @@ Boosts to level up Your channel is currently boosted by these users. Boost Channel + Unlock Features BOOST Enable stories for the channel Enable stories for channel @@ -7655,12 +7759,19 @@ Terms of Use boost expires on %s boosts expire on %s - Your channel needs to reach **Level %d** to change channel color.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel color to selected.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel profile color to selected.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel link style icon.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel profile icon.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to set channel emoji status.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel wallpaper.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach **Level %d** to change channel wallpaper to custom photo.\n\nAsk your **Premium** subscribers to boost your channel with this link: Your channel needs %s to enable posting stories.\n\nAsk your **Premium** subscribers to boost your channel with this link: Your channel needs %1$s to be able post **%2$s** per day.\n\nAsk your Premium subscribers to boost your channel with this link: This channel need %s to enable stories. Help make it possible! This channel need %1$s to be able post **%2$s** per day. Help make it possible! This channel need %s more boosts to enable stories. + **%1$s** needs %2$s to unlock new features. Help upgrade channel This channel reached **Level 1** and can now post stories. This channel reached **Level %1$d** and can now post **%2$s** per day. @@ -7681,7 +7792,12 @@ **%d** stories **%d** stories Increase Story Limit - Enable Colors + Unlock Colors + Unlock Profile Colors + Unlock Emoji Status + Unlock Wallpaper + Unlock Link Icons + Unlock Profile Icons Slide left or right to seek Quote to... Reply to... @@ -7739,7 +7855,7 @@ Choose a color and an icon for your profile Off Off - Your Channel Color + Appearance You can choose an individual color to tint your channel’s name, the links it sends, and replies to its messages. The name of the channel and replies to its message will be shown in the selected color Reply to your channel message @@ -7773,9 +7889,10 @@ Unsaved Changes You have changed your color or icon settings. Apply changes? Unsaved Changes - You have changed your color or icon settings. Apply changes? + You have changed appearance settings. Apply changes? OPEN Your name color has been updated! + Channel appearance has been updated Your channel color has been updated! Your profile color has been updated! Your channel profile color has been updated! @@ -7787,10 +7904,12 @@ Similar Channels Apply for Me Apply for Me and %s + Apply for %s Set Background Remove wallpaper Are you sure you want to reset wallpaper back? Repost\nStory + Repost\nto Story Remove Video Are you sure you want to remove your video message? You have **%1$d** free voice transcription left. @@ -7809,4 +7928,47 @@ Unlock more channels Show More Channels Subscribe to **Telegram Premium**\nto unlock up to %s similar channels. + commented + Level %d + Level %d+ + %d Story Per Day + %d Stories Per Day + %d Custom Reaction + %d Custom Reactions + %d Channel Name Colors + %d Styles for Links and Quotes + %d Styles for Links and Quotes + Custom Logo for Links and Quotes + %d Colors for Channel Cover + Custom Logo for Channel Cover + %s Emoji Statuses + %d Channel Background + %d Channel Backgrounds + Custom Channel Background + Level %d Unlocks: + Level %1$d Required + Reply Logo + Choose a color for the name of your channel, the links it sends, and replies to its messages. + Profile Logo + Choose a color and a logo for the channel\'s profile. + Channel Emoji Status + Choose a status that will be shown next to the channel\'s name. + Channel Wallpaper + Choose from Gallery + Remove Wallpaper + Upload your own background image for the channel. + Set a wallpaper that will be visible for everyone reading your channel. + Read More + Message reposted to your profile. + Message reposted to **%s**. + Select Wallpaper + This voice 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. + Close Voice Message + Are you sure you want to stop listening and delete voice message? diff --git a/TMessagesProj/src/main/res/xml/automotive_app_desc.xml b/TMessagesProj/src/main/res/xml/automotive_app_desc.xml deleted file mode 100644 index 79ec6f5e2..000000000 --- a/TMessagesProj/src/main/res/xml/automotive_app_desc.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/TMessagesProj_AppStandalone/src/main/res/mipmap-anydpi-v26/icon_2_launcher_sa.xml b/TMessagesProj_AppStandalone/src/main/res/mipmap-anydpi-v26/icon_2_launcher_sa.xml index d8044115b..e7996ea53 100644 --- a/TMessagesProj_AppStandalone/src/main/res/mipmap-anydpi-v26/icon_2_launcher_sa.xml +++ b/TMessagesProj_AppStandalone/src/main/res/mipmap-anydpi-v26/icon_2_launcher_sa.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ff409bf10..460cd677d 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=4145 -APP_VERSION_NAME=10.3.2 +APP_VERSION_CODE=4228 +APP_VERSION_NAME=10.5.0 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey