diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 590f4e6ba9..dd4a771b24 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -46,7 +46,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -79,7 +79,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -139,7 +139,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Fix BoringSSL @@ -176,7 +176,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Install Golang @@ -211,7 +211,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Install Rust @@ -244,7 +244,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -271,7 +271,7 @@ jobs: uses: android-actions/setup-android@v2 - name: Install NDK run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Fetch Status @@ -355,7 +355,7 @@ jobs: # uses: android-actions/setup-android@v2 # - name: Install NDK # run: | -# echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null +# echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null # echo "sdk.dir=${ANDROID_HOME}" > local.properties # echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties # - name: Fetch Status diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17e160014e..bf8785366f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -82,7 +82,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -142,7 +142,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Fix BoringSSL @@ -179,7 +179,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Install Golang @@ -214,7 +214,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Install Rust @@ -247,7 +247,7 @@ jobs: - name: Install NDK if: steps.cache.outputs.cache-hit != 'true' run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Native Build @@ -275,7 +275,7 @@ jobs: uses: android-actions/setup-android@v2 - name: Install NDK run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null echo "sdk.dir=${ANDROID_HOME}" > local.properties echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties - name: Fetch Status diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 9b7b299cb8..b7d70a6ec9 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -3,12 +3,12 @@ import cn.hutool.core.util.RuntimeUtil apply plugin: "com.android.application" apply plugin: "kotlin-android" -def verName = "10.2.9" -def verCode = 1149 +def verName = "10.5.0" +def verCode = 1153 -def officialVer = "10.2.9" -def officialCode = 4087 +def officialVer = "10.5.0" +def officialCode = 4228 def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json") @@ -113,7 +113,7 @@ android { appHash = properties.getProperty("TELEGRAM_APP_HASH") ?: System.getenv("TELEGRAM_APP_HASH") ?: appHash } - + buildConfigField "String", "BUILD_VERSION_STRING", "\"" + verName + "\"" buildConfigField "String", "OFFICIAL_VERSION", "\"" + officialVer + "\"" buildConfigField "int", "OFFICIAL_VERSION_CODE", officialCode + "" buildConfigField "int", "APP_ID", appId @@ -348,6 +348,8 @@ dependencies { implementation "com.jakewharton:process-phoenix:2.1.2" implementation 'com.google.guava:guava:31.1-android' + implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1' + compileOnly 'org.yaml:snakeyaml:1.29' fullImplementation 'org.yaml:snakeyaml:1.29' diff --git a/TMessagesProj/jni/ffmpeg b/TMessagesProj/jni/ffmpeg index 4bc4cafaef..c3ad886251 160000 --- a/TMessagesProj/jni/ffmpeg +++ b/TMessagesProj/jni/ffmpeg @@ -1 +1 @@ -Subproject commit 4bc4cafaef8a55462138d7b6f7579c1522de26dc +Subproject commit c3ad886251fdba1eaf9e461a6dd013df19ba54a8 diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp index 68ef0738e8..b651482904 100644 --- a/TMessagesProj/jni/gifvideo.cpp +++ b/TMessagesProj/jni/gifvideo.cpp @@ -1339,7 +1339,7 @@ extern "C" JNIEXPORT int JNICALL Java_org_telegram_ui_Components_AnimatedFileDra } } -extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview, jfloat start_time, jfloat end_time) { +extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jintArray data, jint stride, jboolean preview, jfloat start_time, jfloat end_time, jboolean loop) { if (ptr == NULL || bitmap == nullptr) { return 0; } @@ -1408,18 +1408,19 @@ extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDr LOGE("can't decode packet flushed %s", info->src); return 0; } - if (!preview && got_frame == 0) { - if (info->has_decoded_frames) { - int64_t start_from = 0; - if (start_time > 0) { - start_from = (int64_t)(start_time / av_q2d(info->video_stream->time_base)); - } - if ((ret = av_seek_frame(info->fmt_ctx, info->video_stream_idx, start_from, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME)) < 0) { - LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret)); - return 0; - } else { - avcodec_flush_buffers(info->video_dec_ctx); - } + if (!preview && got_frame == 0 && info->has_decoded_frames) { + if (!loop) { + return 0; + } + int64_t start_from = 0; + if (start_time > 0) { + start_from = (int64_t)(start_time / av_q2d(info->video_stream->time_base)); + } + if ((ret = av_seek_frame(info->fmt_ctx, info->video_stream_idx, start_from, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME)) < 0) { + LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret)); + return 0; + } else { + avcodec_flush_buffers(info->video_dec_ctx); } } } diff --git a/TMessagesProj/jni/image.cpp b/TMessagesProj/jni/image.cpp index cc4a33a7af..50c274c90c 100644 --- a/TMessagesProj/jni/image.cpp +++ b/TMessagesProj/jni/image.cpp @@ -1189,6 +1189,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/ApiScheme.cpp b/TMessagesProj/jni/tgnet/ApiScheme.cpp index 5ab7064f93..9093b19c8b 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.cpp +++ b/TMessagesProj/jni/tgnet/ApiScheme.cpp @@ -518,11 +518,15 @@ void TL_user::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &er if ((flags2 & 32) != 0) { stories_max_id = stream->readInt32(&error); } - if ((flags2 & 128) != 0) { - color = stream->readInt32(&error); + if ((flags2 & 256) != 0) { + int magic = stream->readInt32(&error); + color_color = stream->readInt32(&error); + color_background_emoji_id = stream->readInt64(&error); } - if ((flags2 & 64) != 0) { - background_emoji_id = stream->readInt64(&error); + if ((flags2 & 512) != 0) { + int magic = stream->readInt32(&error); + profile_color_color = stream->readInt32(&error); + profile_color_background_emoji_id = stream->readInt64(&error); } } @@ -591,11 +595,15 @@ void TL_user::serializeToStream(NativeByteBuffer *stream) { if ((flags2 & 32) != 0) { stream->writeInt32(stories_max_id); } - if ((flags2 & 128) != 0) { - stream->writeInt32(color); + if ((flags2 & 256) != 0) { + stream->writeInt32(0xba278146); + stream->writeInt32(color_color); + stream->writeInt32(color_background_emoji_id); } - if ((flags2 & 64) != 0) { - stream->writeInt64(background_emoji_id); + if ((flags2 & 512) != 0) { + stream->writeInt32(0xba278146); + stream->writeInt32(profile_color_color); + stream->writeInt32(profile_color_background_emoji_id); } } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 0318c1a647..edee2074f7 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -339,8 +339,10 @@ class User : public TLObject { int32_t emojiStatusMagic; int64_t emojiStatusDocumentId; int32_t emojiStatusUntil; - int32_t color; - int64_t background_emoji_id; + int32_t color_color; + int64_t color_background_emoji_id; + int32_t profile_color_color; + int64_t profile_color_background_emoji_id; static User *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error); }; @@ -357,7 +359,7 @@ class TL_userEmpty : public User { class TL_user : public User { public: - static const uint32_t constructor = 0xeb602f25; + static const uint32_t constructor = 0x215c4438; void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); void serializeToStream(NativeByteBuffer *stream); diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp index ee7b3ff5da..b2cf3b744c 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 c3913cd4db..9da0069447 100644 --- a/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/v2/InstanceV2Impl.cpp @@ -253,6 +253,54 @@ class OutgoingAudioChannel : public sigslot::has_slots<> { 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 @@ class IncomingV2AudioChannel : public sigslot::has_slots<> { 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 @@ class IncomingV2AudioChannel : public sigslot::has_slots<> { _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 @@ class IncomingV2AudioChannel : public sigslot::has_slots<> { 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 @@ class InstanceV2ImplInternal : public std::enable_shared_from_thisGetSupportedFormats(); @@ -1468,6 +1518,9 @@ class InstanceV2ImplInternal : public std::enable_shared_from_this - + + --> - - + + diff --git a/TMessagesProj/src/main/assets/darkblue.attheme b/TMessagesProj/src/main/assets/darkblue.attheme index bb945993aa..8c3eda0baf 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 1a394741d4..46217ff1c2 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 d3dde3c6f0..66516c7b06 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.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,18 +15,22 @@ 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; import org.telegram.ui.Cells.ChatMessageCell; 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; @@ -124,9 +129,60 @@ private void runAlphaEnterTransition() { return; } // First, remove stuff + 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) { - animateRemoveImpl(holder); + boolean thanos = toBeSnapped.remove(holder) && supportsThanos; + animateRemoveImpl(holder, thanos); + if (thanos) { + hadThanos = true; + } } + final boolean finalThanos = hadThanos; mPendingRemovals.clear(); // Next, move stuff if (movesPending) { @@ -138,7 +194,7 @@ private void runAlphaEnterTransition() { @Override public void run() { for (MoveInfo moveInfo : moves) { - animateMoveImpl(moveInfo.holder, moveInfo); + animateMoveImpl(moveInfo.holder, moveInfo, finalThanos); } moves.clear(); mMovesList.remove(moves); @@ -146,7 +202,7 @@ public void run() { }; 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(); } @@ -660,6 +716,9 @@ public boolean animateMove(RecyclerView.ViewHolder holder, ItemHolderInfo info, @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; @@ -842,10 +901,12 @@ public void onAnimationEnd(Animator animation) { } } - 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) { @@ -1371,36 +1432,72 @@ public void onAnimationEnd(Animator animator) { 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(); } @@ -1501,5 +1598,27 @@ class ItemHolderInfoExtended extends ItemHolderInfo { 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 4a1672172f..08901a46e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -473,11 +473,11 @@ public static Activity findActivity(Context context) { return null; } - public static CharSequence premiumText(String str, Runnable runnable) { + public static SpannableStringBuilder premiumText(String str, Runnable runnable) { return replaceSingleTag(str, -1, REPLACING_TAG_TYPE_LINKBOLD, runnable); } - public static CharSequence replaceSingleTag(String str, Runnable runnable) { + public static SpannableStringBuilder replaceSingleTag(String str, Runnable runnable) { return replaceSingleTag(str, -1, 0, runnable); } @@ -535,6 +535,10 @@ public void updateDrawState(TextPaint textPaint) { } public static SpannableStringBuilder replaceSingleLink(String str, int color) { + return replaceSingleLink(str, color, null); + } + + public static SpannableStringBuilder replaceSingleLink(String str, int color, Runnable onClick) { int startIndex = str.indexOf("**"); int endIndex = str.indexOf("**", startIndex + 1); str = str.replace("**", ""); @@ -556,7 +560,9 @@ public void updateDrawState(@NonNull TextPaint ds) { @Override public void onClick(@NonNull View view) { - + if (onClick != null) { + onClick.run(); + } } }, index, index + len, 0); } @@ -1128,7 +1134,7 @@ public static int calcBitmapColor(Bitmap bitmap) { public static int[] calcDrawableColor(Drawable drawable) { if (drawable instanceof ChatBackgroundDrawable) { ChatBackgroundDrawable chatBackgroundDrawable = (ChatBackgroundDrawable) drawable; - return calcDrawableColor(chatBackgroundDrawable.getDrawable()); + return calcDrawableColor(chatBackgroundDrawable.getDrawable(true)); } int bitmapColor = 0xff000000; int[] result = new int[4]; @@ -5475,6 +5481,10 @@ public static void updateViewVisibilityAnimated(View view, boolean show, float s } 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; } @@ -5486,7 +5496,7 @@ public static void updateViewVisibilityAnimated(View view, boolean show, float s 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) { @@ -5497,7 +5507,7 @@ public static void updateViewVisibilityAnimated(View view, boolean show, float s 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(); @@ -5694,7 +5704,7 @@ public static boolean isEROFS(Exception e) { ); } - 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; @@ -5823,14 +5833,14 @@ public static void makeGlobalBlurBitmap(Utilities.Callback onBitmapDone, 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); - }); +// }); } // }); } @@ -6049,6 +6059,9 @@ public static void forEachViews(View view, Consumer consumer) { } public static void forEachViews(RecyclerView recyclerView, Consumer consumer) { + if (recyclerView == null) { + return; + } for (int i = 0; i < recyclerView.getChildCount(); i++) { consumer.accept(recyclerView.getChildAt(i)); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 7b7474fc3f..4e6d107869 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -19,6 +19,8 @@ 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; @@ -307,7 +309,11 @@ public void onCreate() { 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(); @@ -428,6 +434,13 @@ public void onConfigurationChanged(Configuration newConfig) { } } + 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 { @@ -494,6 +507,11 @@ public static boolean isConnectedToWiFi() { 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 3d8a934bb1..64d57ff67d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java @@ -66,7 +66,7 @@ public String formatCurrency(long amount, String currency, int exp) { } 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/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index a6d1c96138..d3891b2702 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -2086,4 +2086,34 @@ private void setAspectRatio(float aspectRatio, Call call) { } } } + + public static MessagesController.PeerColor getPeerColorForAvatar(int currentAccount, TLRPC.Chat chat) { +// if (chat != null && chat.profile_color != null && chat.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { +// return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(chat.profile_color.color); +// } + return null; + } + + public static int getColorId(TLRPC.Chat chat) { + if (chat == null) return 0; + if (chat.color != null && (chat.color.flags & 1) != 0) return chat.color.color; + return (int) (chat.id % 7); + } + + public static long getEmojiId(TLRPC.Chat chat) { + if (chat != null && chat.color != null && (chat.color.flags & 2) != 0) return chat.color.background_emoji_id; + return 0; + } + + public static int getProfileColorId(TLRPC.Chat chat) { + if (chat == null) return 0; + if (chat.profile_color != null && (chat.profile_color.flags & 1) != 0) return chat.profile_color.color; + return -1; + } + + public static long getProfileEmojiId(TLRPC.Chat chat) { + if (chat != null && chat.profile_color != null && (chat.profile_color.flags & 2) != 0) return chat.profile_color.background_emoji_id; + return 0; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java index 4648b8ba25..6c8239e620 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatThemeController.java @@ -216,7 +216,7 @@ public static boolean equals(TLRPC.WallPaper wallPaper, TLRPC.WallPaper oldWallp 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; } @@ -265,6 +265,10 @@ public EmojiThemes getDialogTheme(long dialogId) { 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())) { @@ -276,10 +280,10 @@ public EmojiThemes getDialogTheme(long dialogId) { } 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()); @@ -295,12 +299,16 @@ public void saveChatWallpaper(long dialogId, TLRPC.WallPaper wallPaper) { } 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) { @@ -405,24 +413,118 @@ public void clearCache() { getSharedPreferences().edit().clear().apply(); } + public void processUpdate(TLRPC.TL_updatePeerWallpaper update) { + if (update.peer instanceof TLRPC.TL_peerUser) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(update.peer.user_id); + if (userFull != null) { + if (wallpaperEquals(userFull.wallpaper, update.wallpaper)) { + return; + } + final long dialogId = userFull.id; + 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, userFull.wallpaper); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + }); + } + } else { + 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 && 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); + } + + public void clearWallpaper(long dialogId, boolean notify, boolean onlyRevert) { TLRPC.TL_messages_setChatWallPaper req = new TLRPC.TL_messages_setChatWallPaper(); - if (dialogId > 0) { + if (dialogId >= 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); req.peer = MessagesController.getInputPeer(user); - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); - if (userFull != null) { - userFull.wallpaper = null; - userFull.flags &= ~16777216; - getMessagesStorage().updateUserInfo(userFull, false); - } - saveChatWallpaper(dialogId, null); - if (notify) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + req.revert = onlyRevert; + if (!onlyRevert) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + userFull.wallpaper = null; + userFull.flags &= ~16777216; + getMessagesStorage().updateUserInfo(userFull, false); + } + saveChatWallpaper(dialogId, null); + if (notify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, userFull); + } } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); 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) -> { @@ -430,68 +532,87 @@ public void clearWallpaper(long dialogId, boolean notify) { }); } - 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); } + req.for_both = wallpaperInfo.forBoth; boolean applyOnRequest = true; if (serverWallpaper != null && serverWallpaper.messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { applyOnRequest = false; 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; - - 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; + wallPaper.settings.flags |= 1; + wallPaper.settings.flags |= 8; + wallPaper.settings.flags |= 16; + wallPaper.settings.flags |= 32; + wallPaper.settings.flags |= 64; + + 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; @@ -505,27 +626,44 @@ public int setWallpaperToUser(long dialogId, String wallpaperLocalPath, Theme.Ov 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/ChatsWidgetService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java index 21aaa43403..fc12553cd0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatsWidgetService.java @@ -150,7 +150,8 @@ public RemoteViews getViewAt(int position) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); } } else { - avatarDrawable = new AvatarDrawable(chat); + avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), chat); } avatarDrawable.setBounds(0, 0, size, size); avatarDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java index 91c576f8d8..201dfe5c65 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java @@ -420,7 +420,7 @@ private static void matchGrammar(String text, LinkedList tokenList, TokenPattern StringToken wrapped; if (pattern.insideTokenPatterns != null) { - wrapped = new StringToken(pattern.group, tokenize(match.string, pattern.insideTokenPatterns, depth + 1), match.length); + wrapped = new StringToken(pattern.group, tokenize(match.string, pattern.insideTokenPatterns, pattern, depth + 1), match.length); } else if (pattern.insideLanguage != null) { wrapped = new StringToken(pattern.group, tokenize(match.string, compiledPatterns.get(pattern.insideLanguage), pattern, depth + 1), match.length); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java index 675b4852d5..9e564ee544 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsWidgetService.java @@ -155,7 +155,8 @@ public RemoteViews getViewAt(int position) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); } } else { - avatarDrawable = new AvatarDrawable(chat); + avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), chat); } avatarDrawable.setBounds(0, 0, size, size); avatarDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/DialogObject.java index 1bf846e351..8b269fdcff 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 static String getPublicUsername(TLObject dialog) { } 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 39a0fb262a..d9c485351a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -2106,7 +2106,7 @@ private void requestReference(RequestInfo requestInfo) { 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 b58281fd3e..63f438b025 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -902,7 +902,7 @@ private FileLoadOperation loadFileInternal(final TLRPC.Document document, final } 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); @@ -1024,7 +1024,7 @@ private boolean canSaveToPublicStorage(Object parentObject) { if (metadata != null) { int flag; long dialogId = metadata.dialogId; - if (getMessagesController().isChatNoForwards(getMessagesController().getChat(-dialogId)) || DialogObject.isEncryptedDialog(dialogId)) { + if (getMessagesController().isChatNoForwardsWithOverride(getMessagesController().getChat(-dialogId)) || DialogObject.isEncryptedDialog(dialogId)) { return false; } if (parentObject instanceof MessageObject) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index bcdb2a5491..207cd5eecf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -249,7 +249,7 @@ public void requestReference(Object parentObject, Object... args) { } 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; } } @@ -1088,6 +1088,9 @@ private boolean onRequestComplete(String locationKey, String parentKey, TLObject 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 aa1356f421..1f1d4efdb6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -105,6 +105,10 @@ */ 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<>(); @@ -4094,7 +4098,7 @@ public static void saveMessageThumbs(TLRPC.Message message) { } 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 d31fcbbf1a..8efbeb42a5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -1023,7 +1023,7 @@ private void updateDrawableRadius(Drawable drawable) { } 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)); } } @@ -1119,25 +1119,6 @@ public boolean setBackupImage() { return false; } - private int bufferedFrame; - public void incrementFrames(int inc) { - if (currentMediaDrawable instanceof RLottieDrawable) { -// RLottieDrawable rlottie = (RLottieDrawable) currentMediaDrawable; -// inc = (int) Math.round((float) rlottie.getFramesCount() / rlottie.getDuration() * (1f / 30f)); -// rlottie.setCurrentFrame( -// (rlottie.getCurrentFrame() + inc) % (int) rlottie.getFramesCount() -// ); - } else if (currentMediaDrawable instanceof AnimatedFileDrawable) { - int lastFrame = (int) bufferedFrame; - bufferedFrame += inc; - int currentFrame = (int) bufferedFrame; - while (lastFrame != currentFrame) { - ((AnimatedFileDrawable) currentMediaDrawable).getNextFrame(); - currentFrame--; - } - } - } - public boolean onAttachedToWindow() { if (attachedToWindow) { return false; @@ -2466,6 +2447,10 @@ public void setRoundRadius(int tl, int tr, int br, int bl) { } public void setRoundRadius(int[] value) { + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + java.util.Arrays.fill(value, 0); + } + boolean changed = false; int firstValue = value[0]; isRoundRect = true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java b/TMessagesProj/src/main/java/org/telegram/messenger/LiteMode.java index c48221982b..f299997c90 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 static void loadPreference() { } 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 static void loadPreference() { } 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 static void loadPreference() { } 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 2560f471ac..e91af17018 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1156,10 +1156,10 @@ public static String getCurrentLanguageName() { } 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) { @@ -1169,6 +1169,11 @@ private String getStringInternal(String key, String fallback, int res) { try { value = ApplicationLoader.applicationContext.getString(res); } catch (Exception e) { + if (fallbackRes != 0) { + try { + value = ApplicationLoader.applicationContext.getString(fallbackRes); + } catch (Exception ignored) {} + } FileLog.e(e); } } @@ -1219,8 +1224,12 @@ public static String getString(String key, int res) { 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) { @@ -1241,7 +1250,8 @@ public static String getPluralString(String key, int plural) { 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) { @@ -1258,6 +1268,10 @@ public static String formatPluralString(String key, int plural, Object... args) 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, ','); } @@ -1282,6 +1296,11 @@ public static String formatPluralStringComma(String key, int plural, char symbol int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); value = ApplicationLoader.applicationContext.getString(resourceId); } + if (value == null) { + int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(key + "_other", "string", ApplicationLoader.applicationContext.getPackageName()); + value = ApplicationLoader.applicationContext.getString(resourceId); + } + value = value.replace("%d", "%1$s"); value = value.replace("%1$d", "%1$s"); if (getInstance().currentLocale != null) { @@ -1733,6 +1752,24 @@ public static String formatDateChat(long date, boolean checkYear) { 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; @@ -1812,6 +1849,42 @@ public static String formatSeenDate(long date) { return "LOC_ERR"; } + public static String formatShortDate(long date) { + try { + date *= 1000; + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + long timeInMillis = rightNow.getTimeInMillis(); + rightNow.setTimeInMillis(date); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (timeInMillis - date < 1000 * 60) { + return LocaleController.getString(R.string.ShortNow); + } else if (timeInMillis - date < 1000 * 60 * 60) { + int minutesAgo = (int) ((timeInMillis - date) / (1000 * 60)); + return LocaleController.formatPluralString("ShortMinutesAgo", minutesAgo); + } else if (dateDay == day && year == dateYear) { + if (timeInMillis - date < 12 * 1000 * 60 * 60) { + int hoursAgo = (int) ((timeInMillis - date) / (1000 * 60 * 60)); + return LocaleController.formatPluralString("ShortHoursAgo", hoursAgo); + } else { + return LocaleController.getString(R.string.ShortToday); + } + } else if (dateDay + 1 == day && year == dateYear) { + return LocaleController.getString(R.string.ShortYesterday); + } else if (Math.abs(System.currentTimeMillis() - date) < 31536000000L) { + return getInstance().formatterDayMonth.format(new Date(date)); + } else { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date)), getInstance().formatterDay.format(new Date(date))); + } + } catch (Exception e) { + FileLog.e(e); + } + return "LOC_ERR"; + } + public static String formatStoryDate(long date) { try { date *= 1000; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 80021a01c1..b726bc8a03 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -620,7 +620,7 @@ public SearchImage clone() { public final static int VIDEO_BITRATE_360 = 750_000; public final static String VIDEO_MIME_TYPE = "video/avc"; - public final static String AUIDO_MIME_TYPE = "audio/mp4a-latm"; + public final static String AUDIO_MIME_TYPE = "audio/mp4a-latm"; private final Object videoConvertSync = new Object(); @@ -786,6 +786,7 @@ public void run() { private int sendAfterDone; private boolean sendAfterDoneNotify; private int sendAfterDoneScheduleDate; + private boolean sendAfterDoneOnce; private Runnable recordStartRunnable; private DispatchQueue recordQueue; @@ -874,7 +875,7 @@ public void run() { } else { recordBuffers.add(buffer); if (sendAfterDone != 3) { - stopRecordingInternal(sendAfterDone, sendAfterDoneNotify, sendAfterDoneScheduleDate); + stopRecordingInternal(sendAfterDone, sendAfterDoneNotify, sendAfterDoneScheduleDate, sendAfterDoneOnce); } } } @@ -1154,7 +1155,7 @@ public void onCallStateChanged(final int state, String incomingNumber) { 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) { @@ -1610,6 +1611,7 @@ public void didReceivedNotification(int id, int account, Object... args) { 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; } @@ -1643,7 +1645,7 @@ public void didReceivedNotification(int id, int account, Object... args) { 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); } @@ -1938,7 +1940,7 @@ public void onSensorChanged(SensorEvent event) { 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()) { @@ -2076,7 +2078,7 @@ public void stopRaiseToEarSensors(ChatActivity chatActivity, boolean fromChat, b 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; @@ -2281,6 +2283,12 @@ public boolean seekToProgress(MessageObject messageObject, float progress) { return true; } + public void seekShift(int ms) { + if (audioPlayer != null) { + audioPlayer.seekTo(Math.max(0, audioPlayer.getCurrentPosition() + ms)); + } + } + public long getDuration() { if (audioPlayer == null) { return 0; @@ -2386,6 +2394,7 @@ public void loadMoreMusic() { 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; } @@ -3786,6 +3795,9 @@ public ArrayList getPlaylist() { } public boolean isPlayingMessage(MessageObject messageObject) { + if (messageObject != null && messageObject.isRepostPreview) { + return false; + } if (audioPlayer == null && videoPlayer == null || messageObject == null || playingMessageObject == null) { return false; } @@ -3982,7 +3994,7 @@ public void generateWaveform(MessageObject messageObject) { }); } - 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; @@ -4016,7 +4028,7 @@ private void stopRecordingInternal(final int send, boolean notify, int scheduleD if (duration > 700) { NotificationCenter.getInstance(recordingCurrentAccount).postNotificationName(NotificationCenter.beforeAudioDidSent, recordingGuid, send == 2 ? audioToSend : null, send == 2 ? recordingAudioFileToSend.getAbsolutePath() : null); 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); } @@ -4050,7 +4062,7 @@ private void stopRecordingInternal(final int send, boolean notify, int scheduleD 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; @@ -4058,7 +4070,7 @@ public void stopRecording(final int send, boolean notify, int scheduleDate) { recordQueue.postRunnable(() -> { if (sendAfterDone == 3) { sendAfterDone = 0; - stopRecordingInternal(send, notify, scheduleDate); + stopRecordingInternal(send, notify, scheduleDate, once); return; } if (audioRecorder == null) { @@ -4068,6 +4080,7 @@ public void stopRecording(final int send, boolean notify, int scheduleDate) { sendAfterDone = send; sendAfterDoneNotify = notify; sendAfterDoneScheduleDate = scheduleDate; + sendAfterDoneOnce = once; audioRecorder.stop(); setBluetoothScoOn(false); } catch (Exception e) { @@ -4080,7 +4093,7 @@ public void stopRecording(final int send, boolean notify, int scheduleDate) { } } if (send == 0) { - stopRecordingInternal(0, false, 0); + stopRecordingInternal(0, false, 0, false); } if (!NekoConfig.disableVibration.Bool()) { try { @@ -5007,12 +5020,13 @@ public static void loadGalleryPhotosAlbums(final int guid) { 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; } @@ -5366,20 +5380,8 @@ public void didWriteData(long availableSize, float progress) { 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 33e2b6fa0a..7f79c73c7d 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 @@ private void loadRepliesOfDraftReplies(final ArrayList messages) 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 @@ private void loadRepliesOfDraftReplies(final ArrayList messages) 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++) { @@ -408,7 +409,7 @@ public void checkStickers(int type) { public void checkReactions() { if (!isLoadingReactions && Math.abs(System.currentTimeMillis() / 1000 - reactionsUpdateDate) >= 60 * 60) { - loadReactions(true, false); + loadReactions(true, null); } } @@ -645,7 +646,7 @@ public List getReactionsList() { return reactionsList; } - public void loadReactions(boolean cache, boolean force) { + public void loadReactions(boolean cache, Integer lastHash) { isLoadingReactions = true; if (cache) { getMessagesStorage().getStorageQueue().postRunnable(() -> { @@ -685,7 +686,7 @@ public void loadReactions(boolean cache, boolean force) { }); } else { TLRPC.TL_messages_getAvailableReactions req = new TLRPC.TL_messages_getAvailableReactions(); - req.hash = force ? 0 : reactionsUpdateHash; + req.hash = lastHash != null ? lastHash : reactionsUpdateHash; getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { int date = (int) (System.currentTimeMillis() / 1000); if (response instanceof TLRPC.TL_messages_availableReactionsNotModified) { @@ -725,7 +726,7 @@ public void processLoadedReactions(List reactions, i if (!cache) { putReactionsToCache(reactions, hash, date); } else if (Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) { - loadReactions(false, true); + loadReactions(false, hash); } } @@ -1165,6 +1166,8 @@ public TLRPC.TL_messages_stickerSet getStickerSet(TLRPC.InputStickerSet inputSti 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) { @@ -1212,6 +1215,9 @@ public TLRPC.TL_messages_stickerSet getStickerSet(TLRPC.InputStickerSet inputSti 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); @@ -5556,6 +5562,13 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } } + 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) { @@ -6339,6 +6352,9 @@ public ArrayList getEntities(CharSequence[] message, boolea } } else { if (start + 1 != index) { + if (message[0] instanceof Spanned && ((Spanned) message[0]).getSpans(Utilities.clamp(start, message[0].length(), 0), Utilities.clamp(start + 1, message[0].length(), 0), CodeHighlighting.Span.class).length > 0) { + continue; + } message[0] = AndroidUtilities.concat(substring(message[0], 0, start), substring(message[0], start + 1, index), substring(message[0], index + 1, message[0].length())); TLRPC.TL_messageEntityCode entity = new TLRPC.TL_messageEntityCode(); entity.offset = start; @@ -6625,12 +6641,7 @@ public Pair getOneThreadDraft(long dialogId) { if (threads == null || threads.size() <= 0) { return null; } - for (int i = 0; i < threads.size(); ++i) { - if (threads.keyAt(i) != 0) { - return new Pair(threads.keyAt(i), threads.valueAt(i)); - } - } - return null; + return new Pair(threads.keyAt(0), threads.valueAt(0)); } public TLRPC.Message getDraftMessage(long dialogId, int threadId) { @@ -6666,6 +6677,8 @@ public void saveDraft(long dialogId, int threadId, CharSequence message, ArrayLi draftMessage.reply_to.quote_text = quote.getText(); if (draftMessage.reply_to.quote_text != null) { draftMessage.reply_to.flags |= 4; + draftMessage.reply_to.flags |= 16; + draftMessage.reply_to.quote_offset = quote.start; } draftMessage.reply_to.quote_entities = quote.getEntities(); if (draftMessage.reply_to.quote_entities != null && !draftMessage.reply_to.quote_entities.isEmpty()) { @@ -8175,6 +8188,16 @@ public ArrayList getDefaultEmojiStatuses() { 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]) { @@ -8266,10 +8289,14 @@ public void fetchEmojiStatuses(int type, boolean cache) { 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; @@ -8513,4 +8540,42 @@ public void loadReplyIcons() { })); } } + + 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 5d79621107..0619463fbb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -73,6 +73,7 @@ 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; @@ -130,6 +131,8 @@ public class MessageObject { public static final int TYPE_STORY_MENTION = 24; public static final int TYPE_GIFT_PREMIUM_CHANNEL = 25; public static final int TYPE_GIVEAWAY = 26; + public static final int TYPE_JOINED_CHANNEL = 27; // recommendations list + public static final int TYPE_GIVEAWAY_RESULTS = 28; public int localType; public String localName; @@ -173,6 +176,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; @@ -214,10 +218,14 @@ public class MessageObject { public boolean sponsoredRecommended; public String sponsoredInfo, sponsoredAdditionalInfo; public TLRPC.TL_sponsoredWebPage sponsoredWebPage; + public TLRPC.BotApp sponsoredBotApp; + public String sponsoredButtonText; public boolean replyTextEllipsized; public boolean replyTextRevealed; public int overrideLinkColor = -1; public long overrideLinkEmoji = -1; + private boolean channelJoined; + public boolean channelJoinedExpanded; public TLRPC.TL_forumTopic replyToForumTopic; // used only for reply message in view all messages @@ -311,6 +319,8 @@ public class MessageObject { " & ", " . " }; + public boolean isRepostPreview; + public boolean isRepostVideoPreview; public boolean forceAvatar; public Drawable customAvatarDrawable; @@ -429,13 +439,33 @@ public boolean isWallpaperAction() { return type == TYPE_ACTION_WALLPAPER || (messageOwner != null && messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper); } + public boolean isWallpaperForBoth() { + return isWallpaperAction() && messageOwner != null && messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper && ((TLRPC.TL_messageActionSetChatWallPaper) messageOwner.action).for_both; + } + + public boolean isCurrentWallpaper() { + if (!isWallpaperAction() || messageOwner == null || messageOwner.action == null || messageOwner.action.wallpaper == null) + return false; + TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(getDialogId()); + if (userFull == null || userFull.wallpaper == null || !userFull.wallpaper_overridden) + return false; + return messageOwner.action.wallpaper.id == userFull.wallpaper.id; + } + public int getEmojiOnlyCount() { return emojiOnlyCount; } public boolean hasMediaSpoilers() { if (NekoConfig.showSpoilersDirectly.Bool()) return false; - 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() { @@ -523,6 +553,9 @@ public void copyStableParams(MessageObject old) { public ArrayList getChoosenReactions() { ArrayList choosenReactions = new ArrayList<>(); TLRPC.ReactionCount newReaction = null; + if (messageOwner.reactions == null) { + return choosenReactions; + } for (int i = 0; i < messageOwner.reactions.results.size(); i++) { if (messageOwner.reactions.results.get(i).chosen) { choosenReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(messageOwner.reactions.results.get(i).reaction)); @@ -808,6 +841,7 @@ private static String capitalizeLanguage(String lng) { case "dockerfile": case "dart": case "java": + case "fift": return capitalizeFirst(lng); case "http": case "html": @@ -831,7 +865,13 @@ private static String capitalizeLanguage(String lng) { case "cobol": case "jsx": case "tsx": + case "tl": return lng.toUpperCase(); + case "tl-b": + case "tlb": + return "TL-B"; + case "func": + return "FunC"; } return lng; } @@ -1475,8 +1515,15 @@ public MessageObject(int accountNum, TLRPC.Message message, 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; @@ -1789,9 +1836,9 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionParticipantJoin) { if (chat.megagroup) { - messageText = replaceWithLink(LocaleController.getString("EventLogGroupJoined", R.string.EventLogGroupJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogGroupJoined), "un1", fromUser); } else { - messageText = replaceWithLink(LocaleController.getString("EventLogChannelJoined", R.string.EventLogChannelJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChannelJoined), "un1", fromUser); } } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionParticipantLeave) { messageOwner = new TLRPC.TL_messageService(); @@ -1815,9 +1862,9 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL } if (messageOwner.from_id instanceof TLRPC.TL_peerUser && peerId == messageOwner.from_id.user_id) { if (chat.megagroup) { - messageText = replaceWithLink(LocaleController.getString("EventLogGroupJoined", R.string.EventLogGroupJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogGroupJoined), "un1", fromUser); } else { - messageText = replaceWithLink(LocaleController.getString("EventLogChannelJoined", R.string.EventLogChannelJoined), "un1", fromUser); + messageText = replaceWithLink(LocaleController.getString(R.string.EventLogChannelJoined), "un1", fromUser); } } else { messageText = replaceWithLink(LocaleController.getString("EventLogAdded", R.string.EventLogAdded), "un2", whoUser); @@ -2684,6 +2731,133 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL } 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); @@ -3431,7 +3605,7 @@ public void createMessageSendInfo() { } 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() { @@ -3526,11 +3700,12 @@ private void updateMessageText(AbstractMap users, AbstractMap< TLObject fromObject = fromUser != null ? fromUser : fromChat; drawServiceWithDefaultTypeface = false; + channelJoined = false; if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action != null) { if (messageOwner.action instanceof TLRPC.TL_messageActionSetSameChatWallPaper) { contentType = 1; - type = TYPE_TEXT; + type = TYPE_DATE; TLRPC.TL_messageActionSetSameChatWallPaper action = (TLRPC.TL_messageActionSetSameChatWallPaper) messageOwner.action; TLRPC.User user = getUser(users, sUsers, isOutOwner() ? 0 : getDialogId()); photoThumbs = new ArrayList<>(); @@ -3540,27 +3715,52 @@ private void updateMessageText(AbstractMap users, AbstractMap< } if (user != null) { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { - messageText = LocaleController.formatString("ActionSetSameWallpaperForThisChatSelf", R.string.ActionSetSameWallpaperForThisChatSelf); + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChatSelf); } else { - messageText = LocaleController.formatString("ActionSetSameWallpaperForThisChat", R.string.ActionSetSameWallpaperForThisChat, user.first_name); + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChat, user.first_name); } + } else if (fromChat != null) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChannel); } } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; - type = TYPE_ACTION_WALLPAPER; TLRPC.TL_messageActionSetChatWallPaper wallPaper = (TLRPC.TL_messageActionSetChatWallPaper) messageOwner.action; + type = TYPE_ACTION_WALLPAPER; photoThumbs = new ArrayList<>(); if (wallPaper.wallpaper.document != null) { photoThumbs.addAll(wallPaper.wallpaper.document.thumbs); photoThumbsObject = wallPaper.wallpaper.document; } TLRPC.User user = getUser(users, sUsers, isOutOwner() ? 0 : getDialogId()); + TLRPC.User partner = getUser(users, sUsers, getDialogId()); if (user != null) { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { - messageText = LocaleController.formatString("ActionSetWallpaperForThisChatSelf", R.string.ActionSetWallpaperForThisChatSelf); + if (wallPaper.same) { + type = TYPE_DATE; + messageText = LocaleController.formatString(R.string.ActionSetSameWallpaperForThisChatSelf); + } else if (wallPaper.for_both && partner != null) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelfBoth); + CharSequence partnerName = new SpannableString(UserObject.getFirstName(partner)); + ((SpannableString) partnerName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, partnerName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + messageText = AndroidUtilities.replaceCharSequence("%s", messageText, partnerName); + } else { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatSelf); + } } else { - messageText = LocaleController.formatString("ActionSetWallpaperForThisChat", R.string.ActionSetWallpaperForThisChat, user.first_name); + CharSequence userName = new SpannableString(UserObject.getFirstName(user)); + ((SpannableString) userName).setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, userName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (wallPaper.same) { + type = TYPE_DATE; + messageText = LocaleController.getString(R.string.ActionSetSameWallpaperForThisChat); + } else if (wallPaper.for_both) { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChatBoth); + } else { + messageText = LocaleController.getString(R.string.ActionSetWallpaperForThisChat); + } + messageText = AndroidUtilities.replaceCharSequence("%s", messageText, userName); } + } else if (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; @@ -3699,6 +3899,7 @@ private void updateMessageText(AbstractMap users, AbstractMap< } if (messageOwner.from_id != null && singleUserId == messageOwner.from_id.user_id) { if (ChatObject.isChannel(chat) && !chat.megagroup) { + channelJoined = true; messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined); } else { if (messageOwner.peer_id.channel_id != 0) { @@ -3748,9 +3949,18 @@ private void updateMessageText(AbstractMap users, AbstractMap< } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayLaunch) { TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; messageText = LocaleController.formatString("BoostingGiveawayJustStarted", R.string.BoostingGiveawayJustStarted, chat != null ? chat.title : ""); - } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode) { + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + TLRPC.TL_messageActionGiveawayResults giveawayResults = (TLRPC.TL_messageActionGiveawayResults) messageOwner.action; + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceWinnersSelected", giveawayResults.winners_count)); + if (giveawayResults.unclaimed_count > 0) { + stringBuilder.append("\n"); + stringBuilder.append(LocaleController.formatPluralString("BoostingGiveawayServiceUndistributed", giveawayResults.unclaimed_count)); + } + messageText = stringBuilder; + } else if (messageOwner.action instanceof TLRPC.TL_messageActionGiftCode && ((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); @@ -3832,39 +4042,61 @@ private void updateMessageText(AbstractMap users, AbstractMap< } } } 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; @@ -4199,15 +4431,19 @@ private void updateMessageText(AbstractMap users, AbstractMap< } 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)) { @@ -4230,6 +4466,8 @@ private void updateMessageText(AbstractMap users, AbstractMap< // 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); @@ -4336,6 +4574,8 @@ private void updateMessageText(AbstractMap users, AbstractMap< 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); @@ -4457,7 +4697,10 @@ public void setType() { int oldType = type; type = 1000; isRoundVideoCached = 0; - if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) { + if (channelJoined) { + type = TYPE_JOINED_CHANNEL; + channelJoinedExpanded = MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("c" + getDialogId() + "_rec", true); + } else if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) { if (isRestrictedMessage) { type = TYPE_TEXT; } else if (emojiAnimatedSticker != null || emojiAnimatedStickerId != null) { @@ -4466,7 +4709,7 @@ public void setType() { } else { type = TYPE_ANIMATED_STICKER; } - } else if (isMediaEmpty(false) && !isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji && messageOwner != null && !hasNonEmojiEntities()) { + } else if (isMediaEmpty(false) && !isDice() && !isSponsored() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji && messageOwner != null && !hasNonEmojiEntities()) { type = TYPE_EMOJIS; } else if (isMediaEmpty()) { type = TYPE_TEXT; @@ -4480,6 +4723,8 @@ public void setType() { 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) { @@ -4537,10 +4782,23 @@ public void setType() { 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; - type = TYPE_TEXT; + type = TYPE_DATE; } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetChatWallPaper) { contentType = 1; type = TYPE_ACTION_WALLPAPER; @@ -4558,10 +4816,10 @@ public void setType() { 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) { @@ -4915,6 +5173,16 @@ public void generateThumbs(boolean update) { } } } + } else if (sponsoredWebPage != null && sponsoredWebPage.photo != null) { + if (!update || photoThumbs == null) { + photoThumbs = new ArrayList<>(sponsoredWebPage.photo.sizes); + } else if (!photoThumbs.isEmpty()) { + updatePhotoSizeLocations(photoThumbs, sponsoredWebPage.photo.sizes); + } + photoThumbsObject = sponsoredWebPage.photo; + if (strippedThumb == null) { + createStrippedThumb(); + } } } @@ -5224,7 +5492,6 @@ public float measureVoiceTranscriptionHeight() { public boolean isVoiceTranscriptionOpen() { return ( - UserConfig.getInstance(currentAccount).isPremium() && messageOwner != null && (isVoice() || isRoundVideo() && TranscribeButton.isVideoTranscriptionOpen(this)) && messageOwner.voiceTranscriptionOpen && @@ -5908,7 +6175,12 @@ public static boolean addEntitiesToText(CharSequence text, ArrayList= 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) @@ -6148,13 +6421,76 @@ public void generateLayout(TLRPC.User fromUser) { } 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) { @@ -6176,9 +6512,9 @@ public void generateLayout(TLRPC.User fromUser) { 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 { @@ -6255,7 +6591,7 @@ public void generateLayout(TLRPC.User fromUser) { } } - 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); @@ -6480,6 +6816,9 @@ public void generateLayout(TLRPC.User fromUser) { 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; @@ -6563,6 +6902,62 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, 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); @@ -6848,6 +7243,9 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, 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) { @@ -6892,20 +7290,20 @@ public boolean isOutOwner() { } public boolean needDrawAvatar() { - if (forceAvatar || customAvatarDrawable != null) { + if (isRepostPreview) { return true; } - if (isSponsored() && (isFromChat() || sponsoredShowPeerPhoto)) { + if (forceAvatar || customAvatarDrawable != null) { return true; } return !isSponsored() && (isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null); } private boolean needDrawAvatarInternal() { - if (forceAvatar || customAvatarDrawable != null) { + if (isRepostPreview) { return true; } - if (isSponsored() && (isFromChat() || sponsoredShowPeerPhoto)) { + if (forceAvatar || customAvatarDrawable != null) { return true; } return !isSponsored() && (isFromChat() && isFromUser() || isFromGroup() || eventId != 0 || messageOwner.fwd_from != null && messageOwner.fwd_from.saved_from_peer != null); @@ -7179,10 +7577,25 @@ public static long getChannelId(TLRPC.Message message) { 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 (NekoXConfig.disableFlagSecure) { return false; } + if (MessagesController.getInstance(currentAccount).isChatNoForwardsWithOverride(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 { @@ -7191,7 +7604,7 @@ public static boolean shouldEncryptPhotoOrVideo(TLRPC.Message message) { } public boolean shouldEncryptPhotoOrVideo() { - return shouldEncryptPhotoOrVideo(messageOwner); + return shouldEncryptPhotoOrVideo(currentAccount, messageOwner); } public static boolean isSecretPhotoOrVideo(TLRPC.Message message) { @@ -7222,6 +7635,9 @@ public boolean needDrawBluredPreview() { if (NekoXConfig.disableFlagSecure) { return false; } + if (isRepostPreview) { + return false; + } if (hasExtendedMediaPreview()) { return true; } else if (messageOwner instanceof TLRPC.TL_message_secret) { @@ -8027,7 +8443,7 @@ public boolean isAnyKindOfSticker() { } public boolean shouldDrawWithoutBackground() { - return type == TYPE_STICKER || type == TYPE_ANIMATED_STICKER || type == TYPE_ROUND_VIDEO || type == TYPE_EMOJIS || isExpiredStory(); + return !isSponsored() && (type == TYPE_STICKER || type == TYPE_ANIMATED_STICKER || type == TYPE_ROUND_VIDEO || type == TYPE_EMOJIS || isExpiredStory()); } public boolean isAnimatedEmojiStickers() { @@ -8058,6 +8474,14 @@ public boolean isVoice() { 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 +9519,7 @@ public boolean selectReaction(ReactionsLayoutInBubble.VisibleReaction visibleRea } 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,21 +9591,37 @@ public boolean isGiveaway() { 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; } - private static CharSequence userSpan; + private static CharSequence[] userSpan; public static CharSequence userSpan() { + return userSpan(0); + } + public static CharSequence userSpan(int a) { if (userSpan == null) { - userSpan = new SpannableStringBuilder("u"); + userSpan = new CharSequence[2]; + } + if (userSpan[a] == null) { + userSpan[a] = new SpannableStringBuilder("u"); ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_reply_user); span.spaceScaleX = .9f; - span.translate(0, AndroidUtilities.dp(1)); + if (a == 0) { + span.translate(0, AndroidUtilities.dp(1)); + } // span.setScale(.7f, .7f); - ((SpannableStringBuilder) userSpan).setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ((SpannableStringBuilder) userSpan[a]).setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - return userSpan; + return userSpan[a]; } private static CharSequence groupSpan; public static CharSequence groupSpan() { @@ -9324,7 +9765,7 @@ public boolean hasLinkMediaToMakeSmall() { 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 @@ -9422,9 +9863,8 @@ public static void cutIntoRanges(CharSequence text, ArrayList ranges) final int type = cutToType.get(cutIndex); if (from != cutIndex) { - int to = cutIndex; if (cutIndex - 1 >= 0 && cutIndex - 1 < text.length() && text.charAt(cutIndex - 1) == '\n') { - to--; + cutIndex--; } String lng = null; @@ -9433,7 +9873,7 @@ public static void cutIntoRanges(CharSequence text, ArrayList ranges) codeSpanIndex++; } - ranges.add(new TextRange(from, to, quoteCount > 0, codeCount > 0, lng)); + ranges.add(new TextRange(from, cutIndex, quoteCount > 0, codeCount > 0, lng)); from = cutIndex; if (from + 1 < text.length() && text.charAt(from) == '\n') { from++; @@ -9449,4 +9889,34 @@ public static void cutIntoRanges(CharSequence text, ArrayList ranges) ranges.add(new TextRange(from, text.length(), quoteCount > 0, codeCount > 0, null)); } } + + public void toggleChannelRecommendations() { + expandChannelRecommendations(!channelJoinedExpanded); + } + + public void expandChannelRecommendations(boolean expand) { + MessagesController.getInstance(currentAccount).getMainSettings().edit() + .putBoolean("c" + getDialogId() + "_rec", channelJoinedExpanded = expand) + .apply(); + } + + public static int findQuoteStart(String text, String quote, int quote_offset) { + if (text == null || quote == null) { + return -1; + } + if (quote_offset == -1) { + return text.indexOf(quote); + } + if (quote_offset + quote.length() < text.length() && text.startsWith(quote, quote_offset)) { + return quote_offset; + } + int nextIndex = text.indexOf(quote, quote_offset); + int prevIndex = text.lastIndexOf(quote, quote_offset); + if (nextIndex == -1) return prevIndex; + if (prevIndex == -1) return nextIndex; + if (nextIndex - quote_offset < quote_offset - prevIndex) { + return nextIndex; + } + return prevIndex; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagePreviewParams.java index 7dff75e4ac..6bc5456c47 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 Messages checkEdits(ArrayList replaceMessageObjects) { public boolean webpagePhoto; public boolean noforwards; + public boolean hasSecretMessages; public TLRPC.WebPage webpage; public CharacterStyle currentLink; @@ -212,10 +213,13 @@ public MessagePreviewParams(boolean secret, boolean noforwards, boolean hideForw } 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); @@ -347,18 +351,22 @@ public void checkCurrentLink(MessageObject msg) { public boolean hasLink(CharSequence text, String url) { if (url != null) { - Spannable spanned = SpannableString.valueOf(text); try { - AndroidUtilities.addLinks(spanned, Linkify.WEB_URLS); - } catch (Exception e) { - FileLog.e(e); - } - URLSpan[] urlSpans = spanned.getSpans(0, spanned.length(), URLSpan.class); + 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; + for (int i = 0; i < urlSpans.length; ++i) { + if (areUrlsEqual(urlSpans[i].getURL(), url)) { + return true; + } } + } catch (Exception e) { + FileLog.e(e); } } return false; @@ -455,6 +463,10 @@ private MessageObject toPreviewMessage(MessageObject messageObject, Boolean out, } 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; @@ -470,7 +482,7 @@ private MessageObject toPreviewMessage(MessageObject messageObject, Boolean out, 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 e2c0eb30c8..a199e4ff9b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -37,6 +37,7 @@ import androidx.collection.LongSparseArray; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationManagerCompat; +import androidx.core.graphics.ColorUtils; import androidx.core.util.Consumer; import org.telegram.SQLite.SQLiteCursor; @@ -533,10 +534,17 @@ protected boolean useCache(Integer arguments) { public int ringtoneSizeMax; public boolean storiesExportNopublicLink; public int authorizationAutoconfirmPeriod; - public int channelColorLevelMin; public int quoteLengthMax; public boolean giveawayGiftsPurchaseAvailable; public PeerColors peerColors; + public PeerColors profilePeerColors; + public int transcribeAudioTrialWeeklyNumber; + public int transcribeAudioTrialDurationMax; + public int transcribeAudioTrialCooldownUntil; + public int transcribeAudioTrialCurrentNumber; + public int recommendedChannelsLimitDefault; + public int recommendedChannelsLimitPremium; + public int boostsChannelLevelMax; public int channelsLimitDefault; public int channelsLimitPremium; @@ -575,6 +583,13 @@ protected boolean useCache(Integer arguments) { 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; @@ -590,6 +605,13 @@ protected boolean useCache(Integer arguments) { 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; @@ -725,7 +747,10 @@ public int getChatReactionsCount() { } public boolean isPremiumUser(TLRPC.User currentUser) { - return NekoConfig.localPremium.Bool() || (!premiumLocked && currentUser.premium); + if (NekoConfig.localPremium.Bool()) { + return true; + } + return !premiumFeaturesBlocked() && currentUser.premium; } public boolean didPressTranscribeButtonEnough() { @@ -743,7 +768,7 @@ public void pressTranscribeButton() { public ArrayList filterPremiumStickers(ArrayList stickerSets) { - if (!premiumLocked) { + if (!premiumFeaturesBlocked()) { return stickerSets; } for (int i = 0; i < stickerSets.size(); i++) { @@ -759,7 +784,7 @@ public ArrayList filterPremiumStickers(ArrayList checkPeerColors(false), 400); topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); @@ -2289,8 +2330,8 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { boolean keelAliveChanged = false; resetAppConfig(); TLRPC.TL_jsonObject liteAppOptions = null; - TLRPC.TL_jsonObject peer_colors = null, dark_peer_colors = null; - TLRPC.TL_jsonArray peer_colors_available = null; + int transcribeAudioTrialWeeklyNumber = 0; + int transcribeAudioTrialCooldownUntil = 0; for (int a = 0, N = object.value.size(); a < N; a++) { TLRPC.TL_jsonObjectValue value = object.value.get(a); switch (value.key) { @@ -3434,6 +3475,28 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } 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; @@ -3566,51 +3629,135 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } - case "channel_color_level_min": { + case "quote_length_max": { 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); + if (quoteLengthMax != num.value) { + quoteLengthMax = (int) num.value; + editor.putInt("quoteLengthMax", quoteLengthMax); changed = true; } } break; } - case "quote_length_max": { + case "giveaway_gifts_purchase_available": { + if (value.value instanceof TLRPC.TL_jsonBool) { + if (giveawayGiftsPurchaseAvailable != ((TLRPC.TL_jsonBool) value.value).value) { + giveawayGiftsPurchaseAvailable = ((TLRPC.TL_jsonBool) value.value).value; + editor.putBoolean("giveawayGiftsPurchaseAvailable", giveawayGiftsPurchaseAvailable); + changed = true; + } + } + break; + } + case "transcribe_audio_trial_weekly_number": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; - if (quoteLengthMax != num.value) { - quoteLengthMax = (int) num.value; - editor.putInt("quoteLengthMax", quoteLengthMax); + transcribeAudioTrialWeeklyNumber = (int) num.value; + } + break; + } + case "transcribe_audio_trial_duration_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (transcribeAudioTrialDurationMax != num.value) { + transcribeAudioTrialDurationMax = (int) num.value; + editor.putInt("transcribeAudioTrialDurationMax", transcribeAudioTrialDurationMax); changed = true; } } break; } - case "peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - peer_colors = (TLRPC.TL_jsonObject) value.value; + case "transcribe_audio_trial_cooldown_until": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + transcribeAudioTrialCooldownUntil = (int) num.value; } break; } - case "dark_peer_colors": { - if (value.value instanceof TLRPC.TL_jsonObject) { - dark_peer_colors = (TLRPC.TL_jsonObject) value.value; + case "recommended_channels_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (recommendedChannelsLimitDefault != num.value) { + recommendedChannelsLimitDefault = (int) num.value; + editor.putInt("recommendedChannelsLimitDefault", recommendedChannelsLimitDefault); + changed = true; + } } break; } - case "peer_colors_available": { - if (value.value instanceof TLRPC.TL_jsonArray) { - peer_colors_available = (TLRPC.TL_jsonArray) value.value; + case "recommended_channels_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (recommendedChannelsLimitPremium != num.value) { + recommendedChannelsLimitPremium = (int) num.value; + editor.putInt("recommendedChannelsLimitPremium", recommendedChannelsLimitPremium); + changed = true; + } } break; } - case "giveaway_gifts_purchase_available": { - if (value.value instanceof TLRPC.TL_jsonBool) { - if (giveawayGiftsPurchaseAvailable != ((TLRPC.TL_jsonBool) value.value).value) { - giveawayGiftsPurchaseAvailable = ((TLRPC.TL_jsonBool) value.value).value; - editor.putBoolean("giveawayGiftsPurchaseAvailable", giveawayGiftsPurchaseAvailable); + case "boosts_channel_level_max": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (boostsChannelLevelMax != num.value) { + boostsChannelLevelMax = (int) num.value; + editor.putInt("boostsChannelLevelMax", boostsChannelLevelMax); + changed = true; + } + } + break; + } + 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; } } @@ -3619,12 +3766,24 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } } - PeerColors newPeerColors = PeerColors.fromJSON(peer_colors, dark_peer_colors, peer_colors_available); - if (peerColors == null || !TextUtils.equals(peerColors.toString(), newPeerColors.toString())) { - peerColors = newPeerColors; - editor.putString("peerColors", peerColors.toString()); + if (transcribeAudioTrialWeeklyNumber != this.transcribeAudioTrialWeeklyNumber) { + this.transcribeAudioTrialWeeklyNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialWeeklyNumber", transcribeAudioTrialWeeklyNumber); + if (transcribeAudioTrialCurrentNumber <= 0 && (transcribeAudioTrialCooldownUntil == 0 || getConnectionsManager().getCurrentTime() > transcribeAudioTrialCooldownUntil)) { + transcribeAudioTrialCurrentNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber); + } else if (transcribeAudioTrialCurrentNumber > transcribeAudioTrialWeeklyNumber) { + transcribeAudioTrialCurrentNumber = transcribeAudioTrialWeeklyNumber; + editor.putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber); + } changed = true; } + if (transcribeAudioTrialCooldownUntil != this.transcribeAudioTrialCooldownUntil) { + this.transcribeAudioTrialCooldownUntil = transcribeAudioTrialCooldownUntil; + editor.putInt("transcribeAudioTrialCooldownUntil", transcribeAudioTrialCooldownUntil); + changed = true; + scheduleTranscriptionUpdate(); + } if (changed) { editor.apply(); @@ -3645,12 +3804,95 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { logDeviceStats(); } + public void updateTranscribeAudioTrialCurrentNumber(int num) { + if (num != transcribeAudioTrialCurrentNumber) { + transcribeAudioTrialCurrentNumber = num; + mainPreferences.edit() + .putInt("transcribeAudioTrialCurrentNumber", transcribeAudioTrialCurrentNumber) + .apply(); + } + } + + public void updateTranscribeAudioTrialCooldownUntil(int until) { + if (until != transcribeAudioTrialCooldownUntil) { + transcribeAudioTrialCooldownUntil = until; + mainPreferences.edit() + .putInt("transcribeAudioTrialCooldownUntil", transcribeAudioTrialCooldownUntil) + .apply(); + scheduleTranscriptionUpdate(); + } + } + + private void scheduleTranscriptionUpdate() { + AndroidUtilities.runOnUIThread(() -> { + AndroidUtilities.cancelRunOnUIThread(notifyTranscriptionAudioCooldownUpdate); + final long wait = transcribeAudioTrialCooldownUntil - getConnectionsManager().getCurrentTime(); + if (wait > 0) { + AndroidUtilities.runOnUIThread(notifyTranscriptionAudioCooldownUpdate, wait); + } + }); + } + private final Runnable notifyTranscriptionAudioCooldownUpdate = () -> getNotificationCenter().postNotificationName(NotificationCenter.updateTranscriptionLock); + public static class PeerColors { + public static final int TYPE_NAME = 0; + public static final int TYPE_PROFILE = 1; + + public final int type; + public final int hash; + public final ArrayList colors = new ArrayList<>(); private final LongSparseArray colorsById = new LongSparseArray<>(); - private PeerColors() {} + 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; + } @Nullable public PeerColor getColor(int colorId) { @@ -3660,6 +3902,9 @@ public PeerColor getColor(int colorId) { @NonNull public String toString() { StringBuilder sb = new StringBuilder(); + if (hash != 0) { + sb.append("@").append(hash).append("^"); + } for (int i = 0; i < colors.size(); ++i) { PeerColor color = colors.get(i); if (i > 0) sb.append(";"); @@ -3668,15 +3913,25 @@ public String toString() { return sb.toString(); } - public static PeerColors fromString(String str) { + public static PeerColors fromString(int type, String str) { if (str == null) return null; - final PeerColors peerColors = new PeerColors(); + int hash = 0; + if (str.startsWith("@")) { + int index = str.indexOf("^"); + if (index >= 0) { + hash = Utilities.parseInt(str.substring(1, index)); + str = str.substring(index + 1); + } + } + final PeerColors peerColors = new PeerColors(type, hash); final String[] colorParts = str.split(";"); for (int i = 0; i < colorParts.length; ++i) { PeerColor peerColor = PeerColor.fromString(colorParts[i]); if (peerColor == null) continue; - peerColors.colors.add(peerColor); + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; + if (!peerColor.hidden) + peerColors.colors.add(peerColor); peerColors.colorsById.put(peerColor.id, peerColor); } return peerColors; @@ -3686,13 +3941,33 @@ private static int color(String str) { return Integer.parseUnsignedInt("ff" + str, 16); } + public static PeerColors fromTL(int type, TLRPC.TL_help_peerColors tl) { + if (tl == null) return null; + try { + PeerColors peerColors = new PeerColors(type, tl.hash); + for (int i = 0; i < tl.colors.size(); ++i) { + PeerColor peerColor = PeerColor.fromTL(tl.colors.get(i)); + if (peerColor == null) continue; + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; + if (!peerColor.hidden) + peerColors.colors.add(peerColor); + peerColors.colorsById.put(peerColor.id, peerColor); + } + return peerColors; + } catch (Exception e) { + FileLog.e(e); + } + return null; + } + public static PeerColors fromJSON( + int type, TLRPC.TL_jsonObject peer_colors, TLRPC.TL_jsonObject dark_peer_colors, TLRPC.TL_jsonArray peer_colors_available ) { try { - PeerColors peerColors = new PeerColors(); + PeerColors peerColors = new PeerColors(type, 0); if (peer_colors != null) { for (TLRPC.TL_jsonObjectValue pair : peer_colors.value) { final int id = Utilities.parseInt(pair.key); @@ -3705,14 +3980,13 @@ public static PeerColors fromJSON( PeerColor peerColor = new PeerColor(); try { peerColor.id = id; - peerColor.color1 = peerColor.darkColor1 = color(((TLRPC.TL_jsonString) val.get(0)).value); - peerColor.color2 = peerColor.darkColor2 = val.size() > 1 ? color(((TLRPC.TL_jsonString) val.get(1)).value) : peerColor.color1; - peerColor.color3 = peerColor.darkColor3 = val.size() > 2 ? color(((TLRPC.TL_jsonString) val.get(2)).value) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.colors[i] = peerColor.darkColors[i] = val.size() > i ? color(((TLRPC.TL_jsonString) val.get(i)).value) : peerColor.colors[0]; } catch (Exception e2) { FileLog.e(e2); continue; } - if (peerColor.id < 7) continue; + peerColor.isDefaultName = peerColor.id < 7 && type == TYPE_NAME; peerColors.colorsById.put(id, peerColor); } } @@ -3729,9 +4003,8 @@ public static PeerColors fromJSON( if (peerColor == null) continue; try { peerColor.id = id; - peerColor.darkColor1 = color(((TLRPC.TL_jsonString) val.get(0)).value); - peerColor.darkColor2 = val.size() > 1 ? color(((TLRPC.TL_jsonString) val.get(1)).value) : peerColor.darkColor1; - peerColor.darkColor3 = val.size() > 2 ? color(((TLRPC.TL_jsonString) val.get(2)).value) : peerColor.darkColor1; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = val.size() > i ? color(((TLRPC.TL_jsonString) val.get(i)).value) : peerColor.darkColors[0]; } catch (Exception e2) { FileLog.e(e2); continue; @@ -3759,17 +4032,52 @@ public static PeerColors fromJSON( } public static class PeerColor { + public boolean isDefaultName; public int id; - private int color1, color2, color3; - private int darkColor1, darkColor2, darkColor3; + 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]; + } + public int getColor2(boolean isDark) { + return (isDark ? darkColors : colors)[1]; + } + public int getColor3(boolean isDark) { + return (isDark ? darkColors : colors)[2]; + } + public int getColor4(boolean isDark) { + return (isDark ? darkColors : colors)[3]; + } + public int getColor5(boolean isDark) { + return (isDark ? darkColors : colors)[4]; + } + public int getColor6(boolean isDark) { + return (isDark ? darkColors : colors)[5]; + } public int getColor1() { - return Theme.isCurrentThemeDark() ? darkColor1 : color1; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[0]; } public int getColor2() { - return Theme.isCurrentThemeDark() ? darkColor2 : color2; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[1]; } public int getColor3() { - return Theme.isCurrentThemeDark() ? darkColor3 : color3; + return (Theme.isCurrentThemeDark() ? darkColors : colors)[2]; + } + public int getColor4() { + return (Theme.isCurrentThemeDark() ? darkColors : colors)[3]; + } + public int getColor5() { + return (Theme.isCurrentThemeDark() ? darkColors : colors)[4]; } public boolean hasColor2() { return getColor2() != getColor1(); @@ -3777,55 +4085,164 @@ public boolean hasColor2() { public boolean hasColor3() { return getColor3() != getColor1(); } + public boolean hasColor2(boolean isDark) { + return getColor2(isDark) != getColor1(isDark); + } + public boolean hasColor3(boolean isDark) { + return getColor3(isDark) != getColor1(isDark); + } + public boolean hasColor6(boolean isDark) { + return getColor6(isDark) != getColor1(isDark); + } + public int getBgColor1(boolean isDark) { + return hasColor6(isDark) ? getColor3(isDark) : getColor2(isDark); + } + public int getBgColor2(boolean isDark) { + return hasColor6(isDark) ? getColor4(isDark) : getColor2(isDark); + } + public int getStoryColor1(boolean isDark) { + return hasColor6(isDark) ? getColor5(isDark) : getColor3(isDark); + } + public int getStoryColor2(boolean isDark) { + return hasColor6(isDark) ? getColor6(isDark) : getColor4(isDark); + } + public int getAvatarColor1() { + return ColorUtils.blendARGB(getBgColor2(false), getStoryColor2(false), .5f); + } + public int getAvatarColor2() { + return ColorUtils.blendARGB(getBgColor1(false), getStoryColor1(false), .5f); + } public void appendString(StringBuilder sb) { sb.append("#"); + if (hidden) sb.append("H"); + if (lvl > 0) { + sb.append("[").append(lvl).append("]"); + } sb.append(id); sb.append("{"); - sb.append(color1); - if (color2 != color1) { + sb.append(colors[0]); + if (colors[1] != colors[0]) { sb.append(","); - sb.append(color2); - if (color3 != color1) { + sb.append(colors[1]); + if (colors[2] != colors[0] || colors[3] != colors[0]) { + sb.append(","); + sb.append(colors[2]); sb.append(","); - sb.append(color3); + sb.append(colors[3]); + if (colors[4] != colors[0] || colors[5] != colors[0]) { + sb.append(","); + sb.append(colors[4]); + sb.append(","); + sb.append(colors[5]); + } } } - if (darkColor1 != color1 || darkColor2 != color2 || darkColor3 != color3) { + if (darkColors[0] != colors[0] || darkColors[1] != colors[1] || darkColors[2] != colors[2]) { sb.append("@"); - sb.append(darkColor1); - if (darkColor2 != darkColor1) { + sb.append(darkColors[0]); + if (darkColors[1] != darkColors[0]) { sb.append(","); - sb.append(darkColor2); - if (darkColor3 != darkColor1) { + sb.append(darkColors[1]); + if (darkColors[2] != darkColors[0] || darkColors[3] != darkColors[0]) { sb.append(","); - sb.append(darkColor3); + sb.append(darkColors[2]); + sb.append(","); + sb.append(darkColors[3]); + if (darkColors[4] != darkColors[0] || darkColors[5] != darkColors[0]) { + sb.append(","); + sb.append(darkColors[4]); + sb.append(","); + sb.append(darkColors[5]); + } } } } sb.append("}"); } + + public static PeerColor fromTL(TLRPC.TL_help_peerColorOption tl) { + if (tl == null) return null; + + final PeerColor peerColor = new PeerColor(); + peerColor.id = tl.color_id; + peerColor.hidden = tl.hidden; + 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); + return peerColor; + } + + public static int[] optionToColors(TLRPC.help_PeerColorSet set) { + final int[] colors = new int[] {0, 0, 0, 0, 0, 0}; + ArrayList finalColorList = null; + if (set instanceof TLRPC.TL_help_peerColorSet) { + finalColorList = ((TLRPC.TL_help_peerColorSet) set).colors; + } else if (set instanceof TLRPC.TL_help_peerColorProfileSet) { + ArrayList colorList1 = ((TLRPC.TL_help_peerColorProfileSet) set).palette_colors; + ArrayList colorList2 = ((TLRPC.TL_help_peerColorProfileSet) set).bg_colors; + ArrayList colorList3 = ((TLRPC.TL_help_peerColorProfileSet) set).story_colors; + finalColorList = new ArrayList(); + if (colorList1 != null) { + for (int i = 0; i < Math.min(2, colorList1.size()); ++i) + finalColorList.add(colorList1.get(i)); + } + if (colorList2 != null) { + for (int i = 0; i < Math.min(2, colorList2.size()); ++i) + finalColorList.add(colorList2.get(i)); + } + if (colorList3 != null) { + for (int i = 0; i < Math.min(2, colorList3.size()); ++i) + finalColorList.add(colorList3.get(i)); + } + } + if (finalColorList != null) { + if (finalColorList.size() > 0) { + Arrays.fill(colors, 0xFF000000 | finalColorList.get(0)); + } + for (int i = 0; i < Math.min(colors.length, finalColorList.size()); ++i) { + colors[i] = 0xFF000000 | finalColorList.get(i); + } + } + return colors; + } + public static PeerColor fromString(String string) { if (string == null || string.isEmpty() || string.charAt(0) != '#') return null; + int startIndex = 1; + boolean hidden = string.length() > 1 && string.charAt(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(1, index)); + 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(","); - peerColor.color1 = Utilities.parseInt(colorsString[0]); - peerColor.color2 = colorsString.length >= 2 ? Utilities.parseInt(colorsString[1]) : peerColor.color1; - peerColor.color3 = colorsString.length >= 3 ? Utilities.parseInt(colorsString[2]) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.colors[i] = colorsString.length >= i + 1 ? Utilities.parseInt(colorsString[i]) : peerColor.colors[0]; if (parts.length >= 2) { colorsString = parts[1].split(","); - peerColor.darkColor1 = Utilities.parseInt(colorsString[0]); - peerColor.darkColor2 = colorsString.length >= 2 ? Utilities.parseInt(colorsString[1]) : peerColor.color1; - peerColor.darkColor3 = colorsString.length >= 3 ? Utilities.parseInt(colorsString[2]) : peerColor.color1; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = colorsString.length >= i + 1 ? Utilities.parseInt(colorsString[i]) : peerColor.darkColors[0]; } else { - peerColor.darkColor1 = peerColor.color1; - peerColor.darkColor2 = peerColor.color2; - peerColor.darkColor3 = peerColor.color3; + for (int i = 0; i < 6; ++i) + peerColor.darkColors[i] = peerColor.colors[i]; } return peerColor; } catch (Exception e) { @@ -3913,9 +4330,9 @@ public void removeSuggestion(long did, String suggestion) { public void updateConfig(final TLRPC.TL_config config) { AndroidUtilities.runOnUIThread(() -> { - // TODO: receive those removed parameters from appconfig getDownloadController().loadAutoDownloadConfig(false); - loadAppConfig(); + loadAppConfig(true); + checkPeerColors(true); thisDc = config.this_dc; remoteConfigLoaded = true; maxMegagroupCount = config.megagroup_size_max; @@ -4286,7 +4703,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } } AndroidUtilities.runOnUIThread(() -> { - if (uploadingWallpaper != null && wallPaper != null) { + if (uploadingWallpaper != null && uploadingWallpaperInfo.requestIds != null && wallPaper != null) { wallPaper.settings = settings; wallPaper.flags |= 4; overrideWallpaperInfo.slug = wallPaper.slug; @@ -4301,8 +4718,8 @@ public void didReceivedNotification(int id, int account, Object... args) { ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForDocument(image, wallPaper.document), false); } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.wallpapersNeedReload, wallPaper.slug); - if (overrideWallpaperInfo.dialogId != 0) { - uploadingWallpaperInfo.requestIds.add(ChatThemeController.getInstance(currentAccount).setWallpaperToUser(overrideWallpaperInfo.dialogId, uploadingWallpaperFinal, overrideWallpaperInfo, null, null)); + if (uploadingWallpaperInfo.requestIds != null && overrideWallpaperInfo.dialogId != 0) { + uploadingWallpaperInfo.requestIds.add(ChatThemeController.getInstance(currentAccount).setWallpaperToPeer(overrideWallpaperInfo.dialogId, uploadingWallpaperFinal, overrideWallpaperInfo, null, null)); } } }); @@ -4697,7 +5114,6 @@ public void cleanup() { loadingSuggestedFilters = false; loadingRemoteFilters = false; suggestedFilters.clear(); - gettingAppChangelog = false; dialogFiltersLoaded = false; ignoreSetOnline = false; @@ -5082,6 +5498,7 @@ public void putChat(final TLRPC.Chat chat, boolean fromCache) { } } } + updateEmojiStatusUntilUpdate(-chat.id, chat.emoji_status); if (chat.min) { if (oldChat != null) { if (!fromCache) { @@ -5163,7 +5580,7 @@ public void putChat(final TLRPC.Chat chat, boolean fromCache) { } 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) { @@ -5551,6 +5968,7 @@ public void loadFullChat(long chatId, int classGuid, boolean force) { 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) { @@ -5632,6 +6050,10 @@ public void loadFullChat(long chatId, int classGuid, boolean force) { dialog.ttl_period = res.full_chat.ttl_period; getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } + 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 { @@ -10960,7 +11382,6 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL migratingDialogs = false; getNotificationCenter().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); } else { - // generateUpdateMessage(); if (!added && loadType == DIALOGS_LOAD_TYPE_CACHE && dialogsEndReached.get(folderId)) { loadDialogs(folderId, 0, count, false); } @@ -12102,13 +12523,28 @@ public void convertToMegaGroup(Context context, long chatId, BaseFragment fragme 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 { @@ -12951,27 +13387,6 @@ public void performLogout(int type) { SharedConfig.saveAccounts(); } - - 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; @@ -14321,14 +14736,18 @@ public void loadPinnedDialogs(final int folderId, long newDialogId, ArrayList { - putUsers(res.users, false); - putChats(res.chats, false); - }); - getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); - - ArrayList pushMessages; - if (createMessage && Math.abs(getConnectionsManager().getCurrentTime() - res.participant.date) < 24 * 60 * 60 && !getMessagesStorage().hasInviteMeMessage(chatId)) { - TLRPC.TL_messageService message = new TLRPC.TL_messageService(); - message.media_unread = true; - message.unread = true; - message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; - message.post = true; - message.local_id = message.id = getUserConfig().getNewMessageId(); - message.date = res.participant.date; - if (selfParticipant.inviter_id != getUserConfig().getClientUserId()) { - message.action = new TLRPC.TL_messageActionChatAddUser(); - } else if (selfParticipant.via_invite) { - message.action = new TLRPC.TL_messageActionChatJoinedByRequest(); - } - message.from_id = new TLRPC.TL_peerUser(); - message.from_id.user_id = res.participant.inviter_id; - message.action.users.add(getUserConfig().getClientUserId()); - message.peer_id = new TLRPC.TL_peerChannel(); - message.peer_id.channel_id = chatId; - message.dialog_id = -chatId; - getUserConfig().saveConfig(false); - - pushMessages = new ArrayList<>(); - ArrayList messagesArr = new ArrayList<>(); - - ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); - for (int a = 0; a < res.users.size(); a++) { - TLRPC.User user = res.users.get(a); - usersDict.put(user.id, user); - } + if (chat.megagroup && getMessagesStorage().isMigratedChat(chat.id)) { + return; + } + AndroidUtilities.runOnUIThread(() -> { + putUsers(res.users, false); + putChats(res.chats, false); + }); + getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); - messagesArr.add(message); - MessageObject obj = new MessageObject(currentAccount, message, usersDict, true, false); - pushMessages.add(obj); - getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, true, false, null))); - getMessagesStorage().putMessages(messagesArr, true, true, false, 0, false, 0); + ArrayList pushMessages; + if (createMessage && Math.abs(getConnectionsManager().getCurrentTime() - res.participant.date) < 24 * 60 * 60 && !getMessagesStorage().hasInviteMeMessage(chatId)) { + TLRPC.TL_messageService message = new TLRPC.TL_messageService(); + message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.local_id = message.id = getUserConfig().getNewMessageId(); + message.date = res.participant.date; + message.from_id = new TLRPC.TL_peerUser(); + message.from_id.user_id = res.participant.inviter_id; + message.peer_id = new TLRPC.TL_peerChannel(); + message.peer_id.channel_id = chatId; + message.media_unread = true; + message.unread = true; + message.post = true; + if (!selfParticipant.via_invite || selfParticipant.inviter_id != getUserConfig().getClientUserId()) { + message.action = new TLRPC.TL_messageActionChatAddUser(); } else { - pushMessages = null; + message.action = new TLRPC.TL_messageActionChatJoinedByRequest(); } + message.action.users.add(getUserConfig().getClientUserId()); + message.dialog_id = -chatId; + getUserConfig().saveConfig(false); - getMessagesStorage().saveChatInviter(chatId, res.participant.inviter_id); + pushMessages = new ArrayList<>(); + ArrayList messagesArr = new ArrayList<>(); - AndroidUtilities.runOnUIThread(() -> { - gettingChatInviters.delete(chatId); - if (pushMessages != null) { - updateInterfaceWithMessages(-chatId, pushMessages, false); - getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); - } - getNotificationCenter().postNotificationName(NotificationCenter.didLoadChatInviter, chatId, res.participant.inviter_id); - }); + ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + + messagesArr.add(message); + MessageObject obj = new MessageObject(currentAccount, message, usersDict, true, false); + pushMessages.add(obj); + getMessagesStorage().getStorageQueue().postRunnable(() -> AndroidUtilities.runOnUIThread(() -> getNotificationsController().processNewMessages(pushMessages, true, false, null))); + getMessagesStorage().putMessages(messagesArr, true, true, false, 0, false, 0); + } else { + pushMessages = null; } + + getMessagesStorage().saveChatInviter(chatId, res.participant.inviter_id); + + AndroidUtilities.runOnUIThread(() -> { + gettingChatInviters.delete(chatId); + if (pushMessages != null) { + updateInterfaceWithMessages(-chatId, pushMessages, false); + getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); + } + getNotificationCenter().postNotificationName(NotificationCenter.didLoadChatInviter, chatId, res.participant.inviter_id); + }); } }); } @@ -14596,6 +15013,8 @@ public static long getUpdateChannelId(TLRPC.Update update) { return ((TLRPC.TL_updateChannelUserTyping) update).channel_id; } else if (update instanceof TLRPC.TL_updatePinnedChannelMessages) { return ((TLRPC.TL_updatePinnedChannelMessages) update).channel_id; + } else if (update instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + return ((TLRPC.TL_updateChannelViewForumAsMessages) update).channel_id; } else { if (BuildVars.LOGS_ENABLED) { FileLog.e("trying to get unknown update channel_id for " + update); @@ -15651,6 +16070,11 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updatePeerWallpaper) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateUserEmojiStatus) { interfaceUpdateMask |= UPDATE_MASK_EMOJI_STATUS; if (updatesOnMainThread == null) { @@ -16415,6 +16839,11 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); + } else if (baseUpdate instanceof TLRPC.TL_updateChannelViewForumAsMessages) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } } if (messages != null) { @@ -16554,6 +16983,9 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList reactions, Utilities.Callback onError, Runnable onSuccess) { + TLRPC.TL_messages_setChatAvailableReactions req = new TLRPC.TL_messages_setChatAvailableReactions(); + req.peer = getInputPeer(-chatId); + if (type == ChatReactionsEditActivity.SELECT_TYPE_NONE || reactions.isEmpty()) { + req.available_reactions = new TLRPC.TL_chatReactionsNone(); + } else if (type == ChatReactionsEditActivity.SELECT_TYPE_ALL) { + req.available_reactions = new TLRPC.TL_chatReactionsAll(); + } else { + TLRPC.TL_chatReactionsSome someReactions = new TLRPC.TL_chatReactionsSome(); + req.available_reactions = someReactions; + someReactions.reactions.addAll(reactions); + } + getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + TLRPC.ChatFull full = getChatFull(chatId); + if (full != null) { + if (full instanceof TLRPC.TL_chatFull) { + full.flags |= 262144; + } + if (full instanceof TLRPC.TL_channelFull) { + full.flags |= 1073741824; + } + full.available_reactions = req.available_reactions; + getMessagesStorage().updateChatInfo(full, false); + } + AndroidUtilities.runOnUIThread(() -> { + if (onSuccess != null) { + onSuccess.run(); + } + getNotificationCenter().postNotificationName(NotificationCenter.chatAvailableReactionsUpdated, chatId, 0); + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + if (onError != null) { + onError.run(error); + } + }); + } + }); + } + public void setChatReactions(long chatId, int type, List reactions) { TLRPC.TL_messages_setChatAvailableReactions req = new TLRPC.TL_messages_setChatAvailableReactions(); req.peer = getInputPeer(-chatId); @@ -19150,13 +19651,13 @@ public interface NewMessageCallback { 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(); @@ -19372,10 +19873,18 @@ public void cancelUploadWallpaper() { } 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; @@ -19448,4 +19957,91 @@ public boolean storyEntitiesAllowed(TLRPC.User user) { return false; } } + + public static class ChannelRecommendations { + public boolean wasPremium; + public final ArrayList chats = new ArrayList<>(); + public int more; + + public static boolean hasRecommendations(ChannelRecommendations rec) { + return rec != null && !rec.chats.isEmpty(); + } + + public static boolean hasRecommendations(int currentAccount, long chatId) { + return hasRecommendations(MessagesController.getInstance(currentAccount).getChannelRecommendations(chatId)); + } + } + + private HashMap cachedChannelRecommendations; + public ChannelRecommendations getChannelRecommendations(long chatId) { + TLRPC.InputChannel inputChannel = getInputChannel(chatId); + if (inputChannel == null) { + return null; + } + if (cachedChannelRecommendations == null) { + cachedChannelRecommendations = new HashMap<>(); + } + final boolean isPremium = getUserConfig().isPremium(); + ChannelRecommendations rec = null; + if (cachedChannelRecommendations.containsKey(chatId)) { + rec = cachedChannelRecommendations.get(chatId); + if (rec != null && rec.wasPremium == isPremium) { + return rec; + } + } + cachedChannelRecommendations.put(chatId, null); + TLRPC.TL_channels_getChannelRecommendations req = new TLRPC.TL_channels_getChannelRecommendations(); + req.channel = inputChannel; + getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.messages_Chats) { + ArrayList chats = ((TLRPC.messages_Chats) res).chats; + putChats(chats, false); + + ChannelRecommendations newrec = new ChannelRecommendations(); + newrec.wasPremium = isPremium; + newrec.chats.addAll(chats); + if (res instanceof TLRPC.TL_messages_chatsSlice) { + newrec.more = Math.max(0, ((TLRPC.TL_messages_chatsSlice) res).count - chats.size()); + } else if (!getUserConfig().isPremium() && BuildVars.DEBUG_PRIVATE_VERSION) { + newrec.more = 90; + } + cachedChannelRecommendations.put(chatId, newrec); + getNotificationCenter().postNotificationName(NotificationCenter.channelRecommendationsLoaded, chatId); + } + })); + return rec; + } + + public void checkPeerColors(boolean force) { + if (peerColors == null || 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(() -> { + peerColors = PeerColors.fromTL(PeerColors.TYPE_NAME, (TLRPC.TL_help_peerColors) res); + mainPreferences.edit().putString("peerColors", peerColors.toString()).apply(); + }); + } + }); + } + 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(() -> { + profilePeerColors = PeerColors.fromTL(PeerColors.TYPE_PROFILE, (TLRPC.TL_help_peerColors) res); + mainPreferences.edit().putString("profilePeerColors", profilePeerColors.toString()).apply(); + }); + } + }); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 32c3ff44bd..6c1b3f1297 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -2077,6 +2077,7 @@ private TLRPC.messages_Dialogs loadDialogsByIds(String ids, ArrayList user dialog.unread_mentions_count = cursor.intValue(15); int dialog_flags = cursor.intValue(16); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; long flags = cursor.longValue(8); int low_flags = (int) flags; dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); @@ -8425,6 +8426,9 @@ public Runnable getMessagesInternal(long dialogId, long mergeDialogId, int count data = cursor.byteBufferValue(6); if (data != null) { message.replyStory = TL_stories.StoryItem.TLdeserialize(data, data.readInt32(false), false); + if (message.replyStory != null && message.replyStory.fwd_from != null) { + addLoadPeerInfo(message.replyStory.fwd_from.from, usersToLoad, chatsToLoad); + } data.reuse(); } } @@ -11289,7 +11293,7 @@ private void putMessagesInternal(ArrayList messages, boolean with dids.add(key); if (exists) { - if (messageId >= last_mid || DialogObject.isEncryptedDialog(key)) { + if (message == null || message.date > dialog_date || DialogObject.isEncryptedDialog(key)) { state_dialogs_update.requery(); state_dialogs_update.bindInteger(1, message != null && (!doNotUpdateDialogDate || dialog_date == 0) ? message.date : dialog_date); state_dialogs_update.bindInteger(2, old_unread_count + unread_count); @@ -11586,7 +11590,7 @@ private void createOrEditTopic(long dialogId, TLRPC.Message message) { forumTopic.topicStartMessage = message; forumTopic.top_message = message.id; forumTopic.topMessage = message; - forumTopic.from_id = getMessagesController().getPeer(getUserConfig().clientUserId); + forumTopic.from_id = message.from_id; forumTopic.notify_settings = new TLRPC.TL_peerNotifySettings(); forumTopic.unread_count = 0; @@ -12789,6 +12793,7 @@ private void updateDialogsWithDeletedMessagesInternal(long originalDialogId, lon dialog.pinned = dialog.pinnedNum != 0; int dialog_flags = cursor.intValue(14); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; dialog.folder_id = cursor.intValue(15); dialog.unread_reactions_count = cursor.intValue(17); long groupMessagesId = cursor.longValue(18); @@ -14180,6 +14185,14 @@ public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList< } } } + 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()) { @@ -14188,6 +14201,39 @@ public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList< } } } + 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) { + if (message.media.webpage.attributes.get(i) instanceof TLRPC.TL_webPageAttributeStory) { + TLRPC.TL_webPageAttributeStory attr = (TLRPC.TL_webPageAttributeStory) message.media.webpage.attributes.get(i); + if (attr.storyItem != null && attr.storyItem.fwd_from != null) { + addLoadPeerInfo(attr.storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } + if (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); + } + } + } + } + } + } if (message.media.peer != null) { addLoadPeerInfo(message.media.peer, usersToLoad, chatsToLoad); } @@ -14220,7 +14266,7 @@ public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList< } } - private static void addLoadPeerInfo(TLRPC.Peer peer, ArrayList usersToLoad, ArrayList chatsToLoad) { + public static void addLoadPeerInfo(TLRPC.Peer peer, ArrayList usersToLoad, ArrayList chatsToLoad) { if (peer instanceof TLRPC.TL_peerUser) { if (!usersToLoad.contains(peer.user_id)) { usersToLoad.add(peer.user_id); @@ -14321,6 +14367,7 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe dialog.unread_mentions_count = cursor.intValue(15); int dialog_flags = cursor.intValue(16); dialog.unread_mark = (dialog_flags & 1) != 0; + dialog.view_forum_as_messages = (dialog_flags & 64) != 0; long flags = cursor.longValue(8); int low_flags = (int) flags; dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); @@ -14829,6 +14876,9 @@ private void putDialogsInternal(TLRPC.messages_Dialogs dialogs, int check) { if (dialog.unread_mark) { flags |= 1; } + if (dialog.view_forum_as_messages) { + flags |= 64; + } state_dialogs.bindInteger(12, flags); state_dialogs.bindInteger(13, dialog.folder_id); NativeByteBuffer data; @@ -15138,6 +15188,46 @@ public void setDialogUnread(long did, boolean unread) { }); } + public void setDialogViewThreadAsMessages(long did, boolean enabled) { + storageQueue.postRunnable(() -> { + SQLitePreparedStatement state = null; + try { + int flags = 0; + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT flags FROM dialogs WHERE did = " + did); + if (cursor.next()) { + flags = cursor.intValue(0); + } + } catch (Exception e) { + checkSQLException(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + + if (enabled) { + flags |= 64; + } else { + flags &= ~64; + } + + state = database.executeFast("UPDATE dialogs SET flags = ? WHERE did = ?"); + state.bindInteger(1, flags); + state.bindLong(2, did); + state.step(); + state.dispose(); + } catch (Exception e) { + checkSQLException(e); + } finally { + if (state != null) { + state.dispose(); + } + } + }); + } + public void resetAllUnreadCounters(boolean muted) { for (int a = 0, N = dialogFilters.size(); a < N; a++) { MessagesController.DialogFilter filter = dialogFilters.get(a); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 8c9ed5dc14..eeaf94215e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -137,6 +137,7 @@ public class NotificationCenter { public static final int animatedEmojiDocumentLoaded = totalEvents++; public static final int recentEmojiStatusesUpdate = totalEvents++; public static final int updateSearchSettings = totalEvents++; + public static final int updateTranscriptionLock = totalEvents++; public static final int messageTranslated = totalEvents++; public static final int messageTranslating = totalEvents++; @@ -211,6 +212,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 +224,8 @@ public class NotificationCenter { public static final int storiesSendAsUpdate = totalEvents++; public static final int unconfirmedAuthUpdate = totalEvents++; public static final int dialogPhotosUpdate = totalEvents++; + public static final int channelRecommendationsLoaded = totalEvents++; + public static final int savedMessagesUpdate = totalEvents++; //global public static final int pushMessagesUpdated = totalEvents++; @@ -285,21 +290,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 2a508ef288..332551c1eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -2180,6 +2180,8 @@ private String getShortStringForMessage(MessageObject messageObject, String[] us } } 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) { @@ -2431,6 +2433,8 @@ private String getStringForMessage(MessageObject messageObject, boolean shortMes } 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) { @@ -2885,6 +2889,8 @@ private String getStringForMessage(MessageObject messageObject, boolean shortMes } 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/OSMDroidMapsProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/OSMDroidMapsProvider.java index 6233d85212..3d05778248 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/OSMDroidMapsProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/OSMDroidMapsProvider.java @@ -513,7 +513,7 @@ public void setTag(Object tag) { @Override public LatLng getPosition() { GeoPoint pos = this.marker.getPosition(); - return new LatLng(pos.getLatitude(), pos.getLatitude()); + return new LatLng(pos.getLatitude(), pos.getLongitude()); } @Override 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 0000000000..a3896ed82c --- /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/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index edacf57d9f..7822832d39 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -155,6 +155,8 @@ public TLRPC.InputReplyTo createReplyInput(TLRPC.InputPeer sendToPeer, int reply replyTo.quote_entities = new ArrayList<>(replyTo.quote_entities); replyTo.flags |= 8; } + replyTo.flags |= 16; + replyTo.quote_offset = replyQuote.start; } } if (replyQuote != null && replyQuote.message != null) { @@ -188,6 +190,10 @@ public TLRPC.InputReplyTo createReplyInput(TLRPC.TL_messageReplyHeader replyHead replyTo.flags |= 8; replyTo.quote_entities = replyHeader.quote_entities; } + if ((replyHeader.flags & 1024) != 0) { + replyTo.flags |= 16; + replyTo.quote_offset = replyHeader.quote_offset; + } } return replyTo; } @@ -3866,6 +3872,8 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (!TextUtils.isEmpty(newMsg.reply_to.quote_text)) { newMsg.reply_to.quote = true; newMsg.reply_to.flags |= 64; + newMsg.reply_to.flags |= 1024; + newMsg.reply_to.quote_offset = replyQuote.start; newMsg.reply_to.quote_entities = replyQuote.getEntities(); if (newMsg.reply_to.quote_entities != null && !newMsg.reply_to.quote_entities.isEmpty()) { newMsg.reply_to.quote_entities = new ArrayList<>(newMsg.reply_to.quote_entities); @@ -3986,6 +3994,8 @@ public void sendMessage(SendMessageParams sendMessageParams) { if (replyQuote.getText() != null) { newMsg.reply_to.flags |= 64; newMsg.reply_to.quote_text = replyQuote.getText(); + newMsg.reply_to.flags |= 1024; + newMsg.reply_to.quote_offset = replyQuote.start; } if (replyQuote.getEntities() != null) { newMsg.reply_to.flags |= 128; @@ -6648,7 +6658,7 @@ private static int prepareSendingDocumentInternal(AccountInstance accountInstanc title = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); permormer = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); } - if (editingMessageObject == null && extL.equals("ogg") && MediaController.isOpusFile(f.getAbsolutePath()) == 1) { + if (editingMessageObject == null && extL.equals("opus") && MediaController.isOpusFile(f.getAbsolutePath()) == 1) { isVoice = true; } } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index c07fbd53b1..ca0572ede7 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.SystemClock; import android.text.TextUtils; import android.util.Base64; -import android.util.Log; import android.webkit.WebView; import androidx.annotation.Nullable; @@ -350,6 +349,8 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { 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; @@ -373,6 +374,7 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { public static int storiesColumnsCount = 3; public static int fastScrollHintCount = 3; public static boolean dontAskManageStorage; + public static boolean multipleReactionsPromoShowed; public static boolean translateChats = true; @@ -1293,7 +1295,6 @@ public static void saveConfig() { 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); @@ -1410,7 +1411,7 @@ public static void loadConfig() { 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); @@ -1430,7 +1431,7 @@ public static void loadConfig() { FileLog.e(e); } if (updateVersion == 0) { - updateVersion = BuildVars.BUILD_VERSION; + updateVersion = buildVersion(); } if (updateVersionString == null) { updateVersionString = BuildVars.BUILD_VERSION_STRING; @@ -1550,6 +1551,9 @@ public static void loadConfig() { useSurfaceInStories = preferences.getBoolean("useSurfaceInStories", Build.VERSION.SDK_INT >= 30); payByInvoice = preferences.getBoolean("payByInvoice", false); photoViewerBlur = preferences.getBoolean("photoViewerBlur", true); + multipleReactionsPromoShowed = preferences.getBoolean("multipleReactionsPromoShowed", false); + forceLessData = preferences.getBoolean("forceLessData", false); + callEncryptionHintDisplayedCount = preferences.getInt("callEncryptionHintDisplayedCount", 0); loadDebugConfig(preferences); @@ -1569,6 +1573,15 @@ public static void loadConfig() { } + 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); @@ -1646,7 +1659,15 @@ public static boolean isAppUpdateAvailable() { if (pendingAppUpdate == null || pendingAppUpdate.document == null || !ApplicationLoader.isStandaloneBuild()) { return false; } - return pendingAppUpdateBuildVersion == BuildVars.BUILD_VERSION; + int currentVersion; + try { + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + currentVersion = pInfo.versionCode; + } catch (Exception e) { + FileLog.e(e); + currentVersion = buildVersion(); + } + return pendingAppUpdateBuildVersion == currentVersion; } public static boolean setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) { @@ -1660,7 +1681,7 @@ public static boolean setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) FileLog.e(e); } if (versionCode == 0) { - versionCode = BuildVars.BUILD_VERSION; + versionCode = buildVersion(); } if (updateVersionString == null) { updateVersionString = BuildVars.BUILD_VERSION_STRING; @@ -1742,7 +1763,6 @@ public static void clearConfig() { useFingerprint = false; isWaitingForPasscodeEnter = false; allowScreenCapture = false; - lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; textSelectionHintShows = 0; scheduledOrNoSoundHintShows = 0; scheduledOrNoSoundHintSeenAt = 0; @@ -1759,6 +1779,14 @@ public static void clearConfig() { saveConfig(); } + public static void setMultipleReactionsPromoShowed(boolean val) { + multipleReactionsPromoShowed = val; + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("multipleReactionsPromoShowed", multipleReactionsPromoShowed); + editor.apply(); + } + public static void setSuggestStickers(int type) { suggestStickers = type; SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -1958,6 +1986,14 @@ public static void toggleDebugWebView() { 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); } @@ -2601,6 +2637,10 @@ public static void updateEmojiInteractionsHintCount(int count) { 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 a52e23562c..4b2bd26573 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -658,6 +658,17 @@ public void toggleShowTopic(long chatId, int topicId, boolean show) { }); } + public void toggleViewForumAsMessages(long channelId, boolean enabled) { + TLRPC.TL_channels_toggleViewForumAsMessages request = new TLRPC.TL_channels_toggleViewForumAsMessages(); + request.channel_id = getMessagesController().getInputChannel(channelId); + request.enabled = enabled; + getConnectionsManager().sendRequest(request, (res, err) -> { + if (res != null) { + getMessagesController().processUpdates((TLRPC.Updates) res, false); + } + }); + } + public void pinTopic(long chatId, int topicId, boolean pin, BaseFragment fragment) { TLRPC.TL_channels_updatePinnedForumTopic req = new TLRPC.TL_channels_updatePinnedForumTopic(); req.channel = getMessagesController().getInputChannel(chatId); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 8aea32280d..2f3cb2cef5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -280,7 +280,7 @@ private void checkPremiumSelf(TLRPC.User oldUser, TLRPC.User newUser) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.premiumStatusChangedGlobal); getMediaDataController().loadPremiumPromo(false); - getMediaDataController().loadReactions(false, true); + getMediaDataController().loadReactions(false, null); getMessagesController().getStoriesController().invalidateStoryLimit(); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index 0b7ca6b2e9..1433a78b5d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -16,6 +16,7 @@ import org.telegram.tgnet.TLRPC; import xyz.nextalone.nagram.helper.MessageHelper; +import xyz.nextalone.nagram.helper.PeerColorHelper; public class UserObject { @@ -144,4 +145,41 @@ public static Long getEmojiStatusDocumentId(TLRPC.EmojiStatus emojiStatus) { public static boolean isService(long user_id) { return user_id == 333000 || user_id == 777000 || user_id == 42777; } + + public static MessagesController.PeerColor getPeerColorForAvatar(int currentAccount, TLRPC.User user) { +// if (user != null && user.profile_color != null && user.profile_color.color >= 0 && MessagesController.getInstance(currentAccount).profilePeerColors != null) { +// return MessagesController.getInstance(currentAccount).profilePeerColors.getColor(user.profile_color.color); +// } + return null; + } + + public static int getColorId(TLRPC.User user) { + if (user == null) return 0; + Integer replace = PeerColorHelper.getColorId(user); + if (replace != null) return replace; + if (user.color != null && (user.color.flags & 1) != 0) return user.color.color; + return (int) (user.id % 7); + } + + public static long getEmojiId(TLRPC.User user) { + Long replace = PeerColorHelper.getEmojiId(user); + if (replace != null) return replace; + if (user != null && user.color != null && (user.color.flags & 2) != 0) return user.color.background_emoji_id; + return 0; + } + + public static int getProfileColorId(TLRPC.User user) { + if (user == null) return 0; + Integer replace = PeerColorHelper.getProfileColorId(user); + if (replace != null) return replace; + if (user.profile_color != null && (user.profile_color.flags & 1) != 0) return user.profile_color.color; + return -1; + } + + public static long getProfileEmojiId(TLRPC.User user) { + Long replace = PeerColorHelper.getProfileEmojiId(user); + if (replace != null) return replace; + if (user != null && user.profile_color != null && (user.profile_color.flags & 2) != 0) return user.profile_color.background_emoji_id; + return 0; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index 001798c0d4..5dc4868b3c 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; @@ -109,11 +111,13 @@ public void serializeToStream(AbstractSerializedData stream) { public static class MediaEntity { - public static final int TYPE_STICKER = 0; - public static final int TYPE_TEXT = 1; - public static final int TYPE_PHOTO = 2; - public static final int TYPE_LOCATION = 3; + public static final byte TYPE_STICKER = 0; + public static final byte TYPE_TEXT = 1; + public static final byte TYPE_PHOTO = 2; + public static final byte TYPE_LOCATION = 3; public static final byte TYPE_REACTION = 4; + public static final byte TYPE_ROUND = 5; + public static final byte TYPE_MESSAGE = 6; public byte type; public byte subType; @@ -134,7 +138,9 @@ public static class MediaEntity { 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; @@ -152,62 +158,72 @@ public static class MediaEntity { public View view; public Canvas canvas; public AnimatedFileDrawable animatedFileDrawable; + public boolean looped; public Canvas roundRadiusCanvas; + public boolean firstSeek; public TL_stories.MediaArea mediaArea; public TLRPC.MessageMedia mediaGeo; public float density; + public long roundOffset; + public long roundLeft; + public long roundRight; + public long roundDuration; + public int W, H; public ReactionsLayoutInBubble.VisibleReaction visibleReaction; 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; } @@ -215,7 +231,16 @@ public MediaEntity(AbstractSerializedData data, boolean full) { } } 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(exception); + roundLeft = data.readInt64(exception); + roundRight = data.readInt64(exception); + roundDuration = data.readInt64(exception); + } + if (type == TYPE_PHOTO) { + segmentedPath = data.readString(exception); } } @@ -273,6 +298,15 @@ public void serializeTo(AbstractSerializedData data, boolean full) { if (type == TYPE_REACTION) { mediaArea.serializeToStream(data); } + if (type == TYPE_ROUND) { + data.writeInt64(roundOffset); + data.writeInt64(roundLeft); + data.writeInt64(roundRight); + data.writeInt64(roundDuration); + } + if (type == TYPE_PHOTO) { + data.writeString(segmentedPath); + } } public MediaEntity copy() { @@ -320,6 +354,10 @@ public MediaEntity copy() { entity.W = W; entity.H = H; entity.visibleReaction = visibleReaction; + entity.roundOffset = roundOffset; + entity.roundDuration = roundDuration; + entity.roundLeft = roundLeft; + entity.roundRight = roundRight; return entity; } } @@ -428,14 +466,7 @@ public String getString() { } 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) { @@ -558,11 +589,7 @@ public boolean parseString(String string) { } } 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/camera/CameraView.java b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java index e6bcf8e5be..4f80e194c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/camera/CameraView.java @@ -66,6 +66,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.Utilities; @@ -680,6 +681,10 @@ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int hei } } + protected boolean square() { + return false; + } + private void updateCameraInfoSize(int i) { ArrayList cameraInfos = CameraController.getInstance().getCameras(); if (cameraInfos == null) { @@ -709,7 +714,11 @@ private void updateCameraInfoSize(int i) { int photoMaxWidth; int photoMaxHeight; - if (initialFrontface) { + if (square()) { + aspectRatio = new Size(1, 1); + photoMaxWidth = wantedWidth = 720; + photoMaxHeight = wantedHeight = 720; + } else if (initialFrontface) { aspectRatio = new Size(16, 9); photoMaxWidth = wantedWidth = 1280; photoMaxHeight = wantedHeight = 720; @@ -1965,6 +1974,10 @@ private void createCamera(final SurfaceTexture surfaceTexture, int i) { }); } + protected void receivedAmplitude(double amplitude) { + + } + private class VideoRecorder implements Runnable { @@ -2081,7 +2094,17 @@ public void run() { ByteBuffer byteBuffer = buffer.buffer[a]; byteBuffer.rewind(); readResult = audioRecorder.read(byteBuffer, 2048); - + if (readResult > 0 && a % 2 == 0) { + byteBuffer.limit(readResult); + double s = 0; + for (int i = 0; i < readResult / 2; i++) { + short p = byteBuffer.getShort(); + s += p * p; + } + double amplitude = Math.sqrt(s / readResult / 2); + AndroidUtilities.runOnUIThread(() -> receivedAmplitude(amplitude)); + byteBuffer.position(0); + } if (readResult <= 0) { buffer.results = a; if (!running) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java index 931f4281d7..63eb63d16e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/AudioRecoder.java @@ -1,16 +1,12 @@ package org.telegram.messenger.video; import android.media.MediaCodec; -import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Build; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.FileLog; import org.telegram.messenger.MediaController; import org.telegram.messenger.video.audio_input.AudioInput; -import org.telegram.messenger.video.audio_input.GeneralAudioInput; import java.io.IOException; import java.nio.ByteBuffer; @@ -60,12 +56,12 @@ public AudioRecoder(ArrayList audioInputs, long totalDurationUs) thr } } - encoder = MediaCodec.createEncoderByType(MediaController.AUIDO_MIME_TYPE); - format = MediaFormat.createAudioFormat(MediaController.AUIDO_MIME_TYPE, + encoder = MediaCodec.createEncoderByType(MediaController.AUDIO_MIME_TYPE); + format = MediaFormat.createAudioFormat(MediaController.AUDIO_MIME_TYPE, sampleRate, channelCount ); - format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024); + format.setInteger(MediaFormat.KEY_BIT_RATE, DEFAULT_BIT_RATE); encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); encoder.start(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index f6e5495f2f..d8b614a008 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 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, 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 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, 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; @@ -307,8 +306,8 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, } if (!decoderDone) { - outputSurface.drawImage(); long presentationTime = (long) (framesCount / 30.0f * 1000L * 1000L * 1000L); + outputSurface.drawImage(presentationTime); inputSurface.setPresentationTime(presentationTime); inputSurface.swapBuffers(); framesCount++; @@ -493,7 +492,7 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, 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; @@ -532,7 +531,7 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, mediaMuxer = new MP4Builder().createMovie(movie, isSecret, outputMimeType.equals("video/hevc")); if (audioIndex >= 0) { MediaFormat audioFormat = extractor.getTrackFormat(audioIndex); - copyAudioBuffer = convertVideoParams.soundInfos.isEmpty() && audioFormat.getString(MediaFormat.KEY_MIME).equals(MediaController.AUIDO_MIME_TYPE) || audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/mpeg"); + copyAudioBuffer = convertVideoParams.soundInfos.isEmpty() && audioFormat.getString(MediaFormat.KEY_MIME).equals(MediaController.AUDIO_MIME_TYPE) || audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/mpeg"); if (audioFormat.getString(MediaFormat.KEY_MIME).equals("audio/unknown")) { audioIndex = -1; @@ -830,7 +829,7 @@ private boolean convertVideoInternal(ConvertVideoParams convertVideoParams, FileLog.e(e); } if (!errorWait) { - outputSurface.drawImage(); + outputSurface.drawImage(info.presentationTimeUs * 1000); inputSurface.setPresentationTime(info.presentationTimeUs * 1000); inputSurface.swapBuffers(); } @@ -1333,6 +1332,9 @@ public static class ConvertVideoParams { 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 static class ConvertVideoParams { 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 static ConvertVideoParams of(String videoPath, File cacheFile, 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 static ConvertVideoParams of(String videoPath, File cacheFile, 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 6a9c203c31..6793076ba3 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); @@ -148,8 +148,8 @@ public void awaitNewImage() { mSurfaceTexture.updateTexImage(); } - public void drawImage() { - mTextureRender.drawFrame(mSurfaceTexture); + public void drawImage(long time) { + mTextureRender.drawFrame(mSurfaceTexture, time); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 4989e14200..fcd99b7175 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.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.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; @@ -62,6 +64,7 @@ import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.BlurringShader; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextEffects; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; @@ -69,6 +72,7 @@ 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; @@ -88,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 = { @@ -108,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; @@ -117,6 +120,7 @@ public class TextureRenderer { private int originalHeight; private int transformedWidth; private int transformedHeight; + private Drawable backgroundDrawable; private BlurringShader blur; @@ -143,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" + @@ -152,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" + @@ -160,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" + @@ -180,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 @@ -206,6 +263,17 @@ 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(); + private final RectF roundDst = new RectF(); + private Path roundClipPath; + private int imageOrientation; private boolean blendEnabled; @@ -237,10 +305,9 @@ public TextureRenderer( Integer gradientTopColor, Integer gradientBottomColor, StoryEntry.HDRInfo hdrInfo, - ArrayList parts + MediaCodecVideoConvertor.ConvertVideoParams params ) { isPhoto = photo; - this.parts = parts; float[] texData = { 0.f, 0.f, @@ -278,6 +345,9 @@ public 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; @@ -285,21 +355,12 @@ public 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, @@ -318,7 +379,18 @@ public 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; @@ -448,35 +520,53 @@ public 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; - } - GLES20.glUseProgram(mProgram[NUM_GRADIENT_SHADER]); + 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.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.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); + 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); + } } - public void drawFrame(SurfaceTexture st) { + public void drawFrame(SurfaceTexture st, long time) { boolean blurred = false; if (isPhoto) { - drawGradient(); + drawBackground(); } else { st.getTransformMatrix(mSTMatrix); if (BuildVars.LOGS_ENABLED && firstFrame) { @@ -523,16 +613,26 @@ public void drawFrame(SurfaceTexture st) { 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); @@ -583,7 +683,7 @@ public void drawFrame(SurfaceTexture st) { 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); @@ -592,30 +692,24 @@ public void drawFrame(SurfaceTexture st) { 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++) { - drawEntity(mediaEntities.get(a), mediaEntities.get(a).color); + drawEntity(mediaEntities.get(a), mediaEntities.get(a).color, time); } } GLES20.glFinish(); } - private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { + private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor, long time) { if (entity.ptr != 0) { if (entity.bitmap == null || entity.W <= 0 || entity.H <= 0) { return; @@ -631,26 +725,102 @@ private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); } else if (entity.animatedFileDrawable != null) { int lastFrame = (int) entity.currentFrame; - entity.currentFrame += entity.framesPerDraw; - int currentFrame = (int) entity.currentFrame; - while (lastFrame != currentFrame) { - entity.animatedFileDrawable.getNextFrame(); - currentFrame--; + float scale = 1f; + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + long vstart, vend; + if (isPhoto) { + vstart = 0; + vend = entity.roundDuration; + } else { + vstart = entity.roundOffset; + vend = entity.roundOffset + (long) (entity.roundRight - entity.roundLeft); + } + final long ms = time / 1_000_000L; + if (ms < vstart) { + scale = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(Utilities.clamp(1f - (vstart - ms) / 400f, 1, 0)); + } else if (ms > vend) { + scale = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(Utilities.clamp(1f - (ms - vend) / 400f, 1, 0)); + } + + if (scale > 0) { + long roundMs; + if (isPhoto) { + roundMs = Utilities.clamp(ms, entity.roundDuration, 0); + } else { + roundMs = Utilities.clamp(ms - entity.roundOffset + entity.roundLeft, entity.roundDuration, 0); + } + while (!entity.looped && entity.animatedFileDrawable.getProgressMs() < Math.min(roundMs, entity.animatedFileDrawable.getDurationMs())) { + int wasProgressMs = entity.animatedFileDrawable.getProgressMs(); + entity.animatedFileDrawable.getNextFrame(false); + if (entity.animatedFileDrawable.getProgressMs() <= wasProgressMs && !(entity.animatedFileDrawable.getProgressMs() == 0 && wasProgressMs == 0)) { + entity.looped = true; + break; + } + } + } + } else { + entity.currentFrame += entity.framesPerDraw; + int currentFrame = (int) entity.currentFrame; + while (lastFrame != currentFrame) { + entity.animatedFileDrawable.getNextFrame(true); + currentFrame--; + } } Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); if (frameBitmap != null) { - if (stickerCanvas == null && stickerBitmap != null) { - stickerCanvas = new Canvas(stickerBitmap); - if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { - stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + Bitmap endBitmap; + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + if (roundBitmap == null) { + final int side = Math.min(frameBitmap.getWidth(), frameBitmap.getHeight()); + roundBitmap = Bitmap.createBitmap(side, side, Bitmap.Config.ARGB_8888); + roundCanvas = new Canvas(roundBitmap); + } + if (roundBitmap != null) { + roundBitmap.eraseColor(Color.TRANSPARENT); + roundCanvas.save(); + if (roundClipPath == null) { + roundClipPath = new Path(); + } + roundClipPath.rewind(); + roundClipPath.addCircle(roundBitmap.getWidth() / 2f, roundBitmap.getHeight() / 2f, roundBitmap.getWidth() / 2f * scale, Path.Direction.CW); + roundCanvas.clipPath(roundClipPath); + if (frameBitmap.getWidth() >= frameBitmap.getHeight()) { + roundSrc.set( + (frameBitmap.getWidth() - frameBitmap.getHeight()) / 2, + 0, + frameBitmap.getWidth() - (frameBitmap.getWidth() - frameBitmap.getHeight()) / 2, + frameBitmap.getHeight() + ); + } else { + roundSrc.set( + 0, + (frameBitmap.getHeight() - frameBitmap.getWidth()) / 2, + frameBitmap.getWidth(), + frameBitmap.getHeight() - (frameBitmap.getHeight() - frameBitmap.getWidth()) / 2 + ); + } + roundDst.set(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight()); + roundCanvas.drawBitmap(frameBitmap, roundSrc, roundDst, null); + roundCanvas.restore(); + } + endBitmap = roundBitmap; + } else { + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { + stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + } + } + if (stickerBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + applyRoundRadius(entity, stickerBitmap, (entity.subType & 8) != 0 ? textColor : 0); } + endBitmap = stickerBitmap; } - if (stickerBitmap != null) { - stickerBitmap.eraseColor(Color.TRANSPARENT); - stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); - applyRoundRadius(entity, stickerBitmap, (entity.subType & 8) != 0 ? textColor : 0); + if (endBitmap != null) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, endBitmap, 0); drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); } } @@ -670,7 +840,7 @@ private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { if (entity1 == null) { continue; } - drawEntity(entity1, entity.color); + drawEntity(entity1, entity.color, time); } } } @@ -774,9 +944,9 @@ private void drawTexture(boolean bind, int texture, float x, float y, float w, f } } 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); } @@ -791,22 +961,27 @@ public void setBreakStrategy(EditTextOutline editText) { @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"); @@ -821,6 +996,23 @@ public void surfaceCreated() { 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)) { @@ -897,7 +1089,7 @@ public void surfaceCreated() { } } } - 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) { @@ -925,24 +1117,41 @@ public void surfaceCreated() { 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); @@ -962,7 +1171,7 @@ public void surfaceCreated() { bitmap = newBitmap; } - if (a == 0 && imagePath != null) { + if (a == imagePathIndex) { imageWidth = bitmap.getWidth(); imageHeight = bitmap.getHeight(); } @@ -979,56 +1188,7 @@ public void surfaceCreated() { 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]; @@ -1040,7 +1200,11 @@ public void surfaceCreated() { GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); for (int a = 0, N = mediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(a); - if (entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER || entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO) { + if ( + entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER || + entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO || + entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND + ) { initStickerEntity(entity); } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT) { EditTextOutline editText = new EditTextOutline(ApplicationLoader.applicationContext); @@ -1239,22 +1403,30 @@ private void initStickerEntity(VideoEditedInfo.MediaEntity entity) { entity.ptr = RLottieDrawable.create(entity.text, null, entity.W, entity.H, entity.metadata, false, null, false, 0); entity.framesPerDraw = entity.metadata[1] / videoFps; } else if ((entity.subType & 4) != 0) { + entity.looped = false; entity.animatedFileDrawable = new AnimatedFileDrawable(new File(entity.text), true, 0, 0, null, null, null, 0, UserConfig.selectedAccount, true, 512, 512, null); entity.framesPerDraw = entity.animatedFileDrawable.getFps() / videoFps; - entity.currentFrame = 0; - entity.animatedFileDrawable.getNextFrame(); + entity.currentFrame = 1; + entity.animatedFileDrawable.getNextFrame(true); + if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + entity.firstSeek = true; + } } else { + 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); @@ -1370,8 +1542,14 @@ public void release() { } 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; @@ -1380,7 +1558,7 @@ public void changeFragmentShader(String fragmentExternalShader, String fragmentS } } 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 1546bedd8b..748129f1a6 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.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; @@ -241,6 +241,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; @@ -1122,6 +1123,10 @@ public void switchCamera() { 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; @@ -1605,6 +1610,10 @@ private void startRatingActivity() { } } + public void sendCallRating(int rating) { + VoIPHelper.sendCallRating(privateCall.id, privateCall.access_hash, currentAccount, rating); + } + public byte[] getEncryptionKey() { return authKey; } @@ -2718,24 +2727,54 @@ public boolean isMicMute() { } 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()) { - BottomBuilder builder = new BottomBuilder(context); - builder.addTitle(LocaleController.getString("VoipOutputDevices", R.string.VoipOutputDevices), true); - builder.addItems(new String[]{ - 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}, (which, dialog, __) -> { - if (getSharedInstance() == null) { - return Unit.INSTANCE; - } - setAudioOutput(which); - return Unit.INSTANCE; - }); + 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.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; + } + setAudioOutput(which); + }); 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); @@ -2760,7 +2799,13 @@ public void toggleSpeakerphoneOrShowRouteSheet(Context context, boolean fromOver } else { am.setBluetoothScoOn(!am.isBluetoothScoOn()); } - updateOutputGainControlState(); + vam.isBluetoothAndSpeakerOnAsync((isBluetoothOn, isSpeakerOn) -> { + updateOutputGainControlState(); + for (StateListener l : stateListeners) { + l.onAudioSettingsChanged(); + } + }); + return; } else { speakerphoneStateToSet = !speakerphoneStateToSet; } @@ -3486,6 +3531,10 @@ public static String getStringFromFile(String filePath) throws Exception { return ret; } + public boolean hasRate() { + return needRateCall || forceRating; + } + private void onTgVoipStop(Instance.FinalState finalState) { if (user == null) { return; @@ -3497,11 +3546,6 @@ private void onTgVoipStop(Instance.FinalState finalState) { 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(); @@ -3764,6 +3808,10 @@ private void configureDeviceForCall() { } 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; @@ -3798,9 +3846,12 @@ private void fetchBluetoothDeviceName() { } } + 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; } @@ -3812,6 +3863,7 @@ public void onSensorChanged(SensorEvent event) { } boolean newIsNear = event.values[0] < Math.min(event.sensor.getMaximumRange(), 3); checkIsNear(newIsNear); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.nearEarEvent, newIsNear); } } @@ -4264,7 +4316,10 @@ public void onConnectionStateChanged(int newState, boolean inTransition) { if (groupCall == null && !wasEstablished) { wasEstablished = true; if (!isProximityNear && !privateCall.video) { - VibrateUtil.vibrate(100); + try { + LaunchActivity.getLastFragment().getFragmentView().performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + } } AndroidUtilities.runOnUIThread(new Runnable() { @Override @@ -4282,7 +4337,7 @@ public void run() { } } } - if (newState == STATE_RECONNECTING) { + if (newState == STATE_RECONNECTING && !isCallEnded) { Utilities.globalQueue.postRunnable(() -> { if (spPlayId != 0) { soundPool.stop(spPlayId); @@ -4330,6 +4385,7 @@ private void callEnded() { 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 e96edb73ed..b2b93bea17 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 android.media.AudioManager; + +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Utilities; @@ -47,6 +49,15 @@ public boolean isSpeakerphoneOn() { 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/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index c9cc6405f0..c8d11a22c8 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -11,12 +11,14 @@ import android.graphics.Bitmap; import android.graphics.Path; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.text.TextUtils; import org.osmdroid.util.TileSystemWebMercator; import androidx.annotation.Nullable; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -80,7 +82,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 166; + public static final int LAYER = 170; public static class TL_stats_megagroupStats extends TLObject { public static final int constructor = 0xef7ff916; @@ -5508,30 +5510,65 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_messageInteractionCounters extends TLObject { - public static final int constructor = 0xad4fc9bd; + public static abstract class PostInteractionCounters extends TLObject { - public int msg_id; + public static PostInteractionCounters TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PostInteractionCounters result = null; + switch (constructor) { + case TL_postInteractionCountersStory.constructor: + result = new TL_postInteractionCountersStory(); + break; + case TL_postInteractionCountersMessage.constructor: + result = new TL_postInteractionCountersMessage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PostInteractionCounters", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_postInteractionCountersStory extends PostInteractionCounters { + public final static int constructor = 0x8a480e27; + + public int story_id; public int views; public int forwards; + public int reactions; - public static TL_messageInteractionCounters TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_messageInteractionCounters.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_messageInteractionCounters", constructor)); - } else { - return null; - } - } - TL_messageInteractionCounters result = new TL_messageInteractionCounters(); - result.readParams(stream, exception); - return result; + public void readParams(AbstractSerializedData stream, boolean exception) { + story_id = stream.readInt32(exception); + views = stream.readInt32(exception); + forwards = stream.readInt32(exception); + reactions = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(story_id); + stream.writeInt32(views); + stream.writeInt32(forwards); + stream.writeInt32(reactions); } + } + + public static class TL_postInteractionCountersMessage extends PostInteractionCounters { + public static final int constructor = 0xe7058e7f; + + public int msg_id; + public int views; + public int forwards; + public int reactions; public void readParams(AbstractSerializedData stream, boolean exception) { msg_id = stream.readInt32(exception); views = stream.readInt32(exception); forwards = stream.readInt32(exception); + reactions = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -5539,6 +5576,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(msg_id); stream.writeInt32(views); stream.writeInt32(forwards); + stream.writeInt32(reactions); } } @@ -8633,6 +8671,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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); } @@ -8648,6 +8689,9 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -12285,7 +12329,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } } - + public static class WebPageAttribute extends TLObject { public int flags; @@ -13067,8 +13111,10 @@ public static abstract class ChatFull extends TLObject { public boolean participants_hidden; public boolean translations_disabled; public boolean stories_pinned_available; + public boolean view_forum_as_messages; public ChatReactions available_reactions; public TL_stories.PeerStories stories; + public WallPaper wallpaper; public long inviterId; //custom public int invitesCount; //custom @@ -13079,9 +13125,12 @@ public static ChatFull TLdeserialize(AbstractSerializedData stream, int construc 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; @@ -15530,7 +15579,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_channelFull extends ChatFull { - public static final int constructor = 0x723027bd; + public static final int constructor = 0xf2bcb6f; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -15548,6 +15597,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { participants_hidden = (flags2 & 4) != 0; translations_disabled = (flags2 & 8) != 0; stories_pinned_available = (flags2 & 32) != 0; + view_forum_as_messages = (flags2 & 64) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -15672,6 +15722,9 @@ public void readParams(AbstractSerializedData stream, boolean 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) { @@ -15690,6 +15743,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); flags2 = stories_pinned_available ? (flags2 | 32) : (flags2 &~ 32); + flags2 = view_forum_as_messages ? (flags2 | 64) : (flags2 &~ 64); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -15796,11 +15850,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 16) != 0) { stories.serializeToStream(stream); } + if ((flags2 & 128) != 0) { + wallpaper.serializeToStream(stream); + } } } - public static class TL_channelFull_layer162 extends TL_channelFull { - public static final int constructor = 0xf2355507; + public static class TL_channelFull_layer167 extends TL_channelFull { + public static final int constructor = 0x723027bd; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -15817,6 +15874,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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) { @@ -15938,6 +15997,9 @@ public void readParams(AbstractSerializedData stream, boolean 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); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -15955,6 +16017,8 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -16058,11 +16122,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 1073741824) != 0) { available_reactions.serializeToStream(stream); } + if ((flags2 & 16) != 0) { + stories.serializeToStream(stream); + } } } - public static class TL_channelFull_layer144 extends ChatFull { - public static final int constructor = 0xea68a619; + public static class TL_channelFull_layer162 extends TL_channelFull { + public static final int constructor = 0xf2355507; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -16076,6 +16143,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -16195,17 +16265,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { default_send_as = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 1073741824) != 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++) { - available_reactions_legacy.add(stream.readString(exception)); - } + available_reactions = ChatReactions.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -16221,6 +16281,9 @@ public void serializeToStream(AbstractSerializedData stream) { 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); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -16322,18 +16385,13 @@ public void serializeToStream(AbstractSerializedData stream) { default_send_as.serializeToStream(stream); } if ((flags & 1073741824) != 0) { - stream.writeInt32(0x1cb5c415); - count = available_reactions_legacy.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - stream.writeString(available_reactions_legacy.get(a)); - } + available_reactions.serializeToStream(stream); } } } - public static class TL_channelFull_layer139 extends ChatFull { - public static final int constructor = 0xe13c3d20; + public static class TL_channelFull_layer144 extends ChatFull { + public static final int constructor = 0xea68a619; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -16345,6 +16403,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -16489,6 +16549,8 @@ public void serializeToStream(AbstractSerializedData stream) { 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); + stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); if ((flags & 1) != 0) { @@ -16599,9 +16661,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_channelFull_layer131 extends TL_channelFull { - public static final int constructor = 0x548c3f93; - + public static class TL_channelFull_layer139 extends ChatFull { + public static final int constructor = 0xe13c3d20; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -16636,7 +16697,7 @@ public void readParams(AbstractSerializedData stream, boolean 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 = (TL_chatInviteExported) ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -16709,6 +16770,41 @@ public void readParams(AbstractSerializedData stream, boolean 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) { + 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++) { + available_reactions_legacy.add(stream.readString(exception)); + } + } } public void serializeToStream(AbstractSerializedData stream) { @@ -16804,11 +16900,36 @@ public void serializeToStream(AbstractSerializedData stream) { 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) { + stream.writeInt32(0x1cb5c415); + count = available_reactions_legacy.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(available_reactions_legacy.get(a)); + } + } } } - public static class TL_channelFull_layer122 extends TL_channelFull { - public static final int constructor = 0xef3a6acd; + public static class TL_channelFull_layer131 extends TL_channelFull { + public static final int constructor = 0x548c3f93; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -16821,7 +16942,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_scheduled = (flags & 524288) != 0; can_view_stats = (flags & 1048576) != 0; blocked = (flags & 4194304) != 0; - id = stream.readInt32(exception); + id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { participants_count = stream.readInt32(exception); @@ -16843,9 +16964,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { unread_count = stream.readInt32(exception); chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); - ExportedChatInvite invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); - if (invite instanceof TL_chatInviteExported) { - exported_invite = (TL_chatInviteExported) invite; + if ((flags & 8388608) != 0) { + exported_invite = (TL_chatInviteExported) ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -16863,7 +16983,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { bot_info.add(object); } if ((flags & 16) != 0) { - migrated_from_chat_id = stream.readInt32(exception); + migrated_from_chat_id = stream.readInt64(exception); } if ((flags & 16) != 0) { migrated_from_max_id = stream.readInt32(exception); @@ -16881,7 +17001,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { folder_id = stream.readInt32(exception); } if ((flags & 16384) != 0) { - linked_chat_id = stream.readInt32(exception); + linked_chat_id = stream.readInt64(exception); } if ((flags & 32768) != 0) { location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -16899,6 +17019,25 @@ public void readParams(AbstractSerializedData stream, boolean 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); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -16912,7 +17051,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = can_view_stats ? (flags | 1048576) : (flags &~ 1048576); flags = blocked ? (flags | 4194304) : (flags &~ 4194304); stream.writeInt32(flags); - stream.writeInt32((int) id); + stream.writeInt64(id); stream.writeString(about); if ((flags & 1) != 0) { stream.writeInt32(participants_count); @@ -16934,10 +17073,8 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(unread_count); chat_photo.serializeToStream(stream); notify_settings.serializeToStream(stream); - if (exported_invite != null) { + if ((flags & 8388608) != 0) { exported_invite.serializeToStream(stream); - } else { - new TLRPC.TL_chatInviteEmpty_layer122().serializeToStream(stream); } stream.writeInt32(0x1cb5c415); int count = bot_info.size(); @@ -16946,7 +17083,7 @@ public void serializeToStream(AbstractSerializedData stream) { bot_info.get(a).serializeToStream(stream); } if ((flags & 16) != 0) { - stream.writeInt32((int) migrated_from_chat_id); + stream.writeInt64(migrated_from_chat_id); } if ((flags & 16) != 0) { stream.writeInt32(migrated_from_max_id); @@ -16964,7 +17101,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(folder_id); } if ((flags & 16384) != 0) { - stream.writeInt32((int) linked_chat_id); + stream.writeInt64(linked_chat_id); } if ((flags & 32768) != 0) { location.serializeToStream(stream); @@ -16982,11 +17119,25 @@ public void serializeToStream(AbstractSerializedData stream) { 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); + } } } - public static class TL_channelFull_layer121 extends TL_channelFull { - public static final int constructor = 0xf0e6672a; + public static class TL_channelFull_layer122 extends TL_channelFull { + public static final int constructor = 0xef3a6acd; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -17074,6 +17225,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { stats_dc = stream.readInt32(exception); } pts = stream.readInt32(exception); + if ((flags & 2097152) != 0) { + call = TL_inputGroupCall.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -17109,7 +17263,11 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(unread_count); chat_photo.serializeToStream(stream); notify_settings.serializeToStream(stream); - exported_invite.serializeToStream(stream); + if (exported_invite != null) { + exported_invite.serializeToStream(stream); + } else { + new TLRPC.TL_chatInviteEmpty_layer122().serializeToStream(stream); + } stream.writeInt32(0x1cb5c415); int count = bot_info.size(); stream.writeInt32(count); @@ -17150,11 +17308,14 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(stats_dc); } stream.writeInt32(pts); + if ((flags & 2097152) != 0) { + call.serializeToStream(stream); + } } } - public static class TL_channelFull_layer103 extends TL_channelFull { - public static final int constructor = 0x10916653; + public static class TL_channelFull_layer121 extends TL_channelFull { + public static final int constructor = 0xf0e6672a; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -17163,8 +17324,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_set_username = (flags & 64) != 0; can_set_stickers = (flags & 128) != 0; hidden_prehistory = (flags & 1024) != 0; - can_view_stats = (flags & 4096) != 0; can_set_location = (flags & 65536) != 0; + has_scheduled = (flags & 524288) != 0; + can_view_stats = (flags & 1048576) != 0; + blocked = (flags & 4194304) != 0; id = stream.readInt32(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -17230,6 +17393,15 @@ public void readParams(AbstractSerializedData stream, boolean 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); } @@ -17239,7 +17411,164 @@ public void serializeToStream(AbstractSerializedData stream) { 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_view_stats ? (flags | 4096) : (flags &~ 4096); + 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); + stream.writeInt32((int) 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); + 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.writeInt32((int) 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.writeInt32((int) 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); + } + } + + public static class TL_channelFull_layer103 extends TL_channelFull { + public static final int constructor = 0x10916653; + + + 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_view_stats = (flags & 4096) != 0; + can_set_location = (flags & 65536) != 0; + id = stream.readInt32(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); + ExportedChatInvite invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + if (invite instanceof TL_chatInviteExported) { + exported_invite = (TL_chatInviteExported) invite; + } + 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.readInt32(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.readInt32(exception); + } + if ((flags & 32768) != 0) { + location = ChannelLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + pts = stream.readInt32(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_view_stats ? (flags | 4096) : (flags &~ 4096); flags = can_set_location ? (flags | 65536) : (flags &~ 65536); stream.writeInt32(flags); stream.writeInt32((int) id); @@ -19095,9 +19424,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stats_messageStats extends TLObject { - public static final int constructor = 0x8999f295; + public final static int constructor = 0x7fe91c14; public StatsGraph views_graph; + public StatsGraph reactions_by_emotion_graph; public static TL_stats_messageStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_stats_messageStats.constructor != constructor) { @@ -19114,11 +19444,13 @@ public static TL_stats_messageStats TLdeserialize(AbstractSerializedData stream, public void readParams(AbstractSerializedData stream, boolean exception) { views_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); views_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); } } @@ -19947,7 +20279,10 @@ public static KeyboardButton TLdeserialize(AbstractSerializedData stream, int co 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; } @@ -23784,8 +24119,8 @@ public static abstract class User extends TLObject { public EmojiStatus emoji_status; public ArrayList usernames = new ArrayList<>(); public int stories_max_id; - public int color; - public long background_emoji_id; + public TL_peerColor color; + public TL_peerColor profile_color; public boolean verifiedExtended() { return verified || (ArrayUtil.contains(NekoXConfig.developers, id) && NekoXConfig.isDeveloper()); @@ -23797,8 +24132,8 @@ public static User TLdeserialize(AbstractSerializedData stream, int constructor, case TL_user.constructor: result = new TL_user(); break; - case TL_user_layer165_2.constructor: - result = new TL_user_layer165_2(); + case TL_user_layer166.constructor: + result = new TL_user_layer166(); break; case 0xcab35e18: result = new TL_userContact_old2(); @@ -23943,7 +24278,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_user extends User { - public static final int constructor = 0xeb602f25; + public static final int constructor = 0x215c4438; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -24045,11 +24380,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - if ((flags2 & 128) != 0) { - color = stream.readInt32(exception); + if ((flags2 & 256) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } - if ((flags2 & 64) != 0) { - background_emoji_id = stream.readInt64(exception); + if ((flags2 & 512) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -24135,17 +24470,23 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 32) != 0) { stream.writeInt32(stories_max_id); } - if ((flags2 & 128) != 0) { - stream.writeInt32(color); + if ((flags2 & 256) != 0) { + if (color == null) { + color = new TL_peerColor(); + } + color.serializeToStream(stream); } - if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); + if ((flags2 & 512) != 0) { + if (profile_color == null) { + profile_color = new TL_peerColor(); + } + profile_color.serializeToStream(stream); } } } - public static class TL_user_layer165_2 extends User { - public static final int constructor = 0x6fdee0df; + public static class TL_user_layer166 extends TL_user { + public static final int constructor = 0xeb602f25; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -24247,9 +24588,15 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - color = stream.readInt32(exception); + if ((flags2 & 128) != 0) { + color = new TL_peerColor(); + color.color = stream.readInt32(exception); + } if ((flags2 & 64) != 0) { - background_emoji_id = stream.readInt64(exception); + if (color == null) { + color = new TL_peerColor(); + } + color.background_emoji_id = stream.readInt64(exception); } } @@ -24335,9 +24682,11 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 32) != 0) { stream.writeInt32(stories_max_id); } - stream.writeInt32(color); + if ((flags2 & 128) != 0) { + stream.writeInt32(color.color); + } if ((flags2 & 64) != 0) { - stream.writeInt64(background_emoji_id); + stream.writeInt64(color.background_emoji_id); } } } @@ -24445,7 +24794,6 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } catch (Throwable e) { FileLog.e(e); } - color = (int) (id % 7); } public void serializeToStream(AbstractSerializedData stream) { @@ -26243,6 +26591,9 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con case 0x332ba9ed: result = new TL_messageActionGiveawayLaunch(); break; + case 0x2a9fadc5: + result = new TL_messageActionGiveawayResults(); + break; case 0xea3948e9: result = new TL_messageActionChannelMigrateFrom(); break; @@ -26283,14 +26634,20 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con result = new TL_messageActionCreatedBroadcastList(); break; case 0xbc44a927: + result = new TL_messageActionSetChatWallPaper_layer166(); + break; + case 0x5060a3f4: result = new TL_messageActionSetChatWallPaper(); break; case 0x55555550: 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; @@ -26387,7 +26744,10 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con 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; } @@ -26991,7 +27351,7 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_messageActionSetChatWallPaper extends MessageAction { + public static class TL_messageActionSetChatWallPaper_layer166 extends TL_messageActionSetChatWallPaper { public static final int constructor = 0xbc44a927; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -27004,6 +27364,28 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_messageActionSetChatWallPaper extends MessageAction { + public static final int constructor = 0x5060a3f4; + + public boolean same; + public boolean for_both; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + same = (flags & 1) != 0; + for_both = (flags & 2) != 0; + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = same ? (flags | 1) : (flags &~ 1); + flags = for_both ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + wallpaper.serializeToStream(stream); + } + } + public static class TL_messageActionUserJoined extends MessageAction { public static final int constructor = 0x55555550; @@ -29131,6 +29513,7 @@ public static abstract class MessageReplyHeader extends TLObject { public MessageMedia reply_media; public String quote_text; public ArrayList quote_entities = new ArrayList<>(); + public int quote_offset; public long user_id; public int story_id; @@ -29144,6 +29527,9 @@ public static MessageReplyHeader TLdeserialize(AbstractSerializedData stream, in case TL_messageReplyHeader.constructor: result = new TL_messageReplyHeader(); break; + case TL_messageReplyHeader_layer166.constructor: + result = new TL_messageReplyHeader_layer166(); + break; case TL_messageReplyHeader_layer165_2.constructor: result = new TL_messageReplyHeader_layer165_2(); break; @@ -29177,6 +29563,92 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messageReplyHeader extends MessageReplyHeader { + public static final int constructor = 0xafbc09db; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + reply_to_scheduled = (flags & 4) != 0; + forum_topic = (flags & 8) != 0; + quote = (flags & 512) != 0; + if ((flags & 16) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + if ((flags & 1) != 0) { + reply_to_peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + reply_from = MessageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 256) != 0) { + reply_media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + reply_to_top_id = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + quote_text = stream.readString(exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + quote_entities.add(object); + } + } + if ((flags & 1024) != 0) { + quote_offset = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = reply_to_scheduled ? (flags | 4) : (flags &~ 4); + flags = forum_topic ? (flags | 8) : (flags &~ 8); + flags = quote ? (flags | 512) : (flags &~ 512); + stream.writeInt32(flags); + if ((flags & 16) != 0) { + stream.writeInt32(reply_to_msg_id); + } + if ((flags & 1) != 0) { + reply_to_peer_id.serializeToStream(stream); + } + if ((flags & 32) != 0) { + reply_from.serializeToStream(stream); + } + if ((flags & 256) != 0) { + reply_media.serializeToStream(stream); + } + if ((flags & 2) != 0) { + stream.writeInt32(reply_to_top_id); + } + if ((flags & 64) != 0) { + stream.writeString(quote_text); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = quote_entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; ++a) { + quote_entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(quote_offset); + } + } + } + + public static class TL_messageReplyHeader_layer166 extends TL_messageReplyHeader { public static final int constructor = 0x6eebcabd; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -29661,12 +30133,16 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stats_broadcastStats extends TLObject { - public static final int constructor = 0xbdf78394; + public static int constructor = 0x396ca5fc; public TL_statsDateRangeDays period; public TL_statsAbsValueAndPrev followers; public TL_statsAbsValueAndPrev views_per_post; public TL_statsAbsValueAndPrev shares_per_post; + public TL_statsAbsValueAndPrev reactions_per_post; + public TL_statsAbsValueAndPrev views_per_story; + public TL_statsAbsValueAndPrev shares_per_story; + public TL_statsAbsValueAndPrev reactions_per_story; public TL_statsPercentValue enabled_notifications; public StatsGraph growth_graph; public StatsGraph followers_graph; @@ -29677,7 +30153,10 @@ public static class TL_stats_broadcastStats extends TLObject { public StatsGraph views_by_source_graph; public StatsGraph new_followers_by_source_graph; public StatsGraph languages_graph; - public ArrayList recent_message_interactions = new ArrayList<>(); + public StatsGraph reactions_by_emotion_graph; + public StatsGraph story_interactions_graph; + public StatsGraph story_reactions_by_emotion_graph; + public ArrayList recent_posts_interactions = new ArrayList<>(); public static TL_stats_broadcastStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_stats_broadcastStats.constructor != constructor) { @@ -29697,6 +30176,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { followers = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); views_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); shares_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_per_post = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + views_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + shares_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_per_story = TL_statsAbsValueAndPrev.TLdeserialize(stream, stream.readInt32(exception), exception); enabled_notifications = TL_statsPercentValue.TLdeserialize(stream, stream.readInt32(exception), exception); growth_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); followers_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -29707,6 +30190,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { views_by_source_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); new_followers_by_source_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); languages_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + story_interactions_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + story_reactions_by_emotion_graph = StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -29716,11 +30202,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - TL_messageInteractionCounters object = TL_messageInteractionCounters.TLdeserialize(stream, stream.readInt32(exception), exception); + PostInteractionCounters object = PostInteractionCounters.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } - recent_message_interactions.add(object); + recent_posts_interactions.add(object); } } @@ -29730,6 +30216,10 @@ public void serializeToStream(AbstractSerializedData stream) { followers.serializeToStream(stream); views_per_post.serializeToStream(stream); shares_per_post.serializeToStream(stream); + reactions_per_post.serializeToStream(stream); + views_per_story.serializeToStream(stream); + shares_per_story.serializeToStream(stream); + reactions_per_story.serializeToStream(stream); enabled_notifications.serializeToStream(stream); growth_graph.serializeToStream(stream); followers_graph.serializeToStream(stream); @@ -29740,11 +30230,14 @@ public void serializeToStream(AbstractSerializedData stream) { views_by_source_graph.serializeToStream(stream); new_followers_by_source_graph.serializeToStream(stream); languages_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); + story_interactions_graph.serializeToStream(stream); + story_reactions_by_emotion_graph.serializeToStream(stream); stream.writeInt32(0x1cb5c415); - int count = recent_message_interactions.size(); + int count = recent_posts_interactions.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { - recent_message_interactions.get(a).serializeToStream(stream); + recent_posts_interactions.get(a).serializeToStream(stream); } } } @@ -32889,6 +33382,9 @@ public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int c 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)); @@ -32909,6 +33405,15 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -33578,324 +34083,336 @@ public static abstract class Update extends TLObject { public static Update TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Update result = null; switch (constructor) { - case 0x24f40e77: + case TL_updateMessagePollVote.constructor: result = new TL_updateMessagePollVote(); break; - case 0x5a73a98c: + case TL_updateMessageExtendedMedia.constructor: result = new TL_updateMessageExtendedMedia(); break; - case 0xaca1657b: + case TL_updateMessagePoll.constructor: result = new TL_updateMessagePoll(); break; - case 0xbb9bb9a5: + case TL_updatePeerHistoryTTL.constructor: result = new TL_updatePeerHistoryTTL(); break; - case 0xf89a6a4e: + case TL_updateChat.constructor: result = new TL_updateChat(); break; - case 0xa20db0e5: + case TL_updateDeleteMessages.constructor: result = new TL_updateDeleteMessages(); break; - case 0x5bb98608: + case TL_updatePinnedChannelMessages.constructor: result = new TL_updatePinnedChannelMessages(); break; - case 0xf2ebdb4e: + case TL_updateGroupCallParticipants.constructor: result = new TL_updateGroupCallParticipants(); break; - case 0x571d2742: + case TL_updateReadFeaturedStickers.constructor: result = new TL_updateReadFeaturedStickers(); break; - case 0x1710f156: + case TL_updateEncryptedChatTyping.constructor: result = new TL_updateEncryptedChatTyping(); break; - case 0xd6b19546: + case TL_updateReadChannelDiscussionInbox.constructor: result = new TL_updateReadChannelDiscussionInbox(); break; - case 0x2f2f21bf: + case TL_updateReadHistoryOutbox.constructor: result = new TL_updateReadHistoryOutbox(); break; - case 0x62ba04d9: + case TL_updateNewChannelMessage.constructor: result = new TL_updateNewChannelMessage(); break; - case 0x1592b79d: + case TL_updateWebViewResultSent.constructor: result = new TL_updateWebViewResultSent(); break; - case 0x6e6fe51c: + case TL_updateDialogPinned.constructor: result = new TL_updateDialogPinned(); break; - case 0x6a7e7366: + case TL_updatePeerSettings.constructor: result = new TL_updatePeerSettings(); break; - case 0x5492a13: + case TL_updateUserPhone.constructor: result = new TL_updateUserPhone(); break; - case 0x4e90bfd6: + case TL_updateMessageID.constructor: result = new TL_updateMessageID(); break; - case 0xb75f99a9: + case TL_updateReadChannelOutbox.constructor: result = new TL_updateReadChannelOutbox(); break; - case 0x8c88c923: + case TL_updateChannelUserTyping.constructor: result = new TL_updateChannelUserTyping(); break; - case 0x1bf335b9: + case TL_updateStoryID.constructor: result = new TL_updateStoryID(); break; - case 0x31c24808: + case TL_updateStickerSets.constructor: result = new TL_updateStickerSets(); break; - case 0x19360dc0: + case TL_updateFolderPeers.constructor: result = new TL_updateFolderPeers(); break; - case 0x1f2b0afd: + case TL_updateNewMessage.constructor: result = new TL_updateNewMessage(); break; - case 0x39a51dfb: + case TL_updateNewScheduledMessage.constructor: result = new TL_updateNewScheduledMessage(); break; - case 0x12bcbd9a: + case TL_updateNewEncryptedMessage.constructor: result = new TL_updateNewEncryptedMessage(); break; - case 0x86fccf85: + case TL_updateMoveStickerSetToTop.constructor: result = new TL_updateMoveStickerSetToTop(); break; - case 0xe5bdf8de: + case TL_updateUserStatus.constructor: result = new TL_updateUserStatus(); break; - case 0x28373599: + case TL_updateUserEmojiStatus.constructor: result = new TL_updateUserEmojiStatus(); break; - case 0xf226ac08: + case TL_updateChannelMessageViews.constructor: result = new TL_updateChannelMessageViews(); break; - case 0xb783982: + case TL_updateGroupCallConnection.constructor: result = new TL_updateGroupCallConnection(); break; - case 0x4d712f2e: + case TL_updateBotCommands.constructor: result = new TL_updateBotCommands(); break; - case 0x871fb939: + case TL_updateGeoLiveViewed.constructor: result = new TL_updateGeoLiveViewed(); break; - case 0xbec268ef: + case TL_updateNotifySettings.constructor: result = new TL_updateNotifySettings(); break; - case 0x985d3abb: + case TL_updateChannelParticipant.constructor: result = new TL_updateChannelParticipant(); break; - case 0x695c9e7c: + case TL_updateReadChannelDiscussionOutbox.constructor: result = new TL_updateReadChannelDiscussionOutbox(); break; - case 0xe32f3d77: + case TL_updateChatParticipantDelete.constructor: result = new TL_updateChatParticipantDelete(); break; - case 0xfb4c496c: + case TL_updateReadFeaturedEmojiStickers.constructor: result = new TL_updateReadFeaturedEmojiStickers(); break; - case 0xe40370a3: + case TL_updateEditMessage.constructor: result = new TL_updateEditMessage(); break; - case 0x6f7863f4: + case TL_updateRecentReactions.constructor: result = new TL_updateRecentReactions(); break; - case 0x7f891213: + case TL_updateWebPage.constructor: result = new TL_updateWebPage(); break; - case 0xe511996d: + case TL_updateFavedStickers.constructor: result = new TL_updateFavedStickers(); break; - case 0x3dda5451: + case TL_updateChatParticipantAdd.constructor: result = new TL_updateChatParticipantAdd(); break; - case 0x83487af0: + case TL_updateChatUserTyping.constructor: result = new TL_updateChatUserTyping(); break; - case 0x564fe691: + case TL_updateLoginToken.constructor: result = new TL_updateLoginToken(); break; - case 0xb4a2e88d: + case TL_updateEncryption.constructor: result = new TL_updateEncryption(); break; - case 0x14b24500: + case TL_updateGroupCall.constructor: result = new TL_updateGroupCall(); break; - case 0x108d941f: + case TL_updateChannelTooLong.constructor: result = new TL_updateChannelTooLong(); break; - case 0xc01e857f: + case TL_updateUserTyping.constructor: result = new TL_updateUserTyping(); break; - case 0xf74e932b: + case TL_stories.TL_updateReadStories.constructor: result = new TL_stories.TL_updateReadStories(); break; - case 0xebe46819: + case TL_updateServiceNotification.constructor: result = new TL_updateServiceNotification(); break; - case 0x56022f4d: + case TL_updateLangPack.constructor: result = new TL_updateLangPack(); break; - case 0xb23fc698: + case TL_updateChannelAvailableMessages.constructor: result = new TL_updateChannelAvailableMessages(); break; - case 0xd7ca61a2: + case TL_updateChatParticipantAdmin.constructor: result = new TL_updateChatParticipantAdmin(); break; - case 0xea29055d: + case TL_updateChannelReadMessagesContents.constructor: result = new TL_updateChannelReadMessagesContents(); break; - case 0xee3b272a: + case TL_updatePrivacy.constructor: result = new TL_updatePrivacy(); break; - case 0xa229dd06: + case TL_updateConfig.constructor: result = new TL_updateConfig(); break; - case 0xe16459c3: + case TL_updateDialogUnreadMark.constructor: result = new TL_updateDialogUnreadMark(); break; - case 0x1b49ec6d: + case TL_updateDraftMessage.constructor: result = new TL_updateDraftMessage(); break; - case 0x8951abef: + case TL_updateNewAuthorization.constructor: result = new TL_updateNewAuthorization(); break; - case 0xa7848924: + case TL_updateUserName.constructor: result = new TL_updateUserName(); break; - case 0x5e1b3cb8: + case TL_updateMessageReactions.constructor: result = new TL_updateMessageReactions(); break; - case 0xab0f6b1e: + case TL_updatePhoneCall.constructor: result = new TL_updatePhoneCall(); break; - case 0x26ffde7d: + case TL_updateDialogFilter.constructor: result = new TL_updateDialogFilter(); break; - case 0xebe07752: + case TL_updatePeerBlocked.constructor: result = new TL_updatePeerBlocked(); break; - case 0xed85eab5: + case TL_updatePinnedMessages.constructor: result = new TL_updatePinnedMessages(); break; - case 0x2661bf09: + case TL_updatePhoneCallSignalingData.constructor: result = new TL_updatePhoneCallSignalingData(); break; - case 0x88617090: + case TL_updateTranscribeAudio.constructor: result = new TL_updateTranscribeAudio(); break; - case 0xfa0f3ca2: + case TL_updatePinnedDialogs.constructor: result = new TL_updatePinnedDialogs(); break; - case 0x74d8be99: + case TL_updateSavedRingtones.constructor: result = new TL_updateSavedRingtones(); break; - case 0x2c084dc1: + case TL_stories.TL_updateStoriesStealthMode.constructor: result = new TL_stories.TL_updateStoriesStealthMode(); break; - case 0x84cd5a: + case TL_updateTranscribedAudio.constructor: result = new TL_updateTranscribedAudio(); break; - case 0xb4afcfb0: + case TL_updatePeerLocated.constructor: result = new TL_updatePeerLocated(); break; - case 0x9a422c20: + case TL_updateRecentStickers.constructor: result = new TL_updateRecentStickers(); break; - case 0x9c974fdf: + case TL_updateReadHistoryInbox.constructor: result = new TL_updateReadHistoryInbox(); break; - case 0xa5d72105: + case TL_updateDialogFilterOrder.constructor: result = new TL_updateDialogFilterOrder(); break; - case 0x9375341e: + case TL_updateSavedGifs.constructor: result = new TL_updateSavedGifs(); break; - case 0x7084a7be: + case TL_updateContactsReset.constructor: result = new TL_updateContactsReset(); break; - case 0x635b4c09: + case TL_updateChannel.constructor: result = new TL_updateChannel(); break; - case 0x2f2ba99f: + case TL_updateChannelWebPage.constructor: result = new TL_updateChannelWebPage(); break; - case 0x90866cee: + case TL_updateDeleteScheduledMessages.constructor: result = new TL_updateDeleteScheduledMessages(); break; - case 0xd29a27f4: + case TL_updateChannelMessageForwards.constructor: result = new TL_updateChannelMessageForwards(); break; - case 0xc32d5b12: + case TL_updateDeleteChannelMessages.constructor: result = new TL_updateDeleteChannelMessages(); break; - case 0x7d627683: + case TL_updateSentStoryReaction.constructor: result = new TL_updateSentStoryReaction(); break; - case 0xf227868c: + case TL_updateUserPhoto.constructor: result = new TL_updateUserPhoto(); break; - case 0x20529438: + case TL_updateUser.constructor: result = new TL_updateUser(); break; - case 0xccf08ad6: + case TL_updateGroupInvitePrivacyForbidden.constructor: result = new TL_updateGroupInvitePrivacyForbidden(); break; - case 0x17b7a20b: + case TL_updateAttachMenuBots.constructor: result = new TL_updateAttachMenuBots(); break; - case 0x3504914f: + case TL_updateDialogFilters.constructor: result = new TL_updateDialogFilters(); break; - case 0x30f443db: + case TL_updateRecentEmojiStatuses.constructor: result = new TL_updateRecentEmojiStatuses(); break; - case 0x75b3b798: + case TL_stories.TL_updateStory.constructor: result = new TL_stories.TL_updateStory(); break; - case 0x7063c3db: + case TL_updatePendingJoinRequests.constructor: result = new TL_updatePendingJoinRequests(); break; - case 0x8e5e9873: + case TL_updateDcOptions.constructor: result = new TL_updateDcOptions(); break; - case 0x1b3f4df7: + case TL_updateEditChannelMessage.constructor: result = new TL_updateEditChannelMessage(); break; - case 0x688a30aa: + case TL_updateNewStickerSet.constructor: result = new TL_updateNewStickerSet(); break; - case 0x8216fba3: + case TL_updateTheme.constructor: result = new TL_updateTheme(); break; - case 0x46560264: + case TL_updateLangPackTooLong.constructor: result = new TL_updateLangPackTooLong(); break; - case 0x38fe25b7: + case TL_updateEncryptedMessagesRead.constructor: result = new TL_updateEncryptedMessagesRead(); break; - case 0xbb2d201: + case TL_updateStickerSetsOrder.constructor: result = new TL_updateStickerSetsOrder(); break; - case 0x922e6e10: + case TL_updateReadChannelInbox.constructor: result = new TL_updateReadChannelInbox(); break; - case 0xf8227181: + case TL_updateReadMessagesContents.constructor: result = new TL_updateReadMessagesContents(); break; - case 0x7761198: + case TL_updateChatParticipants.constructor: result = new TL_updateChatParticipants(); break; - case 0x54c01850: + case TL_updateChatDefaultBannedRights.constructor: result = new TL_updateChatDefaultBannedRights(); break; - case 0x14b85813: + case TL_updateBotMenuButton.constructor: result = new TL_updateBotMenuButton(); break; - case 0xfe198602: + case TL_updateChannelPinnedTopics.constructor: result = new TL_updateChannelPinnedTopics(); break; - case 0x192efbe3: + case TL_updateChannelPinnedTopic.constructor: result = new TL_updateChannelPinnedTopic(); break; + case TL_updateChannelViewForumAsMessages.constructor: + result = new TL_updateChannelViewForumAsMessages(); + break; + case TL_updatePeerWallpaper.constructor: + result = new TL_updatePeerWallpaper(); + break; + 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)); @@ -35080,7 +35597,7 @@ public static class TL_updateUserEmojiStatus extends Update { 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); @@ -35287,10 +35804,10 @@ public void serializeToStream(AbstractSerializedData stream) { 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; @@ -35912,7 +36429,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); } } - + public static class TL_updateRecentEmojiStatuses extends Update { public static final int constructor = 0x30f443db; @@ -40742,7 +41259,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_sponsoredMessage extends TLObject { - public static final int constructor = 0xdaafff6b; + public static final int constructor = 0xed5383f7; public int flags; public boolean recommended; @@ -40753,9 +41270,11 @@ public static class TL_sponsoredMessage extends TLObject { public String chat_invite_hash; public int channel_post; public String start_param; + public BotApp app; public TL_sponsoredWebPage webpage; public String message; public ArrayList entities = new ArrayList<>(); + public String button_text; public String sponsor_info; public String additional_info; @@ -40795,6 +41314,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 512) != 0) { webpage = TL_sponsoredWebPage.TLdeserialize(stream, stream.readInt32(exception), exception); } + if ((flags & 1024) != 0) { + app = BotApp.TLdeserialize(stream, stream.readInt32(exception), exception); + } message = stream.readString(exception); if ((flags & 2) != 0) { int magic = stream.readInt32(exception); @@ -40813,6 +41335,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { entities.add(object); } } + if ((flags & 2048) != 0) { + button_text = stream.readString(exception); + } if ((flags & 128) != 0) { sponsor_info = stream.readString(exception); } @@ -40845,6 +41370,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 512) != 0) { webpage.serializeToStream(stream); } + if ((flags & 1024) != 0) { + app.serializeToStream(stream); + } stream.writeString(message); if ((flags & 2) != 0) { stream.writeInt32(0x1cb5c415); @@ -40854,6 +41382,9 @@ public void serializeToStream(AbstractSerializedData stream) { entities.get(a).serializeToStream(stream); } } + if ((flags & 2048) != 0) { + stream.writeString(button_text); + } if ((flags & 128) != 0) { stream.writeString(sponsor_info); } @@ -42464,17 +42995,21 @@ public static abstract class WallPaperSettings extends TLObject { 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; } @@ -42561,6 +43096,66 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -44292,6 +44887,18 @@ public static ChannelAdminLogEventAction TLdeserialize(AbstractSerializedData st 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)); @@ -44903,6 +45510,24 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -45044,10 +45669,10 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -45078,6 +45703,60 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -45530,8 +46209,10 @@ public static abstract class Chat extends TLObject { public boolean stories_hidden_min; public boolean stories_unavailable; public int stories_max_id; - public int color; - public long background_emoji_id; + public TL_peerColor color; + public TL_peerColor profile_color; + public EmojiStatus emoji_status; + public int level; public ArrayList usernames = new ArrayList<>(); @@ -45561,8 +46242,17 @@ public static Chat TLdeserialize(AbstractSerializedData stream, int constructor, case TL_channel.constructor: result = new TL_channel(); break; - case TL_channel_layer165_2.constructor: - result = new TL_channel_layer165_2(); + case TL_channel_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; case TL_channel_layer165.constructor: result = new TL_channel_layer165(); @@ -46004,8 +46694,8 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_channel extends Chat { - public static final int constructor = 0x1981ea7e; + 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); @@ -46092,11 +46782,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } - if ((flags2 & 64) != 0) { - color = stream.readInt32(exception); + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } - if ((flags2 & 32) != 0) { - background_emoji_id = stream.readInt64(exception); + if ((flags2 & 256) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -46168,17 +46858,17 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags2 & 16) != 0) { stream.writeInt32(stories_max_id); } - if ((flags2 & 64) != 0) { - stream.writeInt32(color); + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); } - if ((flags2 & 32) != 0) { - stream.writeInt64(background_emoji_id); + if ((flags2 & 256) != 0) { + profile_color.serializeToStream(stream); } } } - public static class TL_channel_layer165 extends TL_channel { - public static final int constructor = 0x2458af8c; + 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); @@ -46265,174 +46955,14 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags2 & 16) != 0) { stories_max_id = stream.readInt32(exception); } - color = stream.readInt32(exception); - if ((flags2 & 32) != 0) { - background_emoji_id = stream.readInt64(exception); - } - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = creator ? (flags | 1) : (flags &~ 1); - flags = left ? (flags | 4) : (flags &~ 4); - flags = broadcast ? (flags | 32) : (flags &~ 32); - flags = verified ? (flags | 128) : (flags &~ 128); - flags = megagroup ? (flags | 256) : (flags &~ 256); - flags = restricted ? (flags | 512) : (flags &~ 512); - flags = signatures ? (flags | 2048) : (flags &~ 2048); - flags = min ? (flags | 4096) : (flags &~ 4096); - flags = scam ? (flags | 524288) : (flags &~ 524288); - flags = has_link ? (flags | 1048576) : (flags &~ 1048576); - flags = has_geo ? (flags | 2097152) : (flags &~ 2097152); - flags = slowmode_enabled ? (flags | 4194304) : (flags &~ 4194304); - flags = call_active ? (flags | 8388608) : (flags &~ 8388608); - flags = call_not_empty ? (flags | 16777216) : (flags &~ 16777216); - flags = fake ? (flags | 33554432) : (flags &~ 33554432); - flags = gigagroup ? (flags | 67108864) : (flags &~ 67108864); - flags = noforwards ? (flags | 134217728) : (flags &~ 134217728); - flags = join_to_send ? (flags | 268435456) : (flags &~ 268435456); - flags = join_request ? (flags | 536870912) : (flags &~ 536870912); - flags = forum ? (flags | 1073741824) : (flags &~ 1073741824); - stream.writeInt32(flags); - flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); - flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); - flags2 = stories_unavailable ? (flags2 | 8) : (flags2 &~ 8); - stream.writeInt32(flags2); - stream.writeInt64(id); - if ((flags & 8192) != 0) { - stream.writeInt64(access_hash); - } - stream.writeString(title); - if ((flags & 64) != 0) { - stream.writeString(username); - } - photo.serializeToStream(stream); - stream.writeInt32(date); - if ((flags & 512) != 0) { - stream.writeInt32(0x1cb5c415); - int count = restriction_reason.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - restriction_reason.get(a).serializeToStream(stream); - } - } - if ((flags & 16384) != 0) { - admin_rights.serializeToStream(stream); - } - if ((flags & 32768) != 0) { - banned_rights.serializeToStream(stream); - } - if ((flags & 262144) != 0) { - default_banned_rights.serializeToStream(stream); - } - if ((flags & 131072) != 0) { - stream.writeInt32(participants_count); - } - if ((flags2 & 1) != 0) { - stream.writeInt32(0x1cb5c415); - int count = usernames.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - usernames.get(a).serializeToStream(stream); - } - } - if ((flags2 & 16) != 0) { - stream.writeInt32(stories_max_id); - } - stream.writeInt32(color); - if ((flags2 & 32) != 0) { - stream.writeInt64(background_emoji_id); - } - } - } - - public static class TL_channel_layer165_2 extends TL_channel { - public static final int constructor = 0x94f592db; - - public void readParams(AbstractSerializedData stream, boolean exception) { - 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 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } - if ((flags2 & 1) != 0) { - int magic = stream.readInt32(exception); - if (magic != 0x1cb5c415) { - if (exception) { - throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); - } - return; - } - int count = stream.readInt32(exception); - for (int a = 0; a < count; a++) { - TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - usernames.add(object); - } + if ((flags2 & 256) != 0) { + profile_color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); } - if ((flags2 & 16) != 0) { - stories_max_id = stream.readInt32(exception); + if ((flags2 & 512) != 0) { + emoji_status = EmojiStatus.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -46504,17 +47034,22 @@ public void serializeToStream(AbstractSerializedData 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_layer161 extends TL_channel { - public static final int constructor = 0x83259464; + public static class TL_channel extends Chat { + public static final int constructor = 0xaadfc8f; public void readParams(AbstractSerializedData stream, boolean exception) { - readParams(stream, exception, true); - } - - public void readParams(AbstractSerializedData stream, boolean exception, boolean allowStrippedThumb) { flags = stream.readInt32(exception); creator = (flags & 1) != 0; left = (flags & 4) != 0; @@ -46539,6 +47074,7 @@ public void readParams(AbstractSerializedData stream, boolean exception, boolean 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); @@ -46547,7 +47083,7 @@ public void readParams(AbstractSerializedData stream, boolean exception, boolean if ((flags & 64) != 0) { username = stream.readString(exception); } - photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception, allowStrippedThumb); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); date = stream.readInt32(exception); if ((flags & 512) != 0) { int magic = stream.readInt32(exception); @@ -46595,6 +47131,21 @@ public void readParams(AbstractSerializedData stream, boolean exception, boolean 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) { @@ -46622,6 +47173,7 @@ public void serializeToStream(AbstractSerializedData stream) { 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) { @@ -46661,12 +47213,26 @@ public void serializeToStream(AbstractSerializedData stream) { 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_layer147 extends TL_channel { - public static final int constructor = 0x8261ac61; - + public static class TL_channel_layer167 extends TL_channel { + public static final int constructor = 0x8e87ccd8; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -46690,6 +47256,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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); @@ -46729,6 +47299,29 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 131072) != 0) { participants_count = stream.readInt32(exception); } + if ((flags2 & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } + if ((flags2 & 128) != 0) { + color = TL_peerColor.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -46754,6 +47347,10 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -46784,57 +47381,53 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 131072) != 0) { stream.writeInt32(participants_count); } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } + if ((flags2 & 128) != 0) { + color.serializeToStream(stream); + } } } - public static class TL_chatForbidden extends Chat { - public static final int constructor = 0x6592a1a7; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - title = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeString(title); - } - } - - public static class TL_chatForbidden_layer131 extends TL_chatForbidden { - public static final int constructor = 0x7328bdb; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt32(exception); - title = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32((int) id); - stream.writeString(title); - } - } - - public static class TL_channel_layer67 extends TL_channel { - public static final int constructor = 0xa14dca52; + public static class TL_channel_layer166 extends TL_channel { + public static final int constructor = 0x1981ea7e; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); creator = (flags & 1) != 0; - kicked = (flags & 2) != 0; left = (flags & 4) != 0; - moderator = (flags & 16) != 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; - id = stream.readInt32(exception); + 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); } @@ -46844,26 +47437,95 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); date = stream.readInt32(exception); - version = stream.readInt32(exception); if ((flags & 512) != 0) { - stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_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 & 64) != 0) { + color = new TL_peerColor(); + color.color = stream.readInt32(exception); + } + if ((flags2 & 32) != 0) { + if (color == null) { + color = new TL_peerColor(); + } + color.background_emoji_id = stream.readInt64(exception); } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = creator ? (flags | 1) : (flags &~ 1); - flags = kicked ? (flags | 2) : (flags &~ 2); flags = left ? (flags | 4) : (flags &~ 4); - flags = moderator ? (flags | 16) : (flags &~ 16); 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); - stream.writeInt32((int) id); + 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); } @@ -46873,90 +47535,224 @@ public void serializeToStream(AbstractSerializedData stream) { } photo.serializeToStream(stream); stream.writeInt32(date); - stream.writeInt32(version); if ((flags & 512) != 0) { - stream.writeString(""); + 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 & 64) != 0) { + stream.writeInt32(color == null ? (int) (id % 7) : color.color); + } + if ((flags2 & 32) != 0) { + stream.writeInt64(color == null ? 0 : color.background_emoji_id); } } } - public static class TL_channel_old extends TL_channel { - public static final int constructor = 0x678e9587; + public static class TL_channel_layer165 extends TL_channel { + public static final int constructor = 0x94f592db; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); creator = (flags & 1) != 0; - kicked = (flags & 2) != 0; left = (flags & 4) != 0; - moderator = (flags & 16) != 0; broadcast = (flags & 32) != 0; verified = (flags & 128) != 0; megagroup = (flags & 256) != 0; - explicit_content = (flags & 512) != 0; - id = stream.readInt32(exception); - access_hash = stream.readInt64(exception); + 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); - version = stream.readInt32(exception); + if ((flags & 512) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_restrictionReason object = TL_restrictionReason.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + restriction_reason.add(object); + } + } + if ((flags & 16384) != 0) { + admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 262144) != 0) { + default_banned_rights = TL_chatBannedRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 131072) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags2 & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_username object = TL_username.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + usernames.add(object); + } + } + if ((flags2 & 16) != 0) { + stories_max_id = stream.readInt32(exception); + } +// color = new TL_peerColor(); +// color.color = stream.readInt32(exception); +// if ((flags2 & 32) != 0) { +// color.background_emoji_id = stream.readInt64(exception); +// } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = creator ? (flags | 1) : (flags &~ 1); - flags = kicked ? (flags | 2) : (flags &~ 2); flags = left ? (flags | 4) : (flags &~ 4); - flags = moderator ? (flags | 16) : (flags &~ 16); flags = broadcast ? (flags | 32) : (flags &~ 32); flags = verified ? (flags | 128) : (flags &~ 128); flags = megagroup ? (flags | 256) : (flags &~ 256); - flags = explicit_content ? (flags | 512) : (flags &~ 512); + 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); - stream.writeInt32((int) id); - stream.writeInt64(access_hash); + 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); - stream.writeInt32(version); + if ((flags & 512) != 0) { + stream.writeInt32(0x1cb5c415); + int count = restriction_reason.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + restriction_reason.get(a).serializeToStream(stream); + } + } + if ((flags & 16384) != 0) { + admin_rights.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + banned_rights.serializeToStream(stream); + } + if ((flags & 262144) != 0) { + default_banned_rights.serializeToStream(stream); + } + if ((flags & 131072) != 0) { + stream.writeInt32(participants_count); + } + if ((flags2 & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = usernames.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + usernames.get(a).serializeToStream(stream); + } + } + if ((flags2 & 16) != 0) { + stream.writeInt32(stories_max_id); + } +// stream.writeInt32(color == null ? (int) (id % 7) : color.color); +// if ((flags2 & 32) != 0) { +// stream.writeInt64(color == null ? 0 : color.background_emoji_id); +// } } } - public static class TL_chat_old extends TL_chat { - public static final int constructor = 0x6e9c9bc7; + public static class TL_channel_layer161 extends TL_channel { + public static final int constructor = 0x83259464; public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt32(exception); - title = stream.readString(exception); - photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); - participants_count = stream.readInt32(exception); - date = stream.readInt32(exception); - left = stream.readBool(exception); - version = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32((int) id); - stream.writeString(title); - photo.serializeToStream(stream); - stream.writeInt32(participants_count); - stream.writeInt32(date); - stream.writeBool(left); - stream.writeInt32(version); + readParams(stream, exception, true); } - } - - public static class TL_channel_layer131 extends TL_channel { - public static final int constructor = 0xd31a961e; - - public void readParams(AbstractSerializedData stream, boolean exception) { + public void readParams(AbstractSerializedData stream, boolean exception, boolean allowStrippedThumb) { flags = stream.readInt32(exception); creator = (flags & 1) != 0; left = (flags & 4) != 0; @@ -46974,7 +47770,14 @@ public void readParams(AbstractSerializedData stream, boolean exception) { call_not_empty = (flags & 16777216) != 0; fake = (flags & 33554432) != 0; gigagroup = (flags & 67108864) != 0; - id = stream.readInt32(exception); + 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; + id = stream.readInt64(exception); if ((flags & 8192) != 0) { access_hash = stream.readInt64(exception); } @@ -46982,9 +47785,8 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 64) != 0) { username = stream.readString(exception); } - photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception, allowStrippedThumb); date = stream.readInt32(exception); - version = stream.readInt32(exception); if ((flags & 512) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -47014,6 +47816,23 @@ public void readParams(AbstractSerializedData stream, boolean 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); + } + } } public void serializeToStream(AbstractSerializedData stream) { @@ -47034,8 +47853,15 @@ public void serializeToStream(AbstractSerializedData stream) { 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); - stream.writeInt32((int) id); + flags2 = stories_hidden ? (flags2 | 2) : (flags2 &~ 2); + flags2 = stories_hidden_min ? (flags2 | 4) : (flags2 &~ 4); + stream.writeInt32(flags2); + stream.writeInt64(id); if ((flags & 8192) != 0) { stream.writeInt64(access_hash); } @@ -47045,7 +47871,6 @@ public void serializeToStream(AbstractSerializedData stream) { } photo.serializeToStream(stream); stream.writeInt32(date); - stream.writeInt32(version); if ((flags & 512) != 0) { stream.writeInt32(0x1cb5c415); int count = restriction_reason.size(); @@ -47066,11 +47891,19 @@ public void serializeToStream(AbstractSerializedData 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); + } + } } } - public static class TL_channel_layer104 extends TL_channel { - public static final int constructor = 0x4df30834; + public static class TL_channel_layer147 extends TL_channel { + public static final int constructor = 0x8261ac61; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -47087,7 +47920,15 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_link = (flags & 1048576) != 0; has_geo = (flags & 2097152) != 0; slowmode_enabled = (flags & 4194304) != 0; - id = stream.readInt32(exception); + 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; + id = stream.readInt64(exception); if ((flags & 8192) != 0) { access_hash = stream.readInt64(exception); } @@ -47097,9 +47938,22 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); date = stream.readInt32(exception); - version = stream.readInt32(exception); if ((flags & 512) != 0) { - stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_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); @@ -47129,8 +47983,16 @@ public void serializeToStream(AbstractSerializedData stream) { 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); - stream.writeInt32((int) id); + stream.writeInt64(id); if ((flags & 8192) != 0) { stream.writeInt64(access_hash); } @@ -47140,9 +48002,385 @@ public void serializeToStream(AbstractSerializedData stream) { } photo.serializeToStream(stream); stream.writeInt32(date); - stream.writeInt32(version); if ((flags & 512) != 0) { - stream.writeString(""); + 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); + } + } + } + + public static class TL_chatForbidden extends Chat { + public static final int constructor = 0x6592a1a7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeString(title); + } + } + + public static class TL_chatForbidden_layer131 extends TL_chatForbidden { + public static final int constructor = 0x7328bdb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32((int) id); + stream.writeString(title); + } + } + + public static class TL_channel_layer67 extends TL_channel { + public static final int constructor = 0xa14dca52; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + moderator = (flags & 16) != 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; + id = stream.readInt32(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); + version = stream.readInt32(exception); + if ((flags & 512) != 0) { + stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = moderator ? (flags | 16) : (flags &~ 16); + 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); + stream.writeInt32(flags); + stream.writeInt32((int) 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); + stream.writeInt32(version); + if ((flags & 512) != 0) { + stream.writeString(""); + } + } + } + + public static class TL_channel_old extends TL_channel { + public static final int constructor = 0x678e9587; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + moderator = (flags & 16) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + explicit_content = (flags & 512) != 0; + id = stream.readInt32(exception); + 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); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = moderator ? (flags | 16) : (flags &~ 16); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = explicit_content ? (flags | 512) : (flags &~ 512); + stream.writeInt32(flags); + stream.writeInt32((int) id); + stream.writeInt64(access_hash); + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + stream.writeInt32(version); + } + } + + public static class TL_chat_old extends TL_chat { + public static final int constructor = 0x6e9c9bc7; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + participants_count = stream.readInt32(exception); + date = stream.readInt32(exception); + left = stream.readBool(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32((int) id); + stream.writeString(title); + photo.serializeToStream(stream); + stream.writeInt32(participants_count); + stream.writeInt32(date); + stream.writeBool(left); + stream.writeInt32(version); + } + } + + public static class TL_channel_layer131 extends TL_channel { + public static final int constructor = 0xd31a961e; + + + 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; + id = stream.readInt32(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); + version = 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); + } + } + + 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); + stream.writeInt32(flags); + stream.writeInt32((int) 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); + stream.writeInt32(version); + 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); + } + } + } + + public static class TL_channel_layer104 extends TL_channel { + public static final int constructor = 0x4df30834; + + + 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; + id = stream.readInt32(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); + version = stream.readInt32(exception); + if ((flags & 512) != 0) { + stream.readString(exception); + } + 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); + } + } + + 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); + stream.writeInt32(flags); + stream.writeInt32((int) 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); + stream.writeInt32(version); + if ((flags & 512) != 0) { + stream.writeString(""); } if ((flags & 16384) != 0) { admin_rights.serializeToStream(stream); @@ -47495,6 +48733,7 @@ public static abstract class StickerSet extends TLObject { 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; @@ -47578,6 +48817,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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); } @@ -47624,6 +48864,7 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -48722,6 +49963,7 @@ public static abstract class MessageFwdHeader extends TLObject { public int flags; public boolean imported; + public boolean saved_out; public Peer from_id; public String from_name; public int date; @@ -48729,6 +49971,9 @@ public static abstract class MessageFwdHeader extends TLObject { 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) { @@ -48746,9 +49991,12 @@ public static MessageFwdHeader TLdeserialize(AbstractSerializedData stream, int 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; @@ -48800,6 +50048,85 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -50003,7 +51330,7 @@ public void serializeToStream(AbstractSerializedData stream) { } public static abstract class ReactionCount extends TLObject { - + public int flags; public int chosen_order; public boolean chosen; //custom @@ -50132,6 +51459,7 @@ public static abstract class UserFull extends TLObject { public boolean translations_disabled; public boolean stories_pinned_available; public boolean blocked_my_stories_from; + public boolean wallpaper_overridden; public User user; public String about; public TL_contacts_link_layer101 link; @@ -50222,6 +51550,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { translations_disabled = (flags & 8388608) != 0; stories_pinned_available = (flags & 67108864) != 0; blocked_my_stories_from = (flags & 134217728) != 0; + wallpaper_overridden = (flags & 268435456) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -50299,6 +51628,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); + flags = wallpaper_overridden ? (flags | 268435456) : (flags &~ 268435456); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -51859,6 +53189,7 @@ public static abstract class WallPaper extends TLObject { public WallPaperSettings settings; public String uploadingImage;//custom public Bitmap stripedThumb;//custom + public Drawable thumbDrawable;//custom public static WallPaper TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { WallPaper result = null; @@ -55306,12 +56637,13 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -55335,6 +56667,9 @@ public void serializeToStream(AbstractSerializedData stream) { 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); } @@ -55568,6 +56903,33 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -56195,9 +57557,11 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -56208,8 +57572,12 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct 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); } @@ -57652,6 +59020,21 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -59169,10 +60552,11 @@ public void serializeToStream(AbstractSerializedData stream) { } 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<>(); @@ -59193,6 +60577,9 @@ public void serializeToStream(AbstractSerializedData stream) { 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); } @@ -62319,16 +63706,16 @@ public static abstract class InputStorePaymentPurpose extends TLObject { 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; } @@ -62630,26 +64017,22 @@ public void serializeToStream(AbstractSerializedData stream) { } 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); } } @@ -62675,6 +64058,168 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_stats_getStoryPublicForwards extends TLObject { + public static final int constructor = 0xa6437ef6; + + public InputPeer peer; + public int id; + public String offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stats_publicForwards.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(id); + stream.writeString(offset); + stream.writeInt32(limit); + } + } + + public static class TL_stats_publicForwards extends TLObject { + public static final int constructor = 0x93037e20; + + public int flags; + public int count; + public ArrayList forwards = new ArrayList<>(); + public String next_offset; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_stats_publicForwards TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stats_publicForwards.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stats_publicForwards", constructor)); + } else { + return null; + } + } + TL_stats_publicForwards result = new TL_stats_publicForwards(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PublicForward object = PublicForward.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + forwards.add(object); + } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = forwards.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + forwards.get(a).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static abstract class PublicForward extends TLObject { + + public static PublicForward TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PublicForward result = null; + switch (constructor) { + case TL_publicForwardMessage.constructor: + result = new TL_publicForwardMessage(); + break; + case TL_stories.TL_publicForwardStory.constructor: + result = new TL_stories.TL_publicForwardStory(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PublicForward", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_publicForwardMessage extends PublicForward { + public static final int constructor = 0x1f2bf4a; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + } + } + //manually created public static class TL_photoPathSize extends PhotoSize { @@ -62974,6 +64519,9 @@ public static abstract class MessageMedia extends TLObject { 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; @@ -63047,9 +64595,15 @@ public static MessageMedia TLdeserialize(AbstractSerializedData stream, int cons 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; @@ -63161,6 +64715,14 @@ public static MessageMedia TLdeserialize(AbstractSerializedData stream, int cons } return result; } + + public Boolean documentExists; + public Document getDocument() { + if (alt_document != null && ApplicationLoader.useLessData()) { + return alt_document; + } + return document; + } } //MessageMedia end @@ -63496,6 +65058,7 @@ public static class Message extends TLObject { 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; @@ -63649,9 +65212,12 @@ public static Message TLdeserialize(AbstractSerializedData stream, int construct 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; @@ -64352,6 +65918,196 @@ public void serializeToStream(AbstractSerializedData stream) { } 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) { @@ -66658,6 +68414,7 @@ public static abstract class Dialog extends TLObject { public int flags; public boolean pinned; public boolean unread_mark; + public boolean view_forum_as_messages; public Peer peer; public int top_message; public int read_inbox_max_id; @@ -66675,7 +68432,7 @@ public static abstract class Dialog extends TLObject { 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: @@ -66706,6 +68463,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); pinned = (flags & 4) != 0; unread_mark = (flags & 8) != 0; + view_forum_as_messages = (flags & 64) != 0; peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); top_message = stream.readInt32(exception); read_inbox_max_id = stream.readInt32(exception); @@ -66732,6 +68490,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = pinned ? (flags | 4) : (flags &~ 4); flags = unread_mark ? (flags | 8) : (flags &~ 8); + flags = view_forum_as_messages ? (flags | 64) : (flags &~ 64); stream.writeInt32(flags); peer.serializeToStream(stream); stream.writeInt32(top_message); @@ -67517,9 +69276,11 @@ public void freeResources() { } 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; @@ -67530,7 +69291,11 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct 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); @@ -68072,15 +69837,34 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_keyboardButtonRequestPeer extends KeyboardButton { + public static class TL_keyboardButtonRequestPeer_layer168 extends TL_keyboardButtonRequestPeer { public static final int constructor = 0xd0b468c; + 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); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(button_id); + peer_type.serializeToStream(stream); + } + } + + 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) { @@ -68088,6 +69872,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeString(text); stream.writeInt32(button_id); peer_type.serializeToStream(stream); + stream.writeInt32(max_quantity); } } @@ -69402,12 +71187,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_transcribedAudio extends TLObject { - public static final int constructor = 0x93752c52; + public static final int constructor = 0xcfb9d957; public int flags; public boolean pending; public long transcription_id; public String text; + public int trial_remains_num; + public int trial_remains_until_date; public static TL_messages_transcribedAudio TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_messages_transcribedAudio.constructor != constructor) { @@ -69427,6 +71214,10 @@ public void readParams(AbstractSerializedData stream, boolean exception) { pending = (flags & 1) != 0; transcription_id = stream.readInt64(exception); text = stream.readString(exception); + if ((flags & 2) != 0) { + trial_remains_num = stream.readInt32(exception); + trial_remains_until_date = stream.readInt32(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -69435,6 +71226,10 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(flags); stream.writeInt64(transcription_id); stream.writeString(text); + if ((flags & 2) != 0) { + stream.writeInt32(trial_remains_num); + stream.writeInt32(trial_remains_until_date); + } } } @@ -70438,10 +72233,10 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeBool(enabled); } } - + public static class TL_channels_clickSponsoredMessage extends TLObject { public static final int constructor = 0x18afbc93; - + public InputChannel channel; public byte[] random_id; @@ -70513,12 +72308,12 @@ public void serializeToStream(AbstractSerializedData stream) { } 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); @@ -70529,7 +72324,12 @@ public void serializeToStream(AbstractSerializedData stream) { 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); + } } } @@ -70586,15 +72386,18 @@ public void serializeToStream(AbstractSerializedData stream) { } } - 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) { @@ -70604,6 +72407,43 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -70735,10 +72575,26 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -70749,9 +72605,12 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_profile ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); channel.serializeToStream(stream); - stream.writeInt32(color); + if ((flags & 4) != 0) { + stream.writeInt32(color); + } if ((flags & 1) != 0) { stream.writeInt64(background_emoji_id); } @@ -70759,9 +72618,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_account_updateColor extends TLObject { - public static final int constructor = 0xa001cc43; + public static final int constructor = 0x7cefa15d; public int flags; + public boolean for_profile; public int color; public long background_emoji_id; @@ -70771,8 +72631,11 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_profile ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); - stream.writeInt32(color); + if ((flags & 4) != 0) { + stream.writeInt32(color); + } if ((flags & 1) != 0) { stream.writeInt64(background_emoji_id); } @@ -70794,10 +72657,116 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_updateChannelViewForumAsMessages extends Update { + public static final int constructor = 0x7b68920; + + public long channel_id; + public boolean enabled; + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt64(exception); + enabled = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(channel_id); + stream.writeBool(enabled); + } + } + + public static class TL_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; + + public int flags; + public boolean wallpaper_overridden; + public Peer peer; + public WallPaper wallpaper; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + wallpaper_overridden = (flags & 2) != 0; + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + wallpaper = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = wallpaper_overridden ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + wallpaper.serializeToStream(stream); + } + } + } + public static class TL_messages_setChatWallPaper extends TLObject { public static final int constructor = 0x8ffacae1; public int flags; + public boolean for_both; + public boolean revert; public InputPeer peer; public InputWallPaper wallpaper; public WallPaperSettings settings; @@ -70809,6 +72778,8 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = for_both ? (flags | 8) : (flags &~ 8); + flags = revert ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); peer.serializeToStream(stream); if ((flags & 1) != 0) { @@ -70825,12 +72796,12 @@ public void serializeToStream(AbstractSerializedData stream) { 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); } @@ -70852,7 +72823,7 @@ public static class TL_editCloseFriends extends TLObject { 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); } @@ -70876,6 +72847,7 @@ public static abstract class InputReplyTo extends TLObject { public InputPeer reply_to_peer_id; public String quote_text; public ArrayList quote_entities = new ArrayList<>(); + public int quote_offset; public InputUser user_id; public int story_id; @@ -70886,6 +72858,9 @@ public static InputReplyTo TLdeserialize(AbstractSerializedData stream, int cons case TL_inputReplyToMessage.constructor: result = new TL_inputReplyToMessage(); break; + case TL_inputReplyToMessage_layer166.constructor: + result = new TL_inputReplyToMessage_layer166(); + break; case TL_inputReplyToStory.constructor: result = new TL_inputReplyToStory(); break; @@ -70901,6 +72876,70 @@ public static InputReplyTo TLdeserialize(AbstractSerializedData stream, int cons } public static class TL_inputReplyToMessage extends InputReplyTo { + public static final int constructor = 0x22c0f6d5; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + reply_to_msg_id = stream.readInt32(exception); + if ((flags & 1) != 0) { + top_msg_id = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + reply_to_peer_id = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + quote_text = stream.readString(exception); + } + if ((flags & 8) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + quote_entities.add(object); + } + } + if ((flags & 16) != 0) { + quote_offset = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(reply_to_msg_id); + if ((flags & 1) != 0) { + stream.writeInt32(top_msg_id); + } + if ((flags & 2) != 0) { + reply_to_peer_id.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeString(quote_text); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = quote_entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; ++a) { + quote_entities.get(a).serializeToStream(stream); + } + } + if ((flags & 16) != 0) { + stream.writeInt32(quote_offset); + } + } + } + + public static class TL_inputReplyToMessage_layer166 extends TL_inputReplyToMessage { public static final int constructor = 0x73ec805; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -71172,14 +73211,64 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -71205,7 +73294,7 @@ public void serializeToStream(AbstractSerializedData stream) { } 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<>(); @@ -71255,13 +73344,15 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -71270,6 +73361,7 @@ public static class TL_inputStorePaymentPremiumGiveaway extends InputStorePaymen 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); @@ -71301,6 +73393,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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); @@ -71310,6 +73405,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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) { @@ -71328,6 +73424,9 @@ public void serializeToStream(AbstractSerializedData stream) { 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); @@ -71353,16 +73452,155 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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 int constructor = 0x58260664; + 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; @@ -71532,7 +73770,7 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -71572,7 +73810,7 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -71621,10 +73859,10 @@ public static abstract class payments_GiveawayInfo extends TLObject { 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; } @@ -71656,7 +73894,7 @@ public void serializeToStream(AbstractSerializedData stream) { } 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; @@ -71687,7 +73925,9 @@ public static TL_payments_checkedGiftCode TLdeserialize(AbstractSerializedData s 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); } @@ -71733,9 +73973,11 @@ public void readParams(AbstractSerializedData stream, boolean exception) { 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); } @@ -71789,7 +74031,779 @@ public void serializeToStream(AbstractSerializedData stream) { } } - //functions + public static class TL_messageActionGiveawayResults extends MessageAction { + public static int constructor = 0x2a9fadc5; + + public int winners_count; + public int unclaimed_count; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + winners_count = stream.readInt32(exception); + unclaimed_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(winners_count); + stream.writeInt32(unclaimed_count); + } + } + + public static class TL_channels_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; + + public InputChannel channel; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Chats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_toggleViewForumAsMessages extends TLObject { + public static int constructor = 0x9738bb15; + + public InputChannel channel_id; + public boolean enabled; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel_id.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_peerColor extends TLObject { + public static final int constructor = 0xb54b5acf; + + public int flags; + public int color; + public long background_emoji_id; + + public static TL_peerColor TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_peerColor.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_peerColor", constructor)); + } else { + return null; + } + } + TL_peerColor result = new TL_peerColor(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + color = (flags & 1) != 0 ? stream.readInt32(exception) : -1; + if ((flags & 2) != 0) { + background_emoji_id = stream.readInt64(exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(color); + } + if ((flags & 2) != 0) { + stream.writeInt64(background_emoji_id); + } + } + } + + public static class help_PeerColorSet extends TLObject { + public static help_PeerColorSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_PeerColorSet result = null; + switch (constructor) { + case TL_help_peerColorSet.constructor: + result = new TL_help_peerColorSet(); + break; + case TL_help_peerColorProfileSet.constructor: + result = new TL_help_peerColorProfileSet(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_PeerColorSet", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_peerColorSet extends help_PeerColorSet { + public static final int constructor = 0x26219a58; + + public ArrayList colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + colors.add(stream.readInt32(exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(colors.get(i)); + } + } + } + + public static class TL_help_peerColorProfileSet extends help_PeerColorSet { + public static final int constructor = 0x767d61eb; + + public ArrayList palette_colors = new ArrayList<>(); + public ArrayList bg_colors = new ArrayList<>(); + public ArrayList story_colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + palette_colors.add(stream.readInt32(exception)); + } + + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + bg_colors.add(stream.readInt32(exception)); + } + + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + story_colors.add(stream.readInt32(exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = palette_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(palette_colors.get(i)); + } + stream.writeInt32(0x1cb5c415); + count = bg_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(bg_colors.get(i)); + } + stream.writeInt32(0x1cb5c415); + count = story_colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + stream.writeInt32(story_colors.get(i)); + } + } + } + + public static class TL_help_peerColorOption extends TLObject { + public static final int constructor = 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) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_help_peerColorOption", constructor)); + } else { + return null; + } + } + TL_help_peerColorOption result = new TL_help_peerColorOption(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + hidden = (flags & 1) != 0; + color_id = stream.readInt32(exception); + if ((flags & 2) != 0) { + colors = help_PeerColorSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + dark_colors = help_PeerColorSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 8) != 0) { + channel_min_level = stream.readInt32(exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = hidden ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(color_id); + if ((flags & 2) != 0) { + colors.serializeToStream(stream); + } + if ((flags & 4) != 0) { + dark_colors.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeInt32(channel_min_level); + } + } + } + + public static class help_PeerColors extends TLObject { + public static help_PeerColors TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_PeerColors result = null; + switch (constructor) { + case TL_help_peerColorsNotModified.constructor: + result = new TL_help_peerColorsNotModified(); + break; + case TL_help_peerColors.constructor: + result = new TL_help_peerColors(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_PeerColors", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_peerColorsNotModified extends help_PeerColors { + public static final int constructor = 0x2ba1f5ce; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_peerColors extends help_PeerColors { + public static final int constructor = 0xf8ed08; + + public int hash; + public ArrayList colors = new ArrayList<>(); + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int i = 0; i < count; ++i) { + colors.add(TL_help_peerColorOption.TLdeserialize(stream, stream.readInt32(exception), exception)); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = colors.size(); + stream.writeInt32(count); + for (int i = 0; i < count; ++i) { + colors.get(i).serializeToStream(stream); + } + } + } + + public static class TL_help_getPeerColors extends TLObject { + public static final int constructor = 0xda80f42f; + + public int hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_PeerColors.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_help_getPeerProfileColors extends TLObject { + public static final int constructor = 0xabcfa9fd; + + public int hash; + + @Override + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_PeerColors.TLdeserialize(stream, constructor, exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class 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; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java b/TMessagesProj/src/main/java/org/telegram/tgnet/tl/TL_stories.java index dbf55895c8..2aa0bf5de5 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 void serializeToStream(AbstractSerializedData stream) { } } - 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 static class TL_storyView extends TLObject { 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 void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -462,11 +518,12 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_sendStory extends TLObject { - public static final int constructor = 0xbcb73644; + public static final int constructor = 0xe4e6694b; public int flags; public boolean pinned; public boolean noforwards; + public boolean fwd_modified; public TLRPC.InputPeer peer; public TLRPC.InputMedia media; public ArrayList media_areas = new ArrayList<>(); @@ -475,6 +532,8 @@ public static class TL_stories_sendStory extends TLObject { public ArrayList privacy_rules = new ArrayList<>(); public long random_id; public int period; + public TLRPC.InputPeer fwd_from_id; + public int fwd_from_story; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TLRPC.Updates.TLdeserialize(stream, constructor, exception); @@ -484,6 +543,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = pinned ? (flags | 4) : (flags &~ 4); flags = noforwards ? (flags | 16) : (flags &~ 16); + flags = fwd_modified ? (flags | 128) : (flags &~ 128); stream.writeInt32(flags); peer.serializeToStream(stream); media.serializeToStream(stream); @@ -516,6 +576,12 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 8) != 0) { stream.writeInt32(period); } + if ((flags & 64) != 0) { + fwd_from_id.serializeToStream(stream); + } + if ((flags & 64) != 0) { + stream.writeInt32(fwd_from_story); + } } } @@ -852,28 +918,131 @@ public void serializeToStream(AbstractSerializedData stream) { } } - 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) { + 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); + } + 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("can't parse magic %x in TL_stories_storyViewsList", constructor)); - } else { - return null; + 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); } - TL_stories_storyViewsList result = new TL_stories_storyViewsList(); - result.readParams(stream, exception); - return result; } + } + + + 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); @@ -888,7 +1057,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } 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; } @@ -965,6 +1134,7 @@ public static class TL_stories_getStoryViewsList extends TLObject { 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; @@ -972,13 +1142,14 @@ public static class TL_stories_getStoryViewsList extends TLObject { 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) { @@ -1755,6 +1926,7 @@ public static abstract class StoryItem extends TLObject { public boolean out; public int id; public int date; + public StoryFwdHeader fwd_from; public int expire_date; public String caption; public boolean edited; @@ -1781,9 +1953,12 @@ public static abstract class StoryItem extends TLObject { public static StoryItem TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StoryItem result = null; switch (constructor) { - case 0x44c457ce: + case 0xaf6365a1: result = new TL_storyItem(); break; + case 0x44c457ce: + result = new TL_storyItem_layer166(); + break; case 0x562aa637: result = new TL_storyItem_layer160(); break; @@ -1959,7 +2134,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = has_viewers ? (flags | 2) : (flags &~ 2); + flags = has_viewers ? (flags | 2) : (flags & ~2); stream.writeInt32(flags); stream.writeInt32(views_count); if ((flags & 4) != 0) { @@ -1987,8 +2162,86 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_publicForwardStory extends TLRPC.PublicForward { + public static final int constructor = 0xedf3add0; + + public TLRPC.Peer peer; + public StoryItem story; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + story = StoryItem.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + story.serializeToStream(stream); + } + } + + public static class StoryFwdHeader extends TLObject { + + public int flags; + public boolean modified; + public TLRPC.Peer from; + public String from_name; + public int story_id; + + public static StoryFwdHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryFwdHeader result = null; + switch (constructor) { + case TL_storyFwdHeader.constructor: + result = new TL_storyFwdHeader(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryFwdHeader", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_storyFwdHeader extends StoryFwdHeader { + public static final int constructor = 0xb826e150; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + modified = (flags & 8) != 0; + if ((flags & 1) != 0) { + from = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + from_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + story_id = stream.readInt32(exception); + } + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = modified ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + from.serializeToStream(stream); + } + if ((flags & 2) != 0) { + stream.writeString(from_name); + } + if ((flags & 4) != 0) { + stream.writeInt32(story_id); + } + } + } + public static class TL_storyItem extends StoryItem { - public static final int constructor = 0x44c457ce; + public static final int constructor = 0xaf6365a1; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -2003,6 +2256,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { out = (flags & 65536) != 0; id = stream.readInt32(exception); date = stream.readInt32(exception); + if ((flags & 131072) != 0) { + fwd_from = TL_storyFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } expire_date = stream.readInt32(exception); if ((flags & 1) != 0) { caption = stream.readString(exception); @@ -2081,6 +2337,9 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(flags); stream.writeInt32(id); stream.writeInt32(date); + if ((flags & 131072) != 0) { + fwd_from.serializeToStream(stream); + } stream.writeInt32(expire_date); if ((flags & 1) != 0) { stream.writeString(caption); @@ -2119,8 +2378,140 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_storyItem_layer160 extends TL_storyItem { - public static final int constructor = 0x562aa637; + public static class TL_storyItem_layer166 extends TL_storyItem { + public static final int constructor = 0x44c457ce; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 32) != 0; + isPublic = (flags & 128) != 0; + close_friends = (flags & 256) != 0; + min = (flags & 512) != 0; + noforwards = (flags & 1024) != 0; + edited = (flags & 2048) != 0; + contacts = (flags & 4096) != 0; + selected_contacts = (flags & 8192) != 0; + out = (flags & 65536) != 0; + id = stream.readInt32(exception); + date = stream.readInt32(exception); + expire_date = stream.readInt32(exception); + if ((flags & 1) != 0) { + caption = stream.readString(exception); + } + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.MessageEntity object = TLRPC.MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + media = TLRPC.MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 16384) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MediaArea object = MediaArea.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + media_areas.add(object); + } + } + if ((flags & 4) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TLRPC.PrivacyRule object = TLRPC.PrivacyRule.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + privacy.add(object); + } + } + if ((flags & 8) != 0) { + views = StoryViews.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + sent_reaction = TLRPC.Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 32) : (flags &~ 32); + flags = isPublic ? (flags | 128) : (flags &~ 128); + flags = close_friends ? (flags | 256) : (flags &~ 256); + flags = min ? (flags | 512) : (flags &~ 512); + flags = noforwards ? (flags | 1024) : (flags &~ 1024); + flags = edited ? (flags | 2048) : (flags &~ 2048); + flags = contacts ? (flags | 4096) : (flags &~ 4096); + flags = selected_contacts ? (flags | 8192) : (flags &~ 8192); + flags = out ? (flags | 65536) : (flags &~ 65536); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(date); + stream.writeInt32(expire_date); + if ((flags & 1) != 0) { + stream.writeString(caption); + } + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + media.serializeToStream(stream); + if ((flags & 16384) != 0) { + stream.writeInt32(0x1cb5c415); + int count = media_areas.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + media_areas.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + stream.writeInt32(0x1cb5c415); + int count = privacy.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + privacy.get(a).serializeToStream(stream); + } + } + if ((flags & 8) != 0) { + views.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + sent_reaction.serializeToStream(stream); + } + } + } + + public static class TL_storyItem_layer160 extends TL_storyItem { + public static final int constructor = 0x562aa637; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -2313,9 +2704,15 @@ public static MediaArea TLdeserialize(AbstractSerializedData stream, int constru 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)); @@ -2348,6 +2745,26 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -2404,6 +2821,28 @@ public void serializeToStream(AbstractSerializedData stream) { } } + 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; @@ -2459,4 +2898,281 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(date); } } + + public static class TL_stats_storyStats extends TLObject { + public final static int constructor = 0x50cd067c; + + public TLRPC.StatsGraph views_graph; + public TLRPC.StatsGraph reactions_by_emotion_graph; + + public static TL_stats_storyStats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stats_storyStats.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stats_storyStats", constructor)); + } else { + return null; + } + } + TL_stats_storyStats result = new TL_stats_storyStats(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + views_graph = TLRPC.StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + reactions_by_emotion_graph = TLRPC.StatsGraph.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + views_graph.serializeToStream(stream); + reactions_by_emotion_graph.serializeToStream(stream); + } + } + + public static class TL_stats_getStoryStats extends TLObject { + public final static int constructor = 0x374fef40; + + public int flags; + public boolean dark; + public TLRPC.InputPeer peer; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_stats_storyStats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = dark ? (flags | 1) : (flags & ~1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + } + } + + 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 8d68da578f..cf13a9afda 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; @@ -44,6 +46,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.appcompat.widget.AppCompatImageView; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; @@ -197,7 +200,7 @@ private void createBackButtonImage() { 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 -> { @@ -307,12 +310,11 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 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) { + 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); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { @@ -321,9 +323,9 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { textPaint.getTextBounds(titleView.getText().toString(), 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.setColorFilter(textPaint.getColor(), PorterDuff.Mode.MULTIPLY); drawable.draw(canvas); if (overlayTitleAnimationInProgress) { @@ -448,9 +450,9 @@ private void createTitleTextView(int i) { 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 { @@ -1233,10 +1235,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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) { @@ -1246,12 +1248,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); } @@ -1267,7 +1269,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); @@ -1294,29 +1296,29 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } 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) ); } @@ -1341,13 +1343,13 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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()); } @@ -1358,7 +1360,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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; } @@ -1367,20 +1369,20 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } } 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 ); } @@ -1500,7 +1502,7 @@ public void setTitleOverlayText(String title, int titleId, Runnable action) { 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) { @@ -1520,7 +1522,7 @@ public void setTitleOverlayText(String title, int titleId, Runnable action) { 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) { @@ -1534,7 +1536,7 @@ public void setTitleOverlayText(String title, int titleId, Runnable action) { 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) @@ -1542,7 +1544,7 @@ public void setTitleOverlayText(String title, int titleId, Runnable action) { 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); } @@ -1651,11 +1653,11 @@ public boolean onTouchEvent(MotionEvent event) { 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); } } @@ -1689,7 +1691,7 @@ public void setTitleAnimated(CharSequence title, boolean fromBottom, long durati 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) { @@ -1700,7 +1702,7 @@ public void setTitleAnimated(CharSequence title, boolean fromBottom, long durati 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); @@ -1890,7 +1892,7 @@ public void setDrawBackButton(boolean b) { private StaticLayout countLayout; - private class UnreadImageView extends ImageView { + private class UnreadImageView extends AppCompatImageView { public UnreadImageView(Context context) { super(context); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index d60f5dabc4..11ce0d2050 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -64,6 +64,7 @@ import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; import org.telegram.ui.Components.GroupCallPip; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.StoryViewer; import java.util.ArrayList; @@ -255,10 +256,27 @@ public void setFragmentPanTranslationOffset(int fragmentPanTranslationOffset) { invalidate(); } + float lastY, startY; // for menu buttons to be clicked by hover: private float pressX, pressY; private boolean allowToPressByHover; public void processMenuButtonsTouch(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + startY = event.getY(); + } + if (isInPreviewMode() && previewMenu == null) { + lastY = event.getY(); + if (event.getAction() == MotionEvent.ACTION_UP) { + finishPreviewFragment(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + float dy = startY - lastY; + movePreviewFragment(dy); + if (dy < 0) { + startY = lastY; + } + } + return; + } if (event.getAction() == MotionEvent.ACTION_DOWN) { pressX = event.getX(); pressY = event.getY(); @@ -384,6 +402,7 @@ public void processMenuButtonsTouch(MotionEvent event) { private float themeAnimationValue; private boolean animateThemeAfterAnimation; private Theme.ThemeInfo animateSetThemeAfterAnimation; + private boolean animateSetThemeAfterAnimationApply; private boolean animateSetThemeNightAfterAnimation; private int animateSetThemeAccentIdAfterAnimation; private boolean rebuildAfterAnimation; @@ -1246,14 +1265,16 @@ public boolean presentFragment(NavigationParams params) { return false; } BaseFragment lastFragment = getLastFragment(); - if (lastFragment != null && lastFragment.getVisibleDialog() != null) { - if (shouldOpenFragmentOverlay(lastFragment.getVisibleDialog())) { - BaseFragment.BottomSheetParams bottomSheetParams = new BaseFragment.BottomSheetParams(); - bottomSheetParams.transitionFromLeft = true; - bottomSheetParams.allowNestedScroll = false; - lastFragment.showAsSheet(fragment, bottomSheetParams); - return true; - } + Dialog dialog = lastFragment != null ? lastFragment.getVisibleDialog() : null; + if (dialog == null && LaunchActivity.instance != null && LaunchActivity.instance.getVisibleDialog() != null) { + dialog = LaunchActivity.instance.getVisibleDialog(); + } + if (lastFragment != null && shouldOpenFragmentOverlay(dialog)) { + BaseFragment.BottomSheetParams bottomSheetParams = new BaseFragment.BottomSheetParams(); + bottomSheetParams.transitionFromLeft = true; + bottomSheetParams.allowNestedScroll = false; + lastFragment.showAsSheet(fragment, bottomSheetParams); + return true; } if (BuildVars.LOGS_ENABLED) { FileLog.d("present fragment " + fragment.getClass().getSimpleName() + " args=" + fragment.getArguments()); @@ -1556,7 +1577,7 @@ public void run() { } private boolean shouldOpenFragmentOverlay(Dialog visibleDialog) { - return visibleDialog instanceof ChatAttachAlert || visibleDialog instanceof BotWebViewSheet; + return (visibleDialog != null && visibleDialog.isShowing()) && (visibleDialog instanceof ChatAttachAlert || visibleDialog instanceof BotWebViewSheet); } @Override @@ -1720,6 +1741,10 @@ public void onAnimationEnd(Animator animation) { 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 @@ -2072,7 +2097,7 @@ public void setThemeAnimationValue(float value) { for (int i = 0, N = presentingFragmentDescriptions.size(); i < N; i++) { ThemeDescription description = presentingFragmentDescriptions.get(i); int key = description.getCurrentKey(); - description.setColor(Theme.getColor(key), false, false); + description.setColor(Theme.getColor(key, description.resourcesProvider), false, false); } } if (animationProgressListener != null) { @@ -2124,6 +2149,7 @@ public void animateThemedValues(ThemeAnimationSettings settings, Runnable onDone animateSetThemeAfterAnimation = settings.theme; animateSetThemeNightAfterAnimation = settings.nightTheme; animateSetThemeAccentIdAfterAnimation = settings.accentId; + animateSetThemeAfterAnimationApply = settings.applyTrulyTheme; if (onDone != null) { onDone.run(); } @@ -2259,7 +2285,7 @@ public void onAnimationCancel(Animator animation) { 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 +2389,11 @@ private void checkNeedRebuild() { 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/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 01b62d38c9..aea1801ab4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -1882,6 +1882,17 @@ public void hideSubItem(int id) { } } + public boolean hasSubItem(int id) { + Item lazyItem = findLazyItem(id); + if (lazyItem != null) { + return true; + } + if (popupLayout == null) { + return false; + } + return popupLayout.findViewWithTag(id) != null; + } + /** * Hides this menu item if no subitems are available */ diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index 5e81c8c557..11c14c8797 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; @@ -768,9 +769,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 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)) { @@ -1172,6 +1176,21 @@ public void setTextColor(int color) { } } + 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; @@ -1532,6 +1551,11 @@ public Builder setView(View view, int height) { 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/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 10e2dacc5f..7b4a54e115 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -22,6 +22,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; @@ -87,7 +88,7 @@ public abstract class BaseFragment { protected boolean fragmentBeginToShow; private boolean removingFromStack; private PreviewDelegate previewDelegate; - private Theme.ResourcesProvider resourceProvider; + protected Theme.ResourcesProvider resourceProvider; public StoryViewer storyViewer; public StoryViewer overlayStoryViewer; @@ -843,7 +844,8 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams fragment.onTransitionAnimationStart(true, false); bottomSheet[0] = new BottomSheet(getParentActivity(), true, fragment.getResourceProvider()) { { - drawNavigationBar = true; + occupyNavigationBar = params != null && params.occupyNavigationBar; + drawNavigationBar = !occupyNavigationBar; actionBarLayout[0].setFragmentStack(new ArrayList<>()); actionBarLayout[0].addFragmentToStack(fragment); actionBarLayout[0].showLastFragment(); @@ -864,8 +866,13 @@ public INavigationLayout[] showAsSheet(BaseFragment fragment, BottomSheetParams protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); actionBarLayout[0].setWindow(bottomSheet[0].getWindow()); - fixNavigationBar(Theme.getColor(Theme.key_dialogBackgroundGray, fragment.getResourceProvider())); + if (params == null || !params.occupyNavigationBar) { + fixNavigationBar(Theme.getColor(Theme.key_dialogBackgroundGray, fragment.getResourceProvider())); + } else { + AndroidUtilities.setLightNavigationBar(bottomSheet[0].getWindow(), true); + } AndroidUtilities.setLightStatusBar(getWindow(), fragment.isLightStatusBar()); + fragment.onBottomSheetCreated(); } @Override @@ -874,8 +881,17 @@ protected boolean canDismissWithSwipe() { } @Override - protected boolean canSwipeToBack() { - return params != null && params.transitionFromLeft && actionBarLayout[0] != null && actionBarLayout[0].getFragmentStack().size() <= 1; + protected boolean canSwipeToBack(MotionEvent event) { + if (params != null && params.transitionFromLeft && actionBarLayout[0] != null && actionBarLayout[0].getFragmentStack().size() <= 1) { + if (actionBarLayout[0].getFragmentStack().size() == 1) { + BaseFragment lastFragment = actionBarLayout[0].getFragmentStack().get(0); + if (!lastFragment.isSwipeBackEnabled(event)) { + return false; + } + } + return true; + } + return false; } @Override @@ -923,6 +939,7 @@ protected void onInsetsChanged() { bottomSheet[0].transitionFromRight(params.transitionFromLeft); } fragment.setParentDialog(bottomSheet[0]); + bottomSheet[0].setOpenNoDelay(true); bottomSheet[0].show(); return actionBarLayout; @@ -949,7 +966,7 @@ public boolean hasForceLightStatusBar() { } public int getNavigationBarColor() { - int color = Theme.getColor(Theme.key_windowBackgroundGray, resourceProvider); + int color = Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider()); if (storyViewer != null && storyViewer.attachedToParent()) { return storyViewer.getNavigationBarColor(color); } @@ -1114,12 +1131,17 @@ public StoryViewer getOrCreateOverlayStoryViewer() { return overlayStoryViewer; } + public void onBottomSheetCreated() { + + } + public static class BottomSheetParams { public boolean transitionFromLeft; public boolean allowNestedScroll; public Runnable onDismiss; public Runnable onOpenAnimationFinished; public Runnable onPreFinished; + public boolean occupyNavigationBar; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 006d013380..79e5f3f3b9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -29,6 +29,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -114,6 +115,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) { @@ -348,6 +351,7 @@ private void cancelCurrentAnimation() { private float y = 0f; private float swipeBackX = 0f; + private boolean allowedSwipeToBack; public boolean processTouchEvent(MotionEvent ev, boolean intercept) { if (dismissed) { return false; @@ -355,8 +359,9 @@ public boolean processTouchEvent(MotionEvent ev, boolean intercept) { if (onContainerTouchEvent(ev)) { return true; } - if (canSwipeToBack()) { + if (canSwipeToBack(ev) || allowedSwipeToBack) { if (ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && (!startedTracking && !maybeStartTracking && ev.getPointerCount() == 1)) { + allowedSwipeToBack = true; startedTrackingX = (int) ev.getX(); startedTrackingY = (int) ev.getY(); startedTrackingPointerId = ev.getPointerId(0); @@ -424,6 +429,7 @@ public void onAnimationEnd(Animator animation) { maybeStartTracking = false; startedTracking = false; startedTrackingPointerId = -1; + allowedSwipeToBack = false; } } else { if (canDismissWithTouchOutside() && ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && (!startedTracking && !maybeStartTracking && ev.getPointerCount() == 1)) { @@ -440,7 +446,7 @@ public void onAnimationEnd(Animator animation) { if (velocityTracker != null) { velocityTracker.clear(); } - } else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { + } else if (canDismissWithSwipe() && ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } @@ -480,7 +486,7 @@ public void onAnimationEnd(Animator animation) { startedTrackingPointerId = -1; } } - return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack()); + return (!intercept && maybeStartTracking) || startedTracking || !(canDismissWithSwipe() || canSwipeToBack(ev)); } @Override @@ -572,7 +578,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto right -= getRightInset(); if (useSmoothKeyboard) { t = 0; - } else { + } else if (!occupyNavigationBar) { t -= lastInsets.getSystemWindowInsetBottom() * (1f - hideSystemVerticalInsetsProgress) - (drawNavigationBar ? 0 : getBottomInset()); if (Build.VERSION.SDK_INT >= 29) { t -= getAdditionalMandatoryOffsets(); @@ -674,7 +680,7 @@ public void onAnimationEnd(Animator animation) { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (canDismissWithSwipe() || canSwipeToBack()) { + if (canDismissWithSwipe() || canSwipeToBack(event)) { return processTouchEvent(event, true); } return super.onInterceptTouchEvent(event); @@ -764,7 +770,7 @@ protected void onDraw(Canvas canvas) { restore = true; } super.onDraw(canvas); - if (lastInsets != null && keyboardHeight != 0) { + if (drawNavigationBar && lastInsets != null && keyboardHeight != 0) { backgroundPaint.setColor(behindKeyboardColorKey >= 0 ? getThemedColor(behindKeyboardColorKey) : behindKeyboardColor); canvas.drawRect(containerView.getLeft() + backgroundPaddingLeft, getMeasuredHeight() - keyboardHeight - (drawNavigationBar ? getBottomInset() : 0), containerView.getRight() - backgroundPaddingLeft, getMeasuredHeight() - (drawNavigationBar ? getBottomInset() : 0), backgroundPaint); } @@ -901,7 +907,9 @@ public BottomSheetCell(Context context, int type, Theme.ResourcesProvider resour 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); @@ -914,7 +922,7 @@ public BottomSheetCell(Context context, int type, Theme.ResourcesProvider resour 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)); @@ -1121,7 +1129,7 @@ public void fixNavigationBar() { } public void fixNavigationBar(int bgColor) { - drawNavigationBar = true; + drawNavigationBar = !occupyNavigationBar; drawDoubleNavigationBar = true; scrollNavBar = true; navBarColorKey = -1; @@ -1243,7 +1251,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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; @@ -1337,7 +1345,10 @@ public void show() { } dismissed = false; cancelSheetAnimation(); - containerView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x + backgroundPaddingLeft * 2, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); + containerView.measure( + View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x + backgroundPaddingLeft * 2, View.MeasureSpec.AT_MOST), + View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST) + ); if (showWithoutAnimation) { backDrawable.setAlpha(dimBehind ? dimBehindAlpha : 0); containerView.setTranslationY(0); @@ -1624,7 +1635,7 @@ public void dismissWithButtonClick(final int item) { 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 @@ -1659,6 +1670,27 @@ public void onAnimationCancel(Animator animation) { }); 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 @@ -1678,7 +1710,7 @@ public int getContainerViewHeight() { return containerView.getMeasuredHeight(); } - protected boolean canSwipeToBack() { + protected boolean canSwipeToBack(MotionEvent event) { return false; } @@ -1803,6 +1835,8 @@ protected boolean onCustomOpenAnimation() { public static class Builder { + public static int CELL_TYPE_CALL = 4; + private BottomSheet bottomSheet; public Builder(Context context) { @@ -1870,6 +1904,16 @@ public Builder setTitle(CharSequence title, boolean big) { 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 33922de823..bc9282cb74 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 SparseIntArray getPreviewColors(int currentAccount, int index) { } 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 SparseIntArray getPreviewColors(int currentAccount, int index) { } } + 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 df3f19d93b..2722ae095c 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 @@ private void layoutOverflowPanelItems(List menuItems) { }); } 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 d064757430..41e3ed3dc5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/INavigationLayout.java @@ -369,6 +369,7 @@ class ThemeAnimationSettings { 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 f251f6d383..dfbf64e071 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -66,6 +66,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; @@ -278,6 +279,10 @@ public int getSideDrawablesSize() { int dw = (int) (rightDrawable.getIntrinsicWidth() * rightDrawableScale); size += dw + drawablePadding; } + if (rightDrawable2 != null) { + int dw = (int) (rightDrawable2.getIntrinsicWidth() * rightDrawableScale); + size += dw + drawablePadding; + } return size; } @@ -348,6 +353,11 @@ protected boolean createLayout(int width) { 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) { @@ -373,7 +383,7 @@ protected boolean createLayout(int width) { string = TextUtils.ellipsize(string, textPaint, width, TextUtils.TruncateAt.END); } if (!ellipsizeByGradient && !string.equals(text)) { - fullLayout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, fullTextMaxLines, false); + fullLayout = StaticLayoutEx.createStaticLayout(text, textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, fullTextMaxLines, false); if (fullLayout != null) { int end = fullLayout.getLineEnd(0); int start = fullLayout.getLineStart(1); @@ -392,7 +402,7 @@ protected boolean createLayout(int width) { part = "\u200F" + part; } partLayout = new StaticLayout(part, 0, part.length(), textPaint, scrollNonFitText ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), getAlignment(), 1.0f, 0.0f, false); - fullLayout = StaticLayoutEx.createStaticLayout(full, 0, full.length(), textPaint, width + AndroidUtilities.dp(8) + fullLayoutAdditionalWidth, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, fullTextMaxLines, false); + fullLayout = StaticLayoutEx.createStaticLayout(full, textPaint, width + AndroidUtilities.dp(8) + fullLayoutAdditionalWidth, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width + fullLayoutAdditionalWidth, fullTextMaxLines, false); } } else { layout = new StaticLayout(string, 0, string.length(), textPaint, scrollNonFitText || ellipsizeByGradient ? AndroidUtilities.dp(2000) : width + AndroidUtilities.dp(8), getAlignment(), 1.0f, 0.0f, false); @@ -401,7 +411,7 @@ protected boolean createLayout(int width) { firstLineLayout = null; } } else if (maxLines > 1) { - layout = StaticLayoutEx.createStaticLayout(text, 0, text.length(), textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, maxLines, false); + layout = StaticLayoutEx.createStaticLayout(text, textPaint, width, getAlignment(), 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width, maxLines, false); } else { CharSequence string; if (scrollNonFitText || ellipsizeByGradient) { @@ -456,7 +466,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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) { @@ -466,7 +476,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } 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); @@ -555,7 +565,7 @@ public void setLeftDrawable(Drawable drawable) { @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) { @@ -605,6 +615,26 @@ public void setRightDrawable(Drawable drawable) { } } + 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; } @@ -723,6 +753,11 @@ public void setRightPadding(int padding) { 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(); @@ -814,6 +849,27 @@ protected void onDraw(Canvas canvas) { 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) { @@ -841,6 +897,22 @@ protected void onDraw(Canvas canvas) { 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) { @@ -945,6 +1017,25 @@ protected void onDraw(Canvas canvas) { 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() { @@ -956,7 +1047,7 @@ public int getRightDrawableY() { } 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) { @@ -1041,6 +1132,8 @@ public void invalidateDrawable(Drawable who) { 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 f5ea3582b4..0f53931c93 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -129,12 +129,13 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.RoundVideoProgressShadow; import org.telegram.ui.ThemeActivity; -import org.telegram.messenger.support.SparseLongArray; +import org.telegram.ui.ThemePreviewActivity; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; @@ -963,7 +964,7 @@ private void generatePath(Path path, Rect bounds, int padding, int rad, int smal } 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); @@ -1460,7 +1461,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -1473,7 +1474,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA if (color == 0) { color = defaultColors[key_chat_outBubble]; } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); int distance1 = AndroidUtilities.getColorDistance(firstColor, newColor); int distance2 = AndroidUtilities.getColorDistance(firstColor, myMessagesGradientAccentColor1); @@ -1515,7 +1516,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -1535,7 +1536,7 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA } else { color = currentColorsNoAccent.valueAt(index); } - int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme); + int newColor = changeColorAccent(hsvTemp1, hsvTemp2, color, isDarkTheme, color); if (newColor != color) { currentColors.put(key, newColor); } @@ -1754,7 +1755,6 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA 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); @@ -2001,7 +2001,9 @@ public static int adaptHue(int color, int hueFromColor) { public static int adaptHSV(int color, float sat, float val) { float[] tempHSV = getTempHsv(5); Color.colorToHSV(color, tempHSV); - tempHSV[1] = MathUtils.clamp(tempHSV[1] + sat, 0, 1); + if (tempHSV[1] > .1f && tempHSV[1] < .9f) { // otherwise, saturation would reveal some random hue there + tempHSV[1] = MathUtils.clamp(tempHSV[1] + sat, 0, 1); + } tempHSV[2] = MathUtils.clamp(tempHSV[2] + val, 0, 1); return Color.HSVToColor(Color.alpha(color), tempHSV); } @@ -2052,6 +2054,7 @@ public static class OverrideWallpaperInfo { public long wallpaperId; public long accessHash; public long dialogId; + public boolean forBoth; public ThemeInfo parentTheme; public ThemeAccent parentAccent; @@ -2982,6 +2985,12 @@ default boolean hasGradientService() { return false; } + default boolean isDark() { + // used only in PeerColorActivity + // support in other implementations to use + return Theme.isCurrentThemeDark(); + } + default void applyServiceShaderMatrix(int w, int h, float translationX, float translationY) { Theme.applyServiceShaderMatrix(w, h, translationX, translationY); } @@ -3083,8 +3092,6 @@ public void run() { private static int serviceSelectedMessageColor; public static int serviceMessageColorBackup; public static int serviceSelectedMessageColorBackup; - private static int serviceMessage2Color; - private static int serviceSelectedMessage2Color; public static int currentColor; private static Drawable wallpaper; private static Drawable themedWallpaper; @@ -3103,7 +3110,7 @@ public void run() { public static Paint avatar_backgroundPaint; public static Drawable listSelector; - public static Drawable[] avatarDrawables = new Drawable[17]; + public static Drawable[] avatarDrawables = new Drawable[18]; public static Drawable moveUpDrawable; @@ -3189,8 +3196,6 @@ public void run() { public static Paint chat_messageBackgroundSelectedPaint; public static Paint chat_actionBackgroundPaint; public static Paint chat_actionBackgroundSelectedPaint; - public static Paint chat_actionBackgroundPaint2; - public static Paint chat_actionBackgroundSelectedPaint2; public static Paint chat_actionBackgroundGradientDarkenPaint; public static Paint chat_timeBackgroundPaint; public static Paint chat_composeBackgroundPaint; @@ -3306,6 +3311,7 @@ public void run() { public static Drawable chat_contextResult_shadowUnderSwitchDrawable; public static Drawable chat_shareIconDrawable; public static Drawable chat_replyIconDrawable; + public static Drawable chat_closeIconDrawable; public static Drawable chat_goIconDrawable; public static Drawable chat_botLinkDrawable; public static Drawable chat_botCardDrawable; @@ -4135,7 +4141,6 @@ public void run() { 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++; @@ -4191,6 +4196,7 @@ public void run() { public static final String key_drawable_msgStickerViews = "drawableMsgStickerViews"; public static final String key_drawable_replyIcon = "drawableReplyIcon"; public static final String key_drawable_shareIcon = "drawableShareIcon"; + public static final String key_drawable_closeIcon = "drawableCloseIcon"; public static final String key_drawable_muteIconDrawable = "drawableMuteIcon"; public static final String key_drawable_lockIconDrawable = "drawableLockIcon"; public static final String key_drawable_chat_pollHintDrawableOut = "drawable_chat_pollHintDrawableOut"; @@ -4200,6 +4206,7 @@ public void run() { private static final HashMap defaultChatDrawableColorKeys = new HashMap<>(); public static final String key_paint_chatActionBackground = "paintChatActionBackground"; + public static final String key_paint_chatActionBackgroundDarken = "paintChatActionBackgroundDarken"; public static final String key_paint_chatActionBackgroundSelected = "paintChatActionBackgroundSelected"; public static final String key_paint_chatMessageBackgroundSelected = "paintChatMessageBackgroundSelected"; public static final String key_paint_chatActionText = "paintChatActionText"; @@ -4219,11 +4226,11 @@ public void run() { private static SparseIntArray animatingColors; private static boolean shouldDrawGradientIcons; - private static ThreadLocal hsvTemp1Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp2Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp3Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp4Local = new ThreadLocal<>(); - private static ThreadLocal hsvTemp5Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp1Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp2Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp3Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp4Local = new ThreadLocal<>(); + private static final ThreadLocal hsvTemp5Local = new ThreadLocal<>(); private static FragmentContextViewWavesDrawable fragmentContextViewWavesDrawable; private static RoundVideoProgressShadow roundPlayDrawable; @@ -4418,6 +4425,7 @@ public void run() { 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); @@ -4532,7 +4540,7 @@ public void run() { new int[] { 0, 52, 46, 57, 45, 64, 52, 35, 36, 41, 50, 50, 35, 38, 37, 30 } ); sortAccents(themeInfo); - themes.add(currentDayTheme = currentTheme = defaultTheme = themeInfo); + themes.add(currentDayTheme = defaultTheme = themeInfo); themesDict.put("Blue", themeInfo); themeInfo = new ThemeInfo(); @@ -5409,6 +5417,14 @@ public static Drawable createServiceDrawable(int rad, View view, View containerV } public static Drawable createServiceDrawable(int rad, View view, View containerView, Paint backgroundPaint) { + return createServiceDrawable(rad, view, containerView, backgroundPaint, null); + } + + public static Drawable createServiceDrawable(int rad, View view, View containerView, Theme.ResourcesProvider resourcesProvider) { + return createServiceDrawable(rad, view, containerView, null, resourcesProvider); + } + + public static Drawable createServiceDrawable(int rad, View view, View containerView, Paint backgroundPaint, Theme.ResourcesProvider resourcesProvider) { return new Drawable() { private RectF rect = new RectF(); @@ -5418,9 +5434,9 @@ public void draw(@NonNull Canvas canvas) { Rect bounds = getBounds(); rect.set(bounds.left, bounds.top, bounds.right, bounds.bottom); applyServiceShaderMatrixForView(view, containerView); - canvas.drawRoundRect(rect, rad, rad, backgroundPaint); - if (hasGradientService()) { - canvas.drawRoundRect(rect, rad, rad, chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, rad, rad, backgroundPaint != null ? backgroundPaint : Theme.getThemePaint(Theme.key_paint_chatActionBackground, resourcesProvider)); + if (resourcesProvider != null ? resourcesProvider.hasGradientService() : hasGradientService()) { + canvas.drawRoundRect(rect, rad, rad, Theme.getThemePaint(Theme.key_paint_chatActionBackgroundDarken, resourcesProvider)); } } @@ -5858,7 +5874,7 @@ private static Drawable createRect(Drawable background, int rippleColor, float . 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); @@ -5892,7 +5908,7 @@ private static Drawable createCircle(Drawable background, int rippleColor, float } 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); @@ -6661,6 +6677,24 @@ public static void refreshThemeColors(boolean bg, boolean messages) { AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewTheme, false, checkNavigationBarColor)); } + public static boolean hasHue(int color) { + float[] hsvTemp3 = getTempHsv(3); + Color.colorToHSV(color, hsvTemp3); + return hsvTemp3[1] > .1f && hsvTemp3[1] < .9f; + } + + public static int changeColorAccent(int themeBaseAccent, int accent, int color, boolean isDark) { + return changeColorAccent(themeBaseAccent, accent, color, isDark, color); + } + + public static int changeColorAccent(int themeBaseAccent, int accent, int color, boolean isDark, int fallback) { + float[] hsvTemp3 = getTempHsv(3); + float[] hsvTemp4 = getTempHsv(4); + Color.colorToHSV(themeBaseAccent, hsvTemp3); + Color.colorToHSV(accent, hsvTemp4); + return changeColorAccent(hsvTemp3, hsvTemp4, color, isDark, fallback); + } + public static int changeColorAccent(ThemeInfo themeInfo, int accent, int color) { if (accent == 0 || themeInfo.accentBaseColor == 0 || accent == themeInfo.accentBaseColor || themeInfo.firstAccentIsDefault && themeInfo.currentAccentId == DEFALT_THEME_ACCENT_ID) { return color; @@ -6670,7 +6704,7 @@ public static int changeColorAccent(ThemeInfo themeInfo, int accent, int color) Color.colorToHSV(themeInfo.accentBaseColor, hsvTemp3); Color.colorToHSV(accent, hsvTemp4); - return changeColorAccent(hsvTemp3, hsvTemp4, color, themeInfo.isDark()); + return changeColorAccent(hsvTemp3, hsvTemp4, color, themeInfo.isDark(), color); } public static float[] getTempHsv(int num) { @@ -6728,7 +6762,7 @@ private static float abs(float a) { } private static float[] tmpHSV5; - public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int color, boolean isDarkTheme) { + public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int color, boolean isDarkTheme, int fallback) { if (tmpHSV5 == null) { tmpHSV5 = new float[3]; } @@ -6737,7 +6771,7 @@ public static int changeColorAccent(float[] baseHsv, float[] accentHsv, int colo final float diffH = Math.min(abs(colorHsv[0] - baseHsv[0]), abs(colorHsv[0] - baseHsv[0] - 360f)); if (diffH > 30f) { - return color; + return fallback; } float dist = Math.min(1.5f * colorHsv[1] / baseHsv[1], 1f); @@ -8230,6 +8264,7 @@ public static void createCommonResources(Context context) { avatarDrawables[14] = resources.getDrawable(R.drawable.filled_gift_premium); avatarDrawables[15] = resources.getDrawable(R.drawable.filled_unknown); avatarDrawables[16] = resources.getDrawable(R.drawable.filled_unclaimed); + avatarDrawables[17] = resources.getDrawable(R.drawable.large_repost_story); if (dialogs_archiveAvatarDrawable != null) { dialogs_archiveAvatarDrawable.setCallback(null); @@ -8635,7 +8670,7 @@ public static void createCommonChatResources() { chat_unlockExtendedMediaTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_unlockExtendedMediaTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundGradientDarkenPaint.setColor(0x2a000000); + chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); chat_timeBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_contextResult_titleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -8645,13 +8680,12 @@ public static void createCommonChatResources() { chat_radialProgressPausedSeekbarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); chat_messageBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); - chat_actionBackgroundSelectedPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); addChatPaint(key_paint_chatMessageBackgroundSelected, chat_messageBackgroundSelectedPaint, key_chat_selectedBackground); addChatPaint(key_paint_chatActionBackground, chat_actionBackgroundPaint, key_chat_serviceBackground); + addChatPaint(key_paint_chatActionBackgroundDarken, chat_actionBackgroundGradientDarkenPaint, key_chat_serviceBackground); addChatPaint(key_paint_chatActionBackgroundSelected, chat_actionBackgroundSelectedPaint, key_chat_serviceBackgroundSelected); addChatPaint(key_paint_chatActionText, chat_actionTextPaint, key_chat_serviceText); addChatPaint(key_paint_chatActionText2, chat_actionTextPaint2, key_chat_serviceText); @@ -8779,6 +8813,7 @@ public static void createChatResources(Context context, boolean fontsOnly) { chat_shareIconDrawable = resources.getDrawable(R.drawable.filled_button_share).mutate(); chat_replyIconDrawable = resources.getDrawable(R.drawable.filled_button_reply); + chat_closeIconDrawable = resources.getDrawable(R.drawable.msg_voiceclose).mutate(); chat_goIconDrawable = resources.getDrawable(R.drawable.message_arrow); int rad = AndroidUtilities.dp(2); @@ -8873,6 +8908,7 @@ public static void createChatResources(Context context, boolean fontsOnly) { addChatDrawable(key_drawable_msgStickerReplies, chat_msgStickerRepliesDrawable, key_chat_serviceText); addChatDrawable(key_drawable_msgStickerViews, chat_msgStickerViewsDrawable, key_chat_serviceText); addChatDrawable(key_drawable_replyIcon, chat_replyIconDrawable, key_chat_serviceIcon); + addChatDrawable(key_drawable_closeIcon, chat_closeIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_shareIcon, chat_shareIconDrawable, key_chat_serviceIcon); addChatDrawable(key_drawable_muteIconDrawable, chat_muteIconDrawable, key_chat_muteIcon); addChatDrawable(key_drawable_lockIconDrawable, chat_lockIconDrawable, key_chat_lockIcon); @@ -9126,6 +9162,18 @@ public static void applyServiceShaderMatrixForView(View view, View background, R int x = viewPos[0]; int y = viewPos[1]; background.getLocationOnScreen(viewPos); + if (background instanceof ThemePreviewActivity.BackgroundView) { + if (serviceBitmap != null) { + float bitmapWidth = serviceBitmap.getWidth(); + float bitmapHeight = serviceBitmap.getHeight(); + float maxScale = Math.max(background.getMeasuredWidth() / bitmapWidth, background.getMeasuredHeight() / bitmapHeight); + float width = bitmapWidth * maxScale; + x += ((background.getMeasuredWidth() - width) / 2) -((ThemePreviewActivity.BackgroundView) background).tx; + } else { + x += -((ThemePreviewActivity.BackgroundView) background).tx; + } + y += -((ThemePreviewActivity.BackgroundView) background).ty; + } if (resourcesProvider != null) { resourcesProvider.applyServiceShaderMatrix(background.getMeasuredWidth(), background.getMeasuredHeight(), x, y - viewPos[1]); } else { @@ -9138,7 +9186,7 @@ public static void applyServiceShaderMatrix(int w, int h, float translationX, fl } public static void applyServiceShaderMatrix(Bitmap bitmap, BitmapShader shader, Matrix matrix, int w, int h, float translationX, float translationY) { - if (shader == null) { + if (shader == null || matrix == null) { return; } @@ -9165,40 +9213,44 @@ public static void applyChatServiceMessageColor(int[] custom, Drawable wallpaper return; } int serviceColor; - int serviceColor2; int servicePressedColor; - int servicePressedColor2; serviceMessageColor = serviceMessageColorBackup; serviceSelectedMessageColor = serviceSelectedMessageColorBackup; if (custom != null && custom.length >= 2) { - serviceColor2 = serviceColor = custom[0]; - servicePressedColor2 = servicePressedColor = custom[1]; + serviceColor = custom[0]; + servicePressedColor = custom[1]; serviceMessageColor = custom[0]; serviceSelectedMessageColor = custom[1]; } else { int serviceIndex = currentColors.indexOfKey(key_chat_serviceBackground); if (serviceIndex >= 0) { - serviceColor2 = serviceColor = currentColors.valueAt(serviceIndex); + serviceColor = currentColors.valueAt(serviceIndex); } else { serviceColor = serviceMessageColor; - serviceColor2 = serviceMessage2Color; } int servicePressedIndex = currentColors.indexOfKey(key_chat_serviceBackgroundSelected); if (servicePressedIndex >= 0) { - servicePressedColor2 = servicePressedColor = currentColors.valueAt(servicePressedIndex); + servicePressedColor = currentColors.valueAt(servicePressedIndex); } else { servicePressedColor = serviceSelectedMessageColor; - servicePressedColor2 = serviceSelectedMessage2Color; } } Drawable drawable = wallpaperOverride != null ? wallpaperOverride : currentWallpaper; - boolean drawServiceGradient = drawable instanceof MotionBackgroundDrawable && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); + boolean drawServiceGradient = (drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); if (drawServiceGradient) { - Bitmap newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + Bitmap newBitmap = null; + if (drawable instanceof MotionBackgroundDrawable) { + newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + } else if (drawable instanceof BitmapDrawable) { + newBitmap = checkBlur(drawable); + } if (serviceBitmap != newBitmap) { serviceBitmap = newBitmap; serviceBitmapShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceBitmapShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } if (serviceBitmapMatrix == null) { serviceBitmapMatrix = new Matrix(); } @@ -9247,28 +9299,85 @@ public static void applyChatServiceMessageColor(int[] custom, Drawable wallpaper chat_actionBackgroundPaint.setColor(serviceColor); chat_actionBackgroundSelectedPaint.setColor(servicePressedColor); - chat_actionBackgroundPaint2.setColor(serviceColor2); currentColor = serviceColor; - if (serviceBitmapShader != null && (currentColors.indexOfKey(key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable)) { + if (serviceBitmapShader != null && (currentColors.indexOfKey(key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable)) { ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(((MotionBackgroundDrawable) drawable).getIntensity() >= 0 ? 1.8f : 0.5f); + if (drawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); + if (intensity >= 0) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? +.12f : -.06f); + } else { + colorMatrix.setSaturation(1.1f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .4f : .8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? +.08f : -.06f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .9f : .84f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? -.04f : +.06f); + } + chat_actionBackgroundPaint.setFilterBitmap(true); chat_actionBackgroundPaint.setShader(serviceBitmapShader); chat_actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); - chat_actionBackgroundPaint.setAlpha(127); + chat_actionBackgroundPaint.setAlpha(0xff); + chat_actionBackgroundSelectedPaint.setFilterBitmap(true); chat_actionBackgroundSelectedPaint.setShader(serviceBitmapShader); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.26f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isCurrentThemeDark() ? .92f : .92f); chat_actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); - chat_actionBackgroundSelectedPaint.setAlpha(200); + chat_actionBackgroundSelectedPaint.setAlpha(0xff); + + chat_actionBackgroundGradientDarkenPaint.setAlpha(0); } else { chat_actionBackgroundPaint.setColorFilter(null); chat_actionBackgroundPaint.setShader(null); chat_actionBackgroundSelectedPaint.setColorFilter(null); chat_actionBackgroundSelectedPaint.setShader(null); + + chat_actionBackgroundGradientDarkenPaint.setAlpha(0x15); } } + private static WeakReference lastDrawableToBlur; + private static Bitmap blurredBitmap; + private static Bitmap checkBlur(Drawable d) { + if (lastDrawableToBlur != null && lastDrawableToBlur.get() == d) { + return blurredBitmap; + } + if (lastDrawableToBlur != null) { + lastDrawableToBlur.clear(); + } + lastDrawableToBlur = null; + if (d == null || d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) { + return blurredBitmap = null; + } + lastDrawableToBlur = new WeakReference<>(d); + + final int h = 24; + final int w = (int) ((float) d.getIntrinsicWidth() / d.getIntrinsicHeight() * h); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + d.setBounds(0, 0, w, h); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + final ColorFilter wasColorFilter = d.getColorFilter(); + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(1.3f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .94f); + d.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + d.draw(new Canvas(bitmap)); + d.setColorFilter(wasColorFilter); + } else { + d.draw(new Canvas(bitmap)); + } + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + return blurredBitmap = bitmap; + } + public static void applyChatMessageSelectedBackgroundColor() { applyChatMessageSelectedBackgroundColor(null, wallpaper); } @@ -9417,7 +9526,7 @@ public static int getDefaultAccentColor(int key) { float[] hsvTemp2 = getTempHsv(2); Color.colorToHSV(currentTheme.accentBaseColor, hsvTemp1); Color.colorToHSV(accent.accentColor, hsvTemp2); - return changeColorAccent(hsvTemp1, hsvTemp2, color, currentTheme.isDark()); + return changeColorAccent(hsvTemp1, hsvTemp2, color, currentTheme.isDark(), color); } return 0; } @@ -9699,8 +9808,6 @@ private static void calcBackgroundColor(Drawable drawable, int save) { int[] result = AndroidUtilities.calcDrawableColor(drawable); serviceMessageColor = serviceMessageColorBackup = result[0]; serviceSelectedMessageColor = serviceSelectedMessageColorBackup = result[1]; - serviceMessage2Color = result[2]; - serviceSelectedMessage2Color = result[3]; } } @@ -9783,7 +9890,8 @@ private static Drawable loadWallpaperInternal(OverrideWallpaperInfo overrideWall hasPreviousTheme, isApplyingAccent, wallpaperMotion, - finalWallpaperDocument + finalWallpaperDocument, + false ); isWallpaperMotion = settings.isWallpaperMotion != null ? settings.isWallpaperMotion : isWallpaperMotion; isPatternWallpaper = settings.isPatternWallpaper != null ? settings.isPatternWallpaper : isPatternWallpaper; @@ -9792,6 +9900,7 @@ private static Drawable loadWallpaperInternal(OverrideWallpaperInfo overrideWall wallpaper = settings.wallpaper != null ? settings.wallpaper : wallpaper; Drawable drawable = settings.wallpaper; calcBackgroundColor(drawable, 1); + applyChatServiceMessageColor(); return drawable; } @@ -9800,7 +9909,8 @@ public static BackgroundDrawableSettings createBackgroundDrawable( ThemeInfo currentTheme, SparseIntArray currentColors, String wallpaperLink, - int prevoiusPhase + int prevoiusPhase, + boolean local ) { boolean defaultTheme = currentTheme.firstAccentIsDefault && currentTheme.currentAccentId == DEFALT_THEME_ACCENT_ID; ThemeAccent accent = currentTheme.getAccent(false); @@ -9812,7 +9922,7 @@ public static BackgroundDrawableSettings createBackgroundDrawable( : (int) (accent != null ? (accent.patternIntensity * 100) : currentTheme.patternIntensity); int wallpaperFileOffset = currentColorsNoAccent.get(key_wallpaperFileOffset, -1); - return createBackgroundDrawable(currentTheme, overrideWallpaper, currentColors, wallpaperFile, wallpaperLink, wallpaperFileOffset, intensity, prevoiusPhase, defaultTheme, false, false, wallpaperMotion, null); + return createBackgroundDrawable(currentTheme, overrideWallpaper, currentColors, wallpaperFile, wallpaperLink, wallpaperFileOffset, intensity, prevoiusPhase, defaultTheme, false, false, wallpaperMotion, null, local); } public static BackgroundDrawableSettings createBackgroundDrawable( @@ -9828,10 +9938,11 @@ public static BackgroundDrawableSettings createBackgroundDrawable( boolean hasPreviousTheme, boolean isApplyingAccent, boolean wallpaperMotion, - TLRPC.Document wallpaperDocument + TLRPC.Document wallpaperDocument, + boolean local ) { BackgroundDrawableSettings settings = new BackgroundDrawableSettings(); - settings.wallpaper = wallpaper; + settings.wallpaper = local ? null : wallpaper; boolean overrideTheme = (!hasPreviousTheme || isApplyingAccent) && overrideWallpaper != null; if (overrideWallpaper != null) { settings.isWallpaperMotion = overrideWallpaper.isMotion; @@ -9887,9 +9998,13 @@ public static BackgroundDrawableSettings createBackgroundDrawable( 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 cff3015529..9c6138cd6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -775,8 +775,7 @@ public static int[] createDefaultColors() { 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; @@ -1373,7 +1372,7 @@ public static SparseArray createColorKeysMap() { colorKeysMap.put(key_voipgroup_overlayAlertGradientUnmuted, "voipgroup_overlayAlertGradientUnmuted"); colorKeysMap.put(key_voipgroup_overlayAlertGradientUnmuted2, "voipgroup_overlayAlertGradientUnmuted2"); colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin, "voipgroup_overlayAlertMutedByAdmin"); - colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin2, "kvoipgroup_overlayAlertMutedByAdmin2"); + colorKeysMap.put(key_voipgroup_overlayAlertMutedByAdmin2, "voipgroup_overlayAlertMutedByAdmin2"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient, "voipgroup_mutedByAdminGradient"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient2, "voipgroup_mutedByAdminGradient2"); colorKeysMap.put(key_voipgroup_mutedByAdminGradient3, "voipgroup_mutedByAdminGradient3"); @@ -1521,7 +1520,6 @@ public static SparseArray createColorKeysMap() { 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/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index e3caa36118..476e528ea5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -114,6 +114,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private Runnable cancelShowMoreAnimation; private ArrayList filterDialogIds; private final DialogsActivity dialogsActivity; + private final Theme.ResourcesProvider resourcesProvider; private int currentAccount = UserConfig.selectedAccount; @@ -165,11 +166,13 @@ public static class CategoryAdapterRecycler extends RecyclerListView.SelectionAd private final int currentAccount; private boolean drawChecked; private boolean forceDarkTheme; + private Theme.ResourcesProvider resourcesProvider; - public CategoryAdapterRecycler(Context context, int account, boolean drawChecked) { + public CategoryAdapterRecycler(Context context, int account, boolean drawChecked, Theme.ResourcesProvider resourcesProvider) { this.drawChecked = drawChecked; mContext = context; currentAccount = account; + this.resourcesProvider = resourcesProvider; } public void setIndex(int value) { @@ -178,7 +181,7 @@ public void setIndex(int value) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - HintDialogCell cell = new HintDialogCell(mContext, drawChecked); + HintDialogCell cell = new HintDialogCell(mContext, drawChecked, resourcesProvider); cell.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(80), AndroidUtilities.dp(86))); return new RecyclerListView.Holder(cell); } @@ -246,9 +249,10 @@ private boolean filter(Object obj) { return false; } - public DialogsSearchAdapter(Context context, DialogsActivity dialogsActivity, int messagesSearch, int type, DefaultItemAnimator itemAnimator, boolean allowGlobalSearch) { + public DialogsSearchAdapter(Context context, DialogsActivity dialogsActivity, int messagesSearch, int type, DefaultItemAnimator itemAnimator, boolean allowGlobalSearch, Theme.ResourcesProvider resourcesProvider) { this.itemAnimator = itemAnimator; this.dialogsActivity = dialogsActivity; + this.resourcesProvider = resourcesProvider; searchAdapterHelper = new SearchAdapterHelper(false) { @Override protected boolean filter(TLObject obj) { @@ -1420,7 +1424,7 @@ public boolean supportsPredictiveItemAnimations() { layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); //horizontalListView.setDisallowInterceptTouchEvents(true); - horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false)); + horizontalListView.setAdapter(new CategoryAdapterRecycler(mContext, currentAccount, false, resourcesProvider)); horizontalListView.setOnItemClickListener((view1, position) -> { if (delegate != null) { delegate.didPressedOnSubDialog((Long) view1.getTag()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java new file mode 100644 index 0000000000..ef6c0614fb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/AvatarSpan.java @@ -0,0 +1,82 @@ +package org.telegram.ui; + + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.style.ReplacementSpan; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.ImageReceiver; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AvatarDrawable; + +public class AvatarSpan extends ReplacementSpan { + + private final Paint shadowPaint; + private final ImageReceiver imageReceiver; + private final AvatarDrawable avatarDrawable; + private final int sz; + private final int currentAccount; + + public AvatarSpan(View parent, int currentAccount, int sz) { + this.currentAccount = currentAccount; + this.imageReceiver = new ImageReceiver(parent); + this.avatarDrawable = new AvatarDrawable(); + imageReceiver.setRoundRadius(dp(sz)); + this.sz = sz; + + this.shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + shadowPaint.setShadowLayer(dp(1), 0, dp(.66f), 0x33000000); + + if (parent != null && parent.isAttachedToWindow()) { + imageReceiver.onAttachedToWindow(); + } + if (parent != null) { + parent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(@NonNull View v) { + imageReceiver.onAttachedToWindow(); + } + + @Override + public void onViewDetachedFromWindow(@NonNull View v) { + imageReceiver.onDetachedFromWindow(); + } + }); + } + } + + public void setChat(TLRPC.Chat chat) { + avatarDrawable.setInfo(currentAccount, chat); + imageReceiver.setForUserOrChat(chat, avatarDrawable); + } + + public void setUser(TLRPC.User user) { + avatarDrawable.setInfo(currentAccount, user); + imageReceiver.setForUserOrChat(user, avatarDrawable); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + return dp(sz); + } + + private float translateX, translateY; + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + canvas.drawCircle(translateX + x + dp(sz) / 2f, translateY + (top + bottom) / 2f, dp(sz) / 2f, shadowPaint); + imageReceiver.setImageCoords(translateX + x, translateY + (top + bottom) / 2f - dp(sz) / 2f, dp(sz), dp(sz)); + imageReceiver.draw(canvas); + } + + public void translate(float x, float y) { + this.translateX = x; + this.translateY = y; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 9ae45b1d84..99cb9dbced 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -3211,7 +3211,7 @@ public boolean equals(Object o) { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - if (cachedMediaLayout != null) { + if (cachedMediaLayout != null && event != null) { cachedMediaLayout.getHitRect(AndroidUtilities.rectTmp2); if (!AndroidUtilities.rectTmp2.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { return true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java index 01dfff8f5d..e0550c8053 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AccountSelectCell.java @@ -21,8 +21,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -124,7 +122,7 @@ public void setObject(TLObject object) { public void setAccount(int account, boolean check) { accountNumber = account; TLRPC.User user = UserConfig.getInstance(accountNumber).getCurrentUser(); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); textView.setText(ContactsController.formatName(user.first_name, user.last_name)); imageView.getImageReceiver().setCurrentAccount(account); imageView.setForUserOrChat(user, avatarDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java index 1bf5dd0bef..21663d3b39 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AdminedChannelCell.java @@ -88,7 +88,7 @@ public AdminedChannelCell(Context context, OnClickListener onClickListener, bool public void setChannel(TLRPC.Chat channel, boolean last) { final String url = MessagesController.getInstance(currentAccount).linkPrefix + "/"; currentChannel = channel; - avatarDrawable.setInfo(channel); + avatarDrawable.setInfo(currentAccount, channel); nameTextView.setText(channel.title); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(url + ChatObject.getPublicUsername(channel)); stringBuilder.setSpan(new URLSpanNoUnderline(""), url.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -98,7 +98,7 @@ public void setChannel(TLRPC.Chat channel, boolean last) { } public void update() { - avatarDrawable.setInfo(currentChannel); + avatarDrawable.setInfo(currentAccount, currentChannel); avatarImageView.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java index 76d2b19dc1..bcca2cbb63 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java @@ -153,7 +153,7 @@ protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 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 88fba9f53e..3276c57dc1 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; + import tw.nekomimi.nekogram.NekoConfig; public abstract class BaseCell extends ViewGroup { @@ -114,4 +117,12 @@ public boolean hasOverlappingRendering() { 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/ChannelRecommendationsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChannelRecommendationsCell.java new file mode 100644 index 0000000000..b1438fc894 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChannelRecommendationsCell.java @@ -0,0 +1,872 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.LocaleController.getString; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.graphics.text.LineBreaker; +import android.media.Image; +import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LoadingDrawable; +import org.telegram.ui.Components.Scroller; +import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.Components.Text; + +import java.util.ArrayList; + +public class ChannelRecommendationsCell { + + private ChatMessageCell cell; + public ChannelRecommendationsCell(ChatMessageCell cell) { + this.cell = cell; + this.scroller = new Scroller(cell.getContext()); + this.closeBounce = new ButtonBounce(cell); + + loading = true; + this.loadingAlpha = new AnimatedFloat(cell, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + private int currentAccount; + private long dialogId; + private MessageObject msg; + private TLRPC.Chat currentChat; + public long chatId; + + private final TextPaint serviceTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private StaticLayout serviceText; + private float serviceTextLeft, serviceTextRight; + private int serviceTextHeight; + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path backgroundPath = new Path(); + private float lastBackgroundPathExpandT = -1; + + private int blockWidth = dp(66); + private float scrollX; + private float channelsScrollWidth; + private final ArrayList channels = new ArrayList<>(); + + private final Path loadingPath = new Path(); + private LoadingDrawable loadingDrawable; + + private boolean loading; + private final AnimatedFloat loadingAlpha; + + private Text headerText; + + private final RectF backgroundBounds = new RectF(); + + private final RectF closeBounds = new RectF(); + private final ButtonBounce closeBounce; + private final Paint closePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public void setMessageObject(MessageObject messageObject) { + this.currentAccount = messageObject.currentAccount; + this.msg = messageObject; + this.dialogId = messageObject.getDialogId(); + this.currentChat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + this.chatId = -dialogId; + + serviceTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + serviceTextPaint.setTextSize(dp(14)); + serviceTextPaint.setColor(cell.getThemedColor(Theme.key_chat_serviceText)); + serviceText = new StaticLayout(getString(R.string.ChannelJoined), serviceTextPaint, msg.getMaxMessageTextWidth(), Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); + serviceTextLeft = serviceText.getWidth(); + serviceTextRight = 0; + for (int i = 0; i < serviceText.getLineCount(); ++i) { + serviceTextLeft = Math.min(serviceTextLeft, serviceText.getLineLeft(i)); + serviceTextRight = Math.max(serviceTextRight, serviceText.getLineRight(i)); + } + serviceTextHeight = serviceText.getHeight(); + + closePaint.setStyle(Paint.Style.STROKE); + closePaint.setStrokeCap(Paint.Cap.ROUND); + closePaint.setStrokeJoin(Paint.Join.ROUND); + closePaint.setColor(cell.getThemedColor(Theme.key_dialogEmptyImage)); + + cell.totalHeight = dp(4 + 3.33f + 3.33f + 4) + serviceTextHeight; + + if (headerText == null) { + headerText = new Text(getString(R.string.SimilarChannels), 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)).hackClipBounds(); + } + + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).detach(); + } + channels.clear(); + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(-dialogId); + ArrayList chats = rec == null || rec.chats == null ? new ArrayList<>() : new ArrayList<>(rec.chats); + for (int i = 0; i < chats.size(); ++i) { + if (!ChatObject.isNotInChat(chats.get(i))) { + chats.remove(i); + i--; + } + } + loading = chats.isEmpty() || !UserConfig.getInstance(currentAccount).isPremium() && chats.size() == 1; + if (!loading) { + int count = chats.size(); + if (!UserConfig.getInstance(currentAccount).isPremium() && rec.more > 0) { + count = Math.min(count - 1, MessagesController.getInstance(currentAccount).recommendedChannelsLimitDefault); + } + count = Math.min(count, 10); + for (int i = 0; i < count; ++i) { + channels.add(new ChannelBlock(currentAccount, cell, chats.get(i))); + } + if (count < chats.size()) { + TLRPC.Chat[] _chats = new TLRPC.Chat[3]; + _chats[0] = count >= 0 && count < chats.size() ? chats.get(count) : null; + _chats[1] = count >= 0 && count + 1 < chats.size() ? chats.get(count + 1) : null; + _chats[2] = count >= 0 && count + 2 < chats.size() ? chats.get(count + 2) : null; + channels.add(new ChannelBlock(currentAccount, cell, _chats, (chats.size() + rec.more) - count)); + } + } + + if (isExpanded()) { + cell.totalHeight += dp(6 + 134 + 4); + backgroundPaint.setColor(cell.getThemedColor(Theme.key_chat_inBubble)); + } + + channelsScrollWidth = blockWidth * channels.size() + dp(9) * (channels.size() - 1); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth, 0); + } + + public boolean isExpanded() { + return msg.channelJoinedExpanded && channels.size() > 0; + } + + public void update() { + if (msg == null) { + return; + } + setMessageObject(msg); + cell.invalidateOutbounds(); + } + + public void onAttachedToWindow() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).attach(); + } + } + + public void onDetachedFromWindow() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).detach(); + } + } + +// public void drawText(Canvas canvas) { +// if (msg == null || cell == null) return; +// +// float y = 0; +// if (serviceText != null) { +// y += dp(4 + 3.33f + 3.33f) + serviceTextHeight; +// } +// +// float expandT; +// if (cell.transitionParams.animateRecommendationsExpanded) { +// if (isExpanded()) { +// expandT = cell.transitionParams.animateChangeProgress; +// } else { +// expandT = 1f - cell.transitionParams.animateChangeProgress; +// } +// } else { +// expandT = isExpanded() ? 1f : 0f; +// } +// expandT = Utilities.clamp((expandT - .3f) / .7f, 1, 0); +// if (expandT > 0) { +// int width = (int) Math.min(cell.getWidth() - dp(18), blockWidth * 6.5f); +// backgroundBounds.set( +// (cell.getWidth() - width) / 2f, +// y + dp(4 + 6), +// (cell.getWidth() + width) / 2f, +// y + dp(4 + 134) +// ); +// checkBackgroundPath(expandT); +// +// canvas.save(); +// final float s = .4f + .6f * expandT; +// canvas.scale(s, s, backgroundBounds.centerX(), backgroundBounds.top - dp(6)); +// +// canvas.clipPath(backgroundPath); +// +// if (headerText != null) { +// headerText.draw(canvas, backgroundBounds.left + dp(17), backgroundBounds.top + dp( 20), cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText), expandT); +// } +// +// final float loadingAlpha = this.loadingAlpha.set(loading); +// +// final float xstart = backgroundBounds.left + dp(7) - scrollX; +// final float xi = blockWidth + dp(9); +// int from = (int) Math.floor((backgroundBounds.left - width - xstart) / xi); +// int to = (int) Math.ceil((backgroundBounds.right - xstart) / xi); +// +// if (loadingAlpha < 1) { +// for (int i = Math.max(0, from); i < Math.min(to + 1, channels.size()); ++i) { +// ChannelBlock block = channels.get(i); +// +// canvas.save(); +// canvas.translate(xstart + i * xi, backgroundBounds.bottom - ChannelBlock.height()); +// block.drawText(canvas, blockWidth, expandT * (1f - loadingAlpha)); +// canvas.restore(); +// } +// } +// +// canvas.restore(); +// } +// } + + public void draw(Canvas canvas) { + if (msg == null || cell == null) return; + + computeScroll(); + + float y = 0; + if (serviceText != null) { + canvas.save(); + final float ox = (cell.getWidth() - serviceText.getWidth()) / 2f; + AndroidUtilities.rectTmp.set(ox + serviceTextLeft - dp(8.66f), dp(4), ox + serviceTextRight + dp(8.66f), dp(4 + 3.33f + 3.33f) + serviceTextHeight); + cell.drawServiceBackground(canvas, AndroidUtilities.rectTmp, dp(11), 1f); + canvas.translate(ox, dp(4 + 3.33f)); + serviceText.draw(canvas); + canvas.restore(); + + y += dp(4 + 3.33f + 3.33f) + serviceTextHeight; + } + + float expandT; + if (cell.transitionParams.animateRecommendationsExpanded) { + if (isExpanded()) { + expandT = cell.transitionParams.animateChangeProgress; + } else { + expandT = 1f - cell.transitionParams.animateChangeProgress; + } + } else { + expandT = isExpanded() ? 1f : 0f; + } + expandT = Utilities.clamp((expandT - .3f) / .7f, 1, 0); + + if (expandT > 0) { + final int cellWidth = cell.getWidth() - dp(18); + blockWidth = (int) (cellWidth > dp(66 * 6 + 9 * 5) ? dp(66) : Math.max(cellWidth / 4.5f - dp(9), dp(66))); + channelsScrollWidth = blockWidth * channels.size() + dp(9) * (channels.size() - 1); + final int width = (int) Math.min(cellWidth, blockWidth * 6.5f); + backgroundBounds.set( + (cell.getWidth() - width) / 2f, + y + dp(4 + 6), + (cell.getWidth() + width) / 2f, + y + dp(4 + 134) + ); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + checkBackgroundPath(expandT); + + canvas.save(); + final float s = .4f + .6f * expandT; + canvas.scale(s, s, backgroundBounds.centerX(), backgroundBounds.top - dp(6)); + + backgroundPaint.setAlpha((int) (0xFF * expandT)); + backgroundPaint.setShadowLayer(dpf2(1), 0, dpf2(0.33f), ColorUtils.setAlphaComponent(Color.BLACK, (int) (27 * expandT))); + canvas.drawPath(backgroundPath, backgroundPaint); + + canvas.clipPath(backgroundPath); + + if (headerText != null) { + headerText.draw(canvas, backgroundBounds.left + dp(17), backgroundBounds.top + dp( 20), cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText), expandT); + } + + final float loadingAlpha = this.loadingAlpha.set(loading); + + final float xstart = backgroundBounds.left + dp(7) - scrollX; + final float xi = blockWidth + dp(9); + int from = (int) Math.floor((backgroundBounds.left - width - xstart) / xi); + int to = (int) Math.ceil((backgroundBounds.right - xstart) / xi); + + if (loadingAlpha < 1) { + for (int i = Math.max(0, from); i < Math.min(to + 1, channels.size()); ++i) { + ChannelBlock block = channels.get(i); + + canvas.save(); + canvas.translate(xstart + i * xi, backgroundBounds.bottom - ChannelBlock.height()); + block.draw(canvas, blockWidth, expandT * (1f - loadingAlpha)); + block.drawText(canvas, blockWidth, expandT * (1f - loadingAlpha)); + canvas.restore(); + } + } + if (loadingAlpha > 0) { + loadingPath.rewind(); + for (int i = Math.max(0, from); i < to; ++i) { + ChannelBlock.fillPath(loadingPath, blockWidth, xstart + i * xi); + } + + if (loadingDrawable == null) { + loadingDrawable = new LoadingDrawable(); + loadingDrawable.usePath(loadingPath); + loadingDrawable.setAppearByGradient(false); + } + final int color = cell.getThemedColor(Theme.key_windowBackgroundWhiteBlackText); + loadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + loadingDrawable.setGradientScale(1.5f); + loadingDrawable.setAlpha((int) (0xFF * loadingAlpha)); + canvas.save(); + canvas.translate(0, backgroundBounds.bottom - ChannelBlock.height()); + loadingDrawable.draw(canvas); + canvas.restore(); + +// cell.invalidate(); + } + + final float cs = closeBounce.getScale(0.02f); + + final float cx = backgroundBounds.right - dp(16 + 4); + final float cy = backgroundBounds.top + dp(16 + 4); + canvas.save(); + canvas.scale(cs, cs, cx, cy); + closePaint.setStrokeWidth(dp(1.33f)); + canvas.drawLine(cx - dp(4), cy - dp(4), cx + dp(4), cy + dp(4), closePaint); + canvas.drawLine(cx - dp(4), cy + dp(4), cx + dp(4), cy - dp(4), closePaint); + closeBounds.set(cx - dp(12), cy - dp(12), cx + dp(12), cy + dp(12)); + canvas.restore(); + + canvas.restore(); + } + } + + private void checkBackgroundPath(float t) { + if (Math.abs(t - lastBackgroundPathExpandT) < 0.001f) { + return; + } + + final float r = dp(16.66f); + final float d = r * 2; + + final float bottom = backgroundBounds.bottom; + + backgroundPath.rewind(); + AndroidUtilities.rectTmp.set(backgroundBounds.left, backgroundBounds.top, backgroundBounds.left + d, backgroundBounds.top + d); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -90, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.left, bottom - d, backgroundBounds.left + d, bottom); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -180, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.right - d, bottom - d, backgroundBounds.right, bottom); + backgroundPath.arcTo(AndroidUtilities.rectTmp, -270, -90); + AndroidUtilities.rectTmp.set(backgroundBounds.right - d, backgroundBounds.top, backgroundBounds.right, backgroundBounds.top + d); + backgroundPath.arcTo(AndroidUtilities.rectTmp, 0, -90); + backgroundPath.lineTo(backgroundBounds.centerX() + dp(8), backgroundBounds.top); + backgroundPath.lineTo(backgroundBounds.centerX(), backgroundBounds.top - dp(6)); + backgroundPath.lineTo(backgroundBounds.centerX() - dp(8), backgroundBounds.top); + backgroundPath.close(); + } + + private static class ChannelBlock { + public static int height() { return dp(99); }; + public static int avatarSize() { return dp(54); }; + + private final ChatMessageCell cell; + public final AvatarDrawable[] avatarDrawable; + public final ImageReceiver[] avatarImageReceiver; + + private final TextPaint nameTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final CharSequence name; + private StaticLayout nameText; + + public final boolean isLock; + private final Drawable subscribersDrawable; + private final Paint subscribersStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint subscribersBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint subscribersBackgroundDimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private BitmapShader subscribersBackgroundPaintShader; + private int subscribersBackgroundPaintBitmapWidth, subscribersBackgroundPaintBitmapHeight; + private Matrix subscribersBackgroundPaintMatrix; + private final Text subscribersText; + + private boolean subscribersColorSetFromThumb; + private boolean subscribersColorSet; + + public final ButtonBounce bounce; + public final TLRPC.Chat chat; + + public ChannelBlock(int currentAccount, ChatMessageCell cell, TLRPC.Chat[] chats, int moreCount) { + this.cell = cell; + this.chat = chats[0]; + this.bounce = new ButtonBounce(cell) { + @Override + public void invalidate() { + cell.invalidateOutbounds(); + } + }; + final int count = 3; + avatarImageReceiver = new ImageReceiver[count]; + avatarDrawable = new AvatarDrawable[count]; + for (int i = 0; i < count; ++i) { + avatarImageReceiver[i] = new ImageReceiver(cell); + avatarImageReceiver[i].setParentView(cell); + avatarImageReceiver[i].setRoundRadius(avatarSize()); + avatarDrawable[i] = new AvatarDrawable(); + if (i < chats.length && chats[i] != null) { + avatarDrawable[i].setInfo(currentAccount, chats[i]); + avatarImageReceiver[i].setForUserOrChat(chats[i], avatarDrawable[i]); + } else { +// int resId = i == 1 ? R.drawable.widget_avatar_5 : R.drawable.widget_avatar_4; +// Drawable avatar = cell.getContext().getResources().getDrawable(resId).mutate(); +// avatarImageReceiver[i].setImageBitmap(avatar); + final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + final int color = Theme.blendOver(cell.getThemedColor(Theme.key_chat_inBubble), Theme.multAlpha(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText), .50f)); + paint.setColor(color); + avatarImageReceiver[i].setImageBitmap(new Drawable() { + @Override + public void draw(@NonNull Canvas canvas) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), getBounds().width() / 2f, paint); + } + @Override + public void setAlpha(int alpha) { + paint.setAlpha(Theme.multAlpha(color, alpha / 255f)); + } + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + }); + } + } + if (cell.isCellAttachedToWindow()) { + attach(); + } + + nameTextPaint.setTextSize(dp(11)); + final boolean isPremium = UserConfig.getInstance(cell.currentAccount).isPremium(); + name = LocaleController.getString(isPremium ? R.string.MoreSimilar : R.string.UnlockSimilar); + + subscribersStrokePaint.setStyle(Paint.Style.STROKE); + isLock = true; + subscribersDrawable = isPremium ? null : cell.getContext().getResources().getDrawable(R.drawable.mini_switch_lock).mutate(); + if (chat == null || chat.participants_count <= 1) { + subscribersText = null; + } else { + subscribersText = new Text("+" + moreCount, 9.33f, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + } + + private void checkNameText(int width) { + if (nameText != null && nameText.getWidth() == width) + return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + nameText = StaticLayout.Builder.obtain(name, 0, name.length(), nameTextPaint, width) + .setMaxLines(2) + .setEllipsize(TextUtils.TruncateAt.END) + .setBreakStrategy(LineBreaker.BREAK_STRATEGY_SIMPLE) + .setAlignment(Layout.Alignment.ALIGN_CENTER) + .build(); + } else { + nameText = StaticLayoutEx.createStaticLayout(name, nameTextPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false, TextUtils.TruncateAt.END, width - dp(16), 2, false); + } + } + + public ChannelBlock(int currentAccount, ChatMessageCell cell, TLRPC.Chat chat) { + this.cell = cell; + this.chat = chat; + this.bounce = new ButtonBounce(cell) { + @Override + public void invalidate() { + cell.invalidateOutbounds(); + } + }; + avatarImageReceiver = new ImageReceiver[1]; + avatarImageReceiver[0] = new ImageReceiver(cell); + avatarImageReceiver[0].setParentView(cell); + avatarImageReceiver[0].setRoundRadius(avatarSize()); + if (cell.isCellAttachedToWindow()) { + attach(); + } + + avatarDrawable = new AvatarDrawable[1]; + avatarDrawable[0] = new AvatarDrawable(); + avatarDrawable[0].setInfo(currentAccount, chat); + avatarImageReceiver[0].setForUserOrChat(chat, avatarDrawable[0]); + + nameTextPaint.setTextSize(dp(11)); + CharSequence title = chat != null ? chat.title : ""; + try { + title = Emoji.replaceEmoji(title, nameTextPaint.getFontMetricsInt(), false); + } catch (Exception ignore) {} + name = title; + + subscribersStrokePaint.setStyle(Paint.Style.STROKE); + isLock = false; + subscribersDrawable = cell.getContext().getResources().getDrawable(R.drawable.mini_reply_user).mutate(); + if (chat == null || chat.participants_count <= 1) { + subscribersText = null; + } else { + subscribersText = new Text(chat != null ? LocaleController.formatShortNumber(chat.participants_count, null) : "", 9.33f, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + } + + public void drawText(Canvas canvas, int width, float alpha) { + canvas.save(); + final float s = bounce.getScale(0.075f); + canvas.scale(s, s, width / 2f, height() / 2f); + + checkNameText(width); + if (nameText != null) { + canvas.save(); + canvas.translate((width - nameText.getWidth()) / 2f, dp(66.33f)); + if (avatarImageReceiver.length <= 1) { + nameTextPaint.setColor(cell.getThemedColor(Theme.key_chat_messageTextIn)); + } else { + nameTextPaint.setColor(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText)); + } + nameTextPaint.setAlpha((int) (nameTextPaint.getAlpha() * alpha)); + nameText.draw(canvas); + canvas.restore(); + } + + if (subscribersText != null) { + subscribersText.ellipsize(width - dp(32)); + final float subscribersTextWidth = dp(subscribersDrawable != null ? 17 : 8) + subscribersText.getWidth(); + float left = (width - subscribersTextWidth) / 2f; + final float cy = dp(11 - 14.33f / 2f + .33f) + avatarSize(); + final float sc = .625f; + if (subscribersDrawable != null) { + subscribersDrawable.setBounds( + (int) (left + (isLock ? subscribersText.getWidth() + dp(1.33f) : 0) + dp(3)), + (int) (cy - subscribersDrawable.getIntrinsicHeight() / 2f * sc), + (int) (left + (isLock ? subscribersText.getWidth() + dp(1.33f) : 0) + dp(3) + subscribersDrawable.getIntrinsicWidth() * sc), + (int) (cy + subscribersDrawable.getIntrinsicHeight() / 2f * sc) + ); + subscribersDrawable.draw(canvas); + } + subscribersText.draw(canvas, left + dp(!isLock ? 12.66f : 4), cy, Color.WHITE, alpha); + } + + canvas.restore(); + } + + private Path subscribersBackgroundPath; + + public void draw(Canvas canvas, int width, float alpha) { + canvas.save(); + final float s = bounce.getScale(0.075f); + canvas.scale(s, s, width / 2f, height() / 2f); + + subscribersStrokePaint.setStrokeWidth(dp(2.66f)); + subscribersStrokePaint.setColor(cell.getThemedColor(Theme.key_chat_inBubble)); + for (int i = avatarImageReceiver.length - 1; i >= 0; --i) { + final float x = width / 2f - dp(7) * (avatarImageReceiver.length - 1) / 2f + i * dp(7); + final float y = dp(10) + avatarSize() / 2f; + if (avatarImageReceiver.length > 1) { + canvas.drawCircle(x, y, avatarSize() / 2f, subscribersStrokePaint); + } + avatarImageReceiver[i].setImageCoords( + x - avatarSize() / 2f, + y - avatarSize() / 2f, + avatarSize(), + avatarSize() + ); + avatarImageReceiver[i].setAlpha(alpha); + avatarImageReceiver[i].draw(canvas); + } + + if (subscribersText != null) { + subscribersText.ellipsize(width - dp(32)); + final float subscribersTextWidth = dp(subscribersDrawable != null ? 17 : 8) + subscribersText.getWidth(); + + final float bottom = dp(10) + avatarSize() + dp(1); + AndroidUtilities.rectTmp.set((width - subscribersTextWidth) / 2f, bottom - dp(14.33f), (width + subscribersTextWidth) / 2f, bottom); + + if (!subscribersColorSet && isLock) { + subscribersBackgroundPaint.setColor(Theme.blendOver(cell.getThemedColor(Theme.key_chat_inBubble), Theme.multAlpha(cell.getThemedColor(Theme.key_windowBackgroundWhiteGrayText), .85f))); + subscribersColorSet = true; + } else if (!subscribersColorSet && avatarImageReceiver[0].getStaticThumb() instanceof BitmapDrawable) { + final Bitmap bitmap = ((BitmapDrawable) avatarImageReceiver[0].getStaticThumb()).getBitmap(); + try { + final int bitmapColor = bitmap.getPixel(bitmap.getWidth() / 2, bitmap.getHeight() - 2); + float[] hsl = new float[3]; + ColorUtils.colorToHSL(bitmapColor, hsl); + if (hsl[1] <= .05f || hsl[1] >= .95f || hsl[2] <= .02f || hsl[2] >= .98f) { + hsl[1] = 0; + hsl[2] = Theme.isCurrentThemeDark() ? .38f : .70f; + } else { + hsl[1] = .25f; + hsl[2] = Theme.isCurrentThemeDark() ? .35f : .65f; + } + subscribersBackgroundPaint.setColor(ColorUtils.HSLToColor(hsl)); + } catch (Exception e) { + FileLog.e(e); + } + subscribersColorSet = true; + } else if (!subscribersColorSet && !subscribersColorSetFromThumb) { + try { + final int color = ColorUtils.blendARGB(avatarDrawable[0].getColor(), avatarDrawable[0].getColor2(), .5f); + float[] hsl = new float[3]; + ColorUtils.colorToHSL(color, hsl); + if (hsl[1] <= .05f || hsl[1] >= .95f) { + hsl[2] = Utilities.clamp(hsl[2] - .1f, .6f, .3f); + } else { + hsl[1] = Utilities.clamp(hsl[1] - .06f, .4f, 0); + hsl[2] = Utilities.clamp(hsl[2] - .08f, .5f, .2f); + } + subscribersBackgroundPaint.setColor(ColorUtils.HSLToColor(hsl)); + } catch (Exception e) { + FileLog.e(e); + } + subscribersColorSetFromThumb = true; + } + if (subscribersBackgroundPaintShader != null) { + subscribersBackgroundPaintMatrix.reset(); + subscribersBackgroundPaintMatrix.postScale(avatarSize() / (float) subscribersBackgroundPaintBitmapWidth, avatarSize() / (float) subscribersBackgroundPaintBitmapHeight); + subscribersBackgroundPaintMatrix.postTranslate(width / 2f - avatarSize() / 2f, AndroidUtilities.rectTmp.bottom - avatarSize()); + subscribersBackgroundPaintShader.setLocalMatrix(subscribersBackgroundPaintMatrix); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundDimPaint); + } else { + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersBackgroundPaint); + } + + AndroidUtilities.rectTmp.inset(-dp(1) / 2f, -dp(1) / 2f); + subscribersStrokePaint.setStrokeWidth(dp(1)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(8), dp(8), subscribersStrokePaint); + } + + canvas.restore(); + } + + public static void fillPath(Path path, int width, float x) { + path.addCircle(x + width / 2f, dp(10) + avatarSize() / 2f, avatarSize() / 2f, Path.Direction.CW); + + final float nameWidth = width * .4f; + AndroidUtilities.rectTmp.set(x + (width - nameWidth) / 2f, dp(74 - 5), x + (width + nameWidth) / 2f, dp(74 + 5)); + path.addRoundRect(AndroidUtilities.rectTmp, dp(3), dp(3), Path.Direction.CW); + + final float subWidth = width * .35f; + AndroidUtilities.rectTmp.set(x + (width - subWidth) / 2f, dp(87 - 4), x + (width + subWidth) / 2f, dp(87 + 4)); + path.addRoundRect(AndroidUtilities.rectTmp, dp(2.5f), dp(2.5f), Path.Direction.CW); + } + + public void attach() { + for (int i = 0; i < avatarImageReceiver.length; ++i) { + avatarImageReceiver[i].onAttachedToWindow(); + } + } + + public void detach() { + for (int i = 0; i < avatarImageReceiver.length; ++i) { + avatarImageReceiver[i].onDetachedFromWindow(); + } + } + } + + private boolean maybeScrolling; + private boolean scrolling; + private float lx, ly; + private VelocityTracker velocityTracker; + private final Scroller scroller; + + private ChannelBlock longPressedBlock; + private Runnable longPressRunnable; + + public boolean checkTouchEvent(MotionEvent ev) { + if (msg == null || cell == null) return false; + + final int a = ev.getAction(); + ChannelBlock block = null; + float x = backgroundBounds.left + dp(7) - scrollX; + for (int i = 0; i < channels.size(); ++i) { + ChannelBlock b = channels.get(i); + if (ev.getX() >= x && ev.getX() <= x + blockWidth && ev.getY() >= backgroundBounds.bottom - ChannelBlock.height() && ev.getY() < backgroundBounds.bottom) { + block = b; + break; + } + x += blockWidth + dp(9); + } + + final boolean clickClose = closeBounds.contains(ev.getX(), ev.getY()); + + if (a == MotionEvent.ACTION_DOWN) { + scroller.abortAnimation(); + maybeScrolling = !loading && backgroundBounds.contains(lx = ev.getX(), ly = ev.getY()); + if (maybeScrolling && cell.getParent() != null) { + cell.getParent().requestDisallowInterceptTouchEvent(true); + } + scrolling = false; + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + velocityTracker = VelocityTracker.obtain(); + if (block != null) { + block.bounce.setPressed(true); + } + if (clickClose) { + closeBounce.setPressed(true); + } + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + final ChannelBlock finalBlock = block; + longPressedBlock = block; + if (longPressedBlock != null) { + AndroidUtilities.runOnUIThread(longPressRunnable = () -> { + if (finalBlock == longPressedBlock) { + longPressedBlock.bounce.setPressed(false); + if (longPressedBlock.isLock) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressMoreChannelRecommendations(cell); + } + } else { + didClickChannel(longPressedBlock.chat, true); + } + } + longPressedBlock = null; + longPressRunnable = null; + scrolling = false; + maybeScrolling = false; + closeBounce.setPressed(false); + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + }, ViewConfiguration.getLongPressTimeout()); + } + return maybeScrolling; + } else if (a == MotionEvent.ACTION_MOVE) { + if (velocityTracker != null) { + velocityTracker.addMovement(ev); + } + if (maybeScrolling && Math.abs(ev.getX() - lx) >= AndroidUtilities.touchSlop || scrolling) { + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + scrolling = true; + scroll(lx - ev.getX()); + lx = ev.getX(); + unselectBlocks(); + return true; + } + } else if (a == MotionEvent.ACTION_UP || a == MotionEvent.ACTION_CANCEL) { + if (longPressRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + longPressRunnable = null; + } + + if (velocityTracker != null) { + velocityTracker.addMovement(ev); + } + final boolean wasScrolling = scrolling; + scrolling = false; + if (a == MotionEvent.ACTION_UP) { + if (!wasScrolling && block != null && block.bounce.isPressed()) { + if (block.isLock) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressMoreChannelRecommendations(cell); + } + } else { + didClickChannel(block.chat, false); + } + } else if (wasScrolling && velocityTracker != null) { + velocityTracker.computeCurrentVelocity(500); + int velocity = (int) -velocityTracker.getXVelocity(); + scroller.fling((int) scrollX, 0, velocity, 0, -Integer.MAX_VALUE, Integer.MAX_VALUE, 0, 0); + } else if (closeBounce.isPressed()) { + didClickClose(); + } + } + + closeBounce.setPressed(false); + + maybeScrolling = false; + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + unselectBlocks(); + return wasScrolling; + } + return false; + } + + public void didClickClose() { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressChannelRecommendationsClose(cell); + } + } + + public void didClickChannel(TLRPC.Chat chat, boolean longPress) { + if (cell.getDelegate() != null) { + cell.getDelegate().didPressChannelRecommendation(cell, chat, longPress); + } + } + + private void unselectBlocks() { + for (int i = 0; i < channels.size(); ++i) { + channels.get(i).bounce.setPressed(false); + } + } + + public void computeScroll() { + if (scroller.computeScrollOffset()) { + scrollX = scroller.getCurrX(); + scrollX = Utilities.clamp(scrollX, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + cell.invalidateOutbounds(); + } + } + + private void scroll(float dx) { + scrollX = Utilities.clamp(scrollX + dx, channelsScrollWidth - (backgroundBounds.width() - dp(14)), 0); + cell.invalidateOutbounds(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 13d8d5e050..028af3dde3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -8,6 +8,8 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; @@ -20,9 +22,11 @@ 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; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; @@ -39,12 +43,17 @@ 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; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; @@ -59,6 +68,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.TLObject; @@ -86,6 +96,9 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.PhotoViewer; import org.telegram.ui.Stories.StoriesUtilities; +import org.telegram.ui.Stories.UploadingDotsSpannable; +import org.telegram.ui.Stories.recorder.HintView2; +import org.telegram.ui.Stories.recorder.PreviewView; import tw.nekomimi.nekogram.NekoConfig; import xyz.nextalone.nagram.NaConfig; @@ -161,7 +174,10 @@ public interface ChatActionCellDelegate { default void didClickImage(ChatActionCell cell) { } - default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, boolean animateConfetti) { + default void didClickButton(ChatActionCell cell) { + } + + default void didOpenPremiumGift(ChatActionCell cell, TLRPC.TL_premiumGiftOption giftOption, String slug, boolean animateConfetti) { } default void didOpenPremiumGiftChannel(ChatActionCell cell, String slug, boolean animateConfetti) { @@ -213,6 +229,8 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { 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; @@ -236,6 +254,7 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { TextPaint textPaint; private float viewTop; + private float viewTranslationX; private int backgroundHeight; private boolean visiblePartSet; @@ -260,6 +279,7 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { 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; @@ -270,8 +290,10 @@ public interface ThemeDelegate extends Theme.ResourcesProvider { private int stickerSize; private int giftRectSize; private StaticLayout giftPremiumTitleLayout; + private int giftPremiumSubtitleWidth; private StaticLayout giftPremiumSubtitleLayout; private StaticLayout giftPremiumButtonLayout; + private boolean buttonClickableAsImage = true; TextPaint settingWallpaperPaint; private StaticLayout settingWallpaperLayout; private float settingWallpaperProgress; @@ -346,7 +368,7 @@ public ChatActionCell(Context context, boolean canDrawInParent, Theme.ResourcesP giftSubtitlePaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics())); rippleView = new View(context); - rippleView.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Color.WHITE, .07f), Theme.RIPPLE_MASK_ROUNDRECT_6DP, AndroidUtilities.dp(16))); + rippleView.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Color.BLACK, .1f), Theme.RIPPLE_MASK_ROUNDRECT_6DP, dp(16))); rippleView.setVisibility(GONE); addView(rippleView); @@ -426,7 +448,7 @@ public void setMessageObject(MessageObject messageObject) { } public void setMessageObject(MessageObject messageObject, boolean force) { - if (currentMessageObject == messageObject && (textLayout == null || TextUtils.equals(textLayout.getText(), messageObject.messageText)) && (hasReplyMessage || messageObject.replyMessageObject == null) && !force && messageObject.type != MessageObject.TYPE_SUGGEST_PHOTO) { + if (currentMessageObject == messageObject && (textLayout == null || TextUtils.equals(textLayout.getText(), messageObject.messageText)) && (hasReplyMessage || messageObject.replyMessageObject == null) && !force && messageObject.type != MessageObject.TYPE_SUGGEST_PHOTO && !messageObject.forceUpdate) { return; } if (BuildVars.DEBUG_PRIVATE_VERSION && Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { @@ -435,14 +457,18 @@ public void setMessageObject(MessageObject messageObject, boolean force) { accessibilityText = null; boolean messageIdChanged = currentMessageObject == null || currentMessageObject.stableId != messageObject.stableId; currentMessageObject = messageObject; + messageObject.forceUpdate = false; hasReplyMessage = messageObject.replyMessageObject != null; DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); previousWidth = 0; 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(user); + avatarDrawable.setInfo(currentAccount, user); TL_stories.StoryItem storyItem = messageObject.messageOwner.media.storyItem; if (storyItem != null && storyItem.noforwards) { imageReceiver.setForUserOrChat(user, avatarDrawable, null, true, 0, true); @@ -461,11 +487,34 @@ public void setMessageObject(MessageObject messageObject, boolean force) { } } } - 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)); @@ -524,7 +573,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { forceWasUnread = messageObject.wasUnread; imageReceiver.setAllowStartLottieAnimation(false); imageReceiver.setDelegate(giftStickerDelegate); - imageReceiver.setImageBitmap(new RLottieDrawable(R.raw.premium_gift, messageObject.getId() + "_" + R.raw.premium_gift, AndroidUtilities.dp(160), AndroidUtilities.dp(160))); + imageReceiver.setImageBitmap(new RLottieDrawable(R.raw.premium_gift, messageObject.getId() + "_" + R.raw.premium_gift, dp(160), dp(160))); } else { TLRPC.TL_messages_stickerSet set; TLRPC.Document document = null; @@ -539,12 +588,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { 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(); @@ -675,6 +719,20 @@ public void setVisiblePart(float visibleTop, int parentH) { visiblePartSet = true; backgroundHeight = parentH; viewTop = visibleTop; + viewTranslationX = 0; + } + + private float dimAmount; + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public void setVisiblePart(float visibleTop, float tx, int parentH, float dimAmount) { + visiblePartSet = true; + backgroundHeight = parentH; + viewTop = visibleTop; + viewTranslationX = tx; + + this.dimAmount = dimAmount; + dimPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (0xFF * dimAmount))); + invalidate(); } @Override @@ -755,7 +813,7 @@ public boolean onTouchEvent(MotionEvent event) { imagePressed = true; result = true; } - if (isButtonLayout(messageObject) && (giftButtonRect.contains(x, y) || backgroundRect.contains(x, y))) { + if (isButtonLayout(messageObject) && giftPremiumButtonLayout != null && (giftButtonRect.contains(x, y) || buttonClickableAsImage && backgroundRect.contains(x, y))) { rippleView.setPressed(giftButtonPressed = true); bounce.setPressed(true); result = true; @@ -783,7 +841,11 @@ public boolean onTouchEvent(MotionEvent event) { } else { ImageUpdater imageUpdater = MessagesController.getInstance(currentAccount).photoSuggestion.get(messageObject.messageOwner.local_id); if (imageUpdater == null) { - delegate.didClickImage(this); + if (buttonClickableAsImage) { + delegate.didClickImage(this); + } else { + delegate.didClickButton(this); + } } } } @@ -889,15 +951,33 @@ private void openPremiumGiftChannel() { } } + 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)); } } @@ -949,7 +1029,7 @@ private void openLink(CharacterStyle link) { } private void createLayout(CharSequence text, int width) { - int maxWidth = width - AndroidUtilities.dp(30); + int maxWidth = width - dp(30); if (maxWidth < 0) { return; } @@ -987,7 +1067,7 @@ private void createLayout(CharSequence text, int width) { FileLog.e(e); } textX = (width - textWidth) / 2; - textY = AndroidUtilities.dp(7); + textY = dp(7); textXLeft = (width - textLayout.getWidth()) / 2; spoilersPool.addAll(spoilers); @@ -1002,22 +1082,22 @@ private void createLayout(CharSequence text, int width) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MessageObject messageObject = currentMessageObject; if (messageObject == null && customText == null) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + dp(14)); return; } if (isButtonLayout(messageObject)) { - giftRectSize = Math.min((int) (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() * 0.6f : AndroidUtilities.displaySize.x * 0.62f - AndroidUtilities.dp(34)), AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(64)); + giftRectSize = Math.min((int) (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() * 0.6f : AndroidUtilities.displaySize.x * 0.62f - dp(34)), AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.statusBarHeight - dp(64)); if (!AndroidUtilities.isTablet() && messageObject.type == MessageObject.TYPE_GIFT_PREMIUM) { giftRectSize = (int) (giftRectSize * 1.2f); } - stickerSize = giftRectSize - AndroidUtilities.dp(106); + stickerSize = giftRectSize - dp(106); if (isNewStyleButtonLayout()) { imageReceiver.setRoundRadius(stickerSize / 2); } else { imageReceiver.setRoundRadius(0); } } - int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec)); + int width = Math.max(dp(30), MeasureSpec.getSize(widthMeasureSpec)); if (previousWidth != width) { wasLayout = true; previousWidth = width; @@ -1026,9 +1106,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int additionalHeight = 0; if (messageObject != null) { if (messageObject.type == MessageObject.TYPE_ACTION_PHOTO) { - additionalHeight = AndroidUtilities.roundMessageSize + AndroidUtilities.dp(10); + additionalHeight = AndroidUtilities.roundMessageSize + dp(10); } else if (isButtonLayout(messageObject)) { - additionalHeight = giftRectSize + AndroidUtilities.dp(12); + additionalHeight = giftRectSize + dp(12); } } @@ -1038,36 +1118,36 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int imageSize = getImageSize(messageObject); float y; if (isNewStyleButtonLayout()) { - y = textY + textHeight + AndroidUtilities.dp(4) + AndroidUtilities.dp(16) * 2 + imageSize + giftPremiumSubtitleLayout.getHeight() + AndroidUtilities.dp(4); + y = textY + textHeight + dp(4) + dp(16) * 2 + imageSize + giftPremiumSubtitleLayout.getHeight() + dp(4); } else { - y = textY + textHeight + giftRectSize * 0.075f + imageSize + AndroidUtilities.dp(4) + AndroidUtilities.dp(4) + giftPremiumSubtitleLayout.getHeight(); + y = textY + textHeight + giftRectSize * 0.075f + imageSize + dp(4) + dp(4) + giftPremiumSubtitleLayout.getHeight(); } giftPremiumAdditionalHeight = 0; if (giftPremiumTitleLayout != null) { y += giftPremiumTitleLayout.getHeight(); - y += AndroidUtilities.dp(isGiftChannel ? 6 : 0); + y += dp(isGiftChannel ? 6 : 0); } else { - y -= AndroidUtilities.dp(12); - giftPremiumAdditionalHeight -= AndroidUtilities.dp(30); + y -= dp(12); + giftPremiumAdditionalHeight -= dp(30); } if (giftPremiumSubtitleLayout.getLineCount() > 2) { giftPremiumAdditionalHeight += (giftPremiumSubtitleLayout.getLineBottom(0) - giftPremiumSubtitleLayout.getLineTop(0)) * giftPremiumSubtitleLayout.getLineCount() - 2; } - giftPremiumAdditionalHeight -= AndroidUtilities.dp(isGiftChannel ? 14 : 0); + giftPremiumAdditionalHeight -= dp(isGiftChannel ? 14 : 0); additionalHeight += giftPremiumAdditionalHeight; - int h = textHeight + additionalHeight + AndroidUtilities.dp(14); + int h = textHeight + additionalHeight + dp(14); if (giftPremiumButtonLayout != null) { - y += (h - y - (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) - AndroidUtilities.dp(8)) / 2f; + y += (h - y - (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) - dp(8)) / 2f; float rectX = (previousWidth - giftPremiumButtonWidth) / 2f; - giftButtonRect.set(rectX - AndroidUtilities.dp(18), y - AndroidUtilities.dp(8), rectX + giftPremiumButtonWidth + AndroidUtilities.dp(18), y + (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) + AndroidUtilities.dp(8)); + giftButtonRect.set(rectX - dp(18), y - dp(8), rectX + giftPremiumButtonWidth + dp(18), y + (giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0) + dp(8)); } else { - additionalHeight -= AndroidUtilities.dp(40); - giftPremiumAdditionalHeight -= AndroidUtilities.dp(40); + additionalHeight -= dp(40); + giftPremiumAdditionalHeight -= dp(40); } int sizeInternal = getMeasuredWidth() << 16 + getMeasuredHeight(); starParticlesDrawable.rect.set(giftButtonRect); @@ -1078,25 +1158,25 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } if (isNewStyleButtonLayout()) { - exactlyHeight = textY + textHeight + AndroidUtilities.dp(4); + exactlyHeight = textY + textHeight + dp(4); backgroundRectHeight = 0; - backgroundRectHeight += AndroidUtilities.dp(16) * 2 + imageSize; + backgroundRectHeight += dp(16) * 2 + imageSize; backgroundRectHeight += giftPremiumSubtitleLayout.getHeight(); if (giftPremiumButtonLayout != null) { - backgroundButtonTop = exactlyHeight + backgroundRectHeight + AndroidUtilities.dp(10); + backgroundButtonTop = exactlyHeight + backgroundRectHeight + dp(10); float rectX = (previousWidth - giftPremiumButtonWidth) / 2f; - giftButtonRect.set(rectX - AndroidUtilities.dp(18), backgroundButtonTop, rectX + giftPremiumButtonWidth + AndroidUtilities.dp(18), backgroundButtonTop + giftPremiumButtonLayout.getHeight() + AndroidUtilities.dp(8) * 2); - backgroundRectHeight += AndroidUtilities.dp(10) + giftButtonRect.height(); + giftButtonRect.set(rectX - dp(18), backgroundButtonTop, rectX + giftPremiumButtonWidth + dp(18), backgroundButtonTop + giftPremiumButtonLayout.getHeight() + dp(8) * 2); + backgroundRectHeight += dp(10) + giftButtonRect.height(); } - backgroundRectHeight += AndroidUtilities.dp(16); + backgroundRectHeight += dp(16); exactlyHeight += backgroundRectHeight; - exactlyHeight += AndroidUtilities.dp(6); + exactlyHeight += dp(6); } } if (messageObject != null && (isNewStyleButtonLayout())) { setMeasuredDimension(width, exactlyHeight); } else { - setMeasuredDimension(width, textHeight + additionalHeight + AndroidUtilities.dp(14)); + setMeasuredDimension(width, textHeight + additionalHeight + dp(14)); } } @@ -1107,7 +1187,7 @@ private boolean isNewStyleButtonLayout() { private int getImageSize(MessageObject messageObject) { int imageSize = stickerSize; if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO || isNewStyleButtonLayout()) { - imageSize = AndroidUtilities.dp(78);//Math.max(, (int) (stickerSize * 0.7f)); + imageSize = dp(78);//Math.max(, (int) (stickerSize * 0.7f)); } return imageSize; } @@ -1130,9 +1210,15 @@ private void buildLayout() { if (text == null) { if (messageObject.messageOwner != null && messageObject.messageOwner.media != null && messageObject.messageOwner.media.ttl_seconds != 0) { if (messageObject.messageOwner.media.photo != null) { - text = LocaleController.getString("AttachPhotoExpired", R.string.AttachPhotoExpired); + text = LocaleController.getString(R.string.AttachPhotoExpired); } else if (messageObject.messageOwner.media.document instanceof TLRPC.TL_documentEmpty || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && messageObject.messageOwner.media.document == null) { - text = LocaleController.getString("AttachVideoExpired", R.string.AttachVideoExpired); + 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); } @@ -1159,11 +1245,13 @@ private void buildLayout() { createLayout(text, previousWidth); if (messageObject != null) { if (messageObject.type == MessageObject.TYPE_ACTION_PHOTO) { - imageReceiver.setImageCoords((previousWidth - AndroidUtilities.roundMessageSize) / 2f, textHeight + AndroidUtilities.dp(19), AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize); + imageReceiver.setImageCoords((previousWidth - AndroidUtilities.roundMessageSize) / 2f, textHeight + dp(19), AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL) { createGiftPremiumChannelLayouts(); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM) { - createGiftPremiumLayouts(LocaleController.getString(R.string.ActionGiftPremiumTitle), LocaleController.formatString(R.string.ActionGiftPremiumSubtitle, LocaleController.formatPluralString("Months", messageObject.messageOwner.action.months)), LocaleController.getString(R.string.ActionGiftPremiumView), giftRectSize); + 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; @@ -1172,24 +1260,24 @@ private void buildLayout() { if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { TLRPC.User user2 = MessagesController.getInstance(currentAccount).getUser(messageObject.getDialogId()); if (isVideo) { - description = LocaleController.formatString("ActionSuggestVideoFromYouDescription", R.string.ActionSuggestVideoFromYouDescription, user2.first_name); + description = LocaleController.formatString(R.string.ActionSuggestVideoFromYouDescription, user2.first_name); } else { - description = LocaleController.formatString("ActionSuggestPhotoFromYouDescription", R.string.ActionSuggestPhotoFromYouDescription, user2.first_name); + description = LocaleController.formatString(R.string.ActionSuggestPhotoFromYouDescription, user2.first_name); } } else { if (isVideo) { - description = LocaleController.formatString("ActionSuggestVideoToYouDescription", R.string.ActionSuggestVideoToYouDescription, user.first_name); + description = LocaleController.formatString(R.string.ActionSuggestVideoToYouDescription, user.first_name); } else { - description = LocaleController.formatString("ActionSuggestPhotoToYouDescription", R.string.ActionSuggestPhotoToYouDescription, user.first_name); + description = LocaleController.formatString(R.string.ActionSuggestPhotoToYouDescription, user.first_name); } } String action; if (actionSuggestProfilePhoto.video || (actionSuggestProfilePhoto.photo.video_sizes != null && !actionSuggestProfilePhoto.photo.video_sizes.isEmpty())) { - action = LocaleController.getString("ViewVideoAction", R.string.ViewVideoAction); + action = LocaleController.getString(R.string.ViewVideoAction); } else { - action = LocaleController.getString("ViewPhotoAction", R.string.ViewPhotoAction); + action = LocaleController.getString(R.string.ViewPhotoAction); } - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, true); textLayout = null; textHeight = 0; textY = 0; @@ -1197,13 +1285,20 @@ private void buildLayout() { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(messageObject.isOutOwner() ? 0 : messageObject.getDialogId()); CharSequence description; String action = null; - if (user.id == UserConfig.getInstance(currentAccount).clientUserId) { + boolean actionClickableAsImage = true; + if (messageObject.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 != null && user.id == UserConfig.getInstance(currentAccount).clientUserId) { description = messageObject.messageText; } else { description = messageObject.messageText; - action = LocaleController.getString("ViewWallpaperAction", R.string.ViewWallpaperAction); + action = LocaleController.getString(R.string.ViewWallpaperAction); } - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, actionClickableAsImage); textLayout = null; textHeight = 0; textY = 0; @@ -1218,9 +1313,9 @@ private void buildLayout() { } else { description = AndroidUtilities.replaceTags(LocaleController.formatString("StoryMentionedTitle", R.string.StoryMentionedTitle, user.first_name)); } - action = LocaleController.getString("StoryMentionedAction", R.string.StoryMentionedAction); + action = LocaleController.getString(R.string.StoryMentionedAction); - createGiftPremiumLayouts(null, description, action, giftRectSize); + createGiftPremiumLayouts(null, description, action, giftRectSize, true); textLayout = null; textHeight = 0; textY = 0; @@ -1230,9 +1325,9 @@ private void buildLayout() { private void createGiftPremiumChannelLayouts() { int width = giftRectSize; - width -= AndroidUtilities.dp(16); - giftTitlePaint.setTextSize(AndroidUtilities.dp(14)); - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(13)); + width -= dp(16); + giftTitlePaint.setTextSize(dp(14)); + giftSubtitlePaint.setTextSize(dp(13)); TLRPC.TL_messageActionGiftCode gifCodeAction = (TLRPC.TL_messageActionGiftCode) currentMessageObject.messageOwner.action; int months = gifCodeAction.months; TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(gifCodeAction.boost_peer)); @@ -1265,18 +1360,20 @@ private void createGiftPremiumChannelLayouts() { titleBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, titleBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumTitleLayout = new StaticLayout(titleBuilder, giftTitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.1f, 0.0f, false); + giftPremiumSubtitleWidth = width; giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.1f, 0.0f, false); SpannableStringBuilder buttonBuilder = SpannableStringBuilder.valueOf(btnText); buttonBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, buttonBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumButtonLayout = new StaticLayout(buttonBuilder, (TextPaint) getThemedPaint(Theme.key_paint_chatActionText), width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + buttonClickableAsImage = true; giftPremiumButtonWidth = measureLayoutWidth(giftPremiumButtonLayout); } - private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, CharSequence button, int width) { - width -= AndroidUtilities.dp(16); + private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, CharSequence button, int width, boolean buttonClickableAsImage) { + width -= dp(16); if (title != null) { - giftTitlePaint.setTextSize(AndroidUtilities.dp(16)); + giftTitlePaint.setTextSize(dp(16)); SpannableStringBuilder titleBuilder = SpannableStringBuilder.valueOf(title); titleBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, titleBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumTitleLayout = new StaticLayout(titleBuilder, giftTitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); @@ -1284,18 +1381,30 @@ private void createGiftPremiumLayouts(CharSequence title, CharSequence subtitle, giftPremiumTitleLayout = null; } if (currentMessageObject != null && isNewStyleButtonLayout()) { - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(13)); + giftSubtitlePaint.setTextSize(dp(13)); } else { - giftSubtitlePaint.setTextSize(AndroidUtilities.dp(15)); + giftSubtitlePaint.setTextSize(dp(15)); + } + int subtitleWidth = giftPremiumSubtitleWidth = width; + if (currentMessageObject != null && (currentMessageObject.type == MessageObject.TYPE_ACTION_WALLPAPER && currentMessageObject.getDialogId() >= 0)) { + final int recommendedWidthForTwoLines = HintView2.cutInFancyHalf(subtitle, giftSubtitlePaint); + if (recommendedWidthForTwoLines < subtitleWidth && recommendedWidthForTwoLines > subtitleWidth / 5f) { + subtitleWidth = recommendedWidthForTwoLines; + } } - giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + try { + subtitle = Emoji.replaceEmoji(subtitle, giftSubtitlePaint.getFontMetricsInt(), false); + } catch (Exception ignore) {} + giftPremiumSubtitleLayout = new StaticLayout(subtitle, giftSubtitlePaint, subtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, dp(1.66f), false); if (button != null) { SpannableStringBuilder buttonBuilder = SpannableStringBuilder.valueOf(button); buttonBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, buttonBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); giftPremiumButtonLayout = new StaticLayout(buttonBuilder, (TextPaint) getThemedPaint(Theme.key_paint_chatActionText), width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + this.buttonClickableAsImage = buttonClickableAsImage; giftPremiumButtonWidth = measureLayoutWidth(giftPremiumButtonLayout); } else { giftPremiumButtonLayout = null; + this.buttonClickableAsImage = false; giftPremiumButtonWidth = 0; } } @@ -1311,6 +1420,10 @@ private float measureLayoutWidth(Layout layout) { return maxWidth; } + public boolean showingCancelButton() { + return radialProgress != null && radialProgress.getIcon() == MediaActionDrawable.ICON_CANCEL; + } + public int getCustomDate() { return customDate; } @@ -1320,10 +1433,10 @@ protected void onDraw(Canvas canvas) { MessageObject messageObject = currentMessageObject; int imageSize = stickerSize; if (isButtonLayout(messageObject)) { - stickerSize = giftRectSize - AndroidUtilities.dp(106); + stickerSize = giftRectSize - dp(106); if (isNewStyleButtonLayout()) { imageSize = getImageSize(messageObject); - int top = textY + textHeight + AndroidUtilities.dp(4) + AndroidUtilities.dp(16); + int top = textY + textHeight + dp(4) + dp(16); float x = (previousWidth - imageSize) / 2f; float y = top; if (messageObject.isStoryMention()) { @@ -1335,10 +1448,10 @@ protected void onDraw(Canvas canvas) { imageReceiver.setImageCoords((previousWidth - stickerSize) / 2f, textY + textHeight + giftRectSize * 0.075f, stickerSize, stickerSize); } else if (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL) { imageSize = (int) (stickerSize * (AndroidUtilities.isTablet() ? 1.0f : 1.2f)); - imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - AndroidUtilities.dp(22), imageSize, imageSize); + imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - dp(22), imageSize, imageSize); } else { imageSize = (int) (stickerSize * 1f); - imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - AndroidUtilities.dp(4), imageSize, imageSize); + imageReceiver.setImageCoords((previousWidth - imageSize) / 2f, textY + textHeight + giftRectSize * 0.075f - dp(4), imageSize, imageSize); } textPaint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); if (textPaint != null) { @@ -1347,6 +1460,7 @@ protected void onDraw(Canvas canvas) { } if (giftSubtitlePaint != null && giftSubtitlePaint.getColor() != textPaint.getColor()) { giftSubtitlePaint.setColor(textPaint.getColor()); + giftSubtitlePaint.linkColor = textPaint.getColor(); } } } @@ -1354,7 +1468,20 @@ protected void onDraw(Canvas canvas) { 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); @@ -1373,7 +1500,7 @@ protected void onDraw(Canvas canvas) { if (imageUpdater != null) { radialProgress.setProgress(imageUpdater.getCurrentImageProgress(), true); radialProgress.setCircleRadius((int) (imageReceiver.getImageWidth() * 0.5f) + 1); - radialProgress.setMaxIconSize(AndroidUtilities.dp(24)); + radialProgress.setMaxIconSize(dp(24)); radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); if (imageUpdater.getCurrentImageProgress() == 1f) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, true, true); @@ -1385,8 +1512,8 @@ protected void onDraw(Canvas canvas) { } else if (messageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { float progress = getUploadingInfoProgress(messageObject); radialProgress.setProgress(progress, true); - radialProgress.setCircleRadius(AndroidUtilities.dp(26)); - radialProgress.setMaxIconSize(AndroidUtilities.dp(24)); + radialProgress.setCircleRadius(dp(26)); + radialProgress.setMaxIconSize(dp(24)); radialProgress.setColorKeys(Theme.key_chat_mediaLoaderPhoto, Theme.key_chat_mediaLoaderPhotoSelected, Theme.key_chat_mediaLoaderPhotoIcon, Theme.key_chat_mediaLoaderPhotoIconSelected); if (progress == 1f) { radialProgress.setIcon(MediaActionDrawable.ICON_NONE, true, true); @@ -1421,18 +1548,18 @@ protected void onDraw(Canvas canvas) { if (isButtonLayout(messageObject)) { canvas.save(); - float x = (previousWidth - giftRectSize) / 2f + AndroidUtilities.dp(8); + float x = (previousWidth - giftRectSize) / 2f + dp(8); float y; if (isNewStyleButtonLayout()) { - float top = backgroundRect != null ? backgroundRect.top : (textY + textHeight + AndroidUtilities.dp(4)); - y = top + AndroidUtilities.dp(16) * 2 + imageSize; + float top = backgroundRect != null ? backgroundRect.top : (textY + textHeight + dp(4)); + y = top + dp(16) * 2 + imageSize; } else { - y = textY + textHeight + giftRectSize * 0.075f + (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO ? imageSize : stickerSize) + AndroidUtilities.dp(4); + y = textY + textHeight + giftRectSize * 0.075f + (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO ? imageSize : stickerSize) + dp(4); if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { - y += AndroidUtilities.dp(16); + y += dp(16); } if (giftPremiumButtonLayout == null) { - y -= AndroidUtilities.dp(24); + y -= dp(24); } } @@ -1440,26 +1567,40 @@ protected void onDraw(Canvas canvas) { if (giftPremiumTitleLayout != null) { giftPremiumTitleLayout.draw(canvas); y += giftPremiumTitleLayout.getHeight(); - y += AndroidUtilities.dp(messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL ? 6 : 0); + y += dp(messageObject.type == MessageObject.TYPE_GIFT_PREMIUM_CHANNEL ? 6 : 0); } else { - y -= AndroidUtilities.dp(4); + y -= dp(4); } canvas.restore(); - y += AndroidUtilities.dp(4); + y += dp(4); canvas.save(); canvas.translate(x, y); if (messageObject.type == MessageObject.TYPE_ACTION_WALLPAPER) { if (radialProgress.getTransitionProgress() != 1f || radialProgress.getIcon() != MediaActionDrawable.ICON_NONE) { if (settingWallpaperLayout == null) { settingWallpaperPaint = new TextPaint(); - settingWallpaperPaint.setTextSize(AndroidUtilities.dp(13)); - settingWallpaperLayout = new StaticLayout("Setting new wallpaper...", settingWallpaperPaint, giftPremiumSubtitleLayout.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + settingWallpaperPaint.setTextSize(dp(13)); + SpannableStringBuilder cs = new SpannableStringBuilder(LocaleController.getString(R.string.ActionSettingWallpaper)); + int index = cs.toString().indexOf("..."), len = 3; + if (index < 0) { + index = cs.toString().indexOf("…"); + len = 1; + } + if (index >= 0) { + SpannableString loading = new SpannableString("…"); + UploadingDotsSpannable loadingDots = new UploadingDotsSpannable(); + loadingDots.fixTop = true; + loadingDots.setParent(ChatActionCell.this, false); + loading.setSpan(loadingDots, 0, loading.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + cs.replace(index, index + len, loading); + } + settingWallpaperLayout = new StaticLayout(cs, settingWallpaperPaint, giftPremiumSubtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } float progressLocal = getUploadingInfoProgress(messageObject); if (settingWallpaperProgressTextLayout == null || settingWallpaperProgress != progressLocal) { settingWallpaperProgress = progressLocal; - settingWallpaperProgressTextLayout = new StaticLayout((int) (progressLocal * 100) + "%", giftSubtitlePaint, giftPremiumSubtitleLayout.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + settingWallpaperProgressTextLayout = new StaticLayout((int) (progressLocal * 100) + "%", giftSubtitlePaint, giftPremiumSubtitleWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); } settingWallpaperPaint.setColor(giftSubtitlePaint.getColor()); @@ -1468,14 +1609,17 @@ protected void onDraw(Canvas canvas) { 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(); - canvas.scale(s, s, giftPremiumSubtitleLayout.getWidth() / 2f, giftPremiumSubtitleLayout.getHeight() / 2f); + canvas.scale(s, s, giftPremiumSubtitleWidth / 2f, giftPremiumSubtitleLayout.getHeight() / 2f); + canvas.translate((giftPremiumSubtitleWidth -giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); canvas.restore(); 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); @@ -1483,40 +1627,47 @@ protected void onDraw(Canvas canvas) { canvas.restore(); canvas.save(); - canvas.translate(0, settingWallpaperLayout.getHeight() + AndroidUtilities.dp(4)); + canvas.translate(0, settingWallpaperLayout.getHeight() + dp(4)); canvas.scale(s, s, settingWallpaperProgressTextLayout.getWidth() / 2f, settingWallpaperProgressTextLayout.getHeight() / 2f); settingWallpaperProgressTextLayout.draw(canvas); canvas.restore(); giftSubtitlePaint.setColor(oldColor); + giftSubtitlePaint.linkColor = oldColor; } else { settingWallpaperLayout.draw(canvas); canvas.save(); - canvas.translate(0, settingWallpaperLayout.getHeight() + AndroidUtilities.dp(4)); + canvas.translate(0, settingWallpaperLayout.getHeight() + dp(4)); settingWallpaperProgressTextLayout.draw(canvas); canvas.restore(); } } else { + canvas.save(); + canvas.translate((giftPremiumSubtitleWidth - giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); + canvas.restore(); } } else if (giftPremiumSubtitleLayout != null) { + canvas.save(); + canvas.translate((giftPremiumSubtitleWidth - giftPremiumSubtitleLayout.getWidth()) / 2f, 0); giftPremiumSubtitleLayout.draw(canvas); + canvas.restore(); } canvas.restore(); if (giftPremiumTitleLayout == null) { - y -= AndroidUtilities.dp(8); + y -= dp(8); } y += giftPremiumSubtitleLayout.getHeight(); int buttonH = giftPremiumButtonLayout != null ? giftPremiumButtonLayout.getHeight() : 0; - y += (getHeight() - y - buttonH - AndroidUtilities.dp(8)) / 2f; + y += (getHeight() - y - buttonH - dp(8)) / 2f; if (themeDelegate != null) { - themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } else { - Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } final float S = bounce.getScale(0.02f); @@ -1524,16 +1675,18 @@ protected void onDraw(Canvas canvas) { canvas.scale(S, S, giftButtonRect.centerX(), giftButtonRect.centerY()); if (giftPremiumButtonLayout != null) { - Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); - canvas.drawRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), backgroundPaint); - + Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundSelected); + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), backgroundPaint); if (hasGradientService()) { - canvas.drawRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + if (dimAmount > 0) { + canvas.drawRoundRect(giftButtonRect, dp(16), dp(16), dimPaint); } if (getMessageObject().type != MessageObject.TYPE_SUGGEST_PHOTO && getMessageObject().type != MessageObject.TYPE_ACTION_WALLPAPER && getMessageObject().type != MessageObject.TYPE_STORY_MENTION) { starsPath.rewind(); - starsPath.addRoundRect(giftButtonRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Path.Direction.CW); + starsPath.addRoundRect(giftButtonRect, dp(16), dp(16), Path.Direction.CW); canvas.save(); canvas.clipPath(starsPath); @@ -1558,7 +1711,7 @@ protected void onDraw(Canvas canvas) { if (progressView == null) { progressView = new RadialProgressView(getContext()); } - int rad = AndroidUtilities.dp(16); + int rad = dp(16); canvas.save(); canvas.scale(progressToProgress, progressToProgress, giftButtonRect.centerX(), giftButtonRect.centerY()); progressView.setSize(rad); @@ -1570,7 +1723,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); float s = 1f - progressToProgress; canvas.scale(s, s, giftButtonRect.centerX(), giftButtonRect.centerY()); - canvas.translate(x, giftButtonRect.top + AndroidUtilities.dp(8)); + canvas.translate(x, giftButtonRect.top + dp(8)); giftPremiumButtonLayout.draw(canvas); canvas.restore(); } @@ -1586,7 +1739,7 @@ protected void onDraw(Canvas canvas) { Theme.multAlpha(Color.WHITE, .2f), Theme.multAlpha(Color.WHITE, .7f) ); - loadingDrawable.strokePaint.setStrokeWidth(AndroidUtilities.dp(1)); + loadingDrawable.strokePaint.setStrokeWidth(dp(1)); } loadingDrawable.resetDisappear(); loadingDrawable.setBounds(giftButtonRect); @@ -1606,6 +1759,24 @@ protected void onDraw(Canvas canvas) { } } + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == rippleView) { + final float S = bounce.getScale(0.02f); + canvas.save(); + canvas.scale(S, S, child.getX() + child.getMeasuredWidth() / 2f, child.getY() + child.getMeasuredHeight() / 2f); + final boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } + return super.drawChild(canvas, child, drawingTime); + } + + 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) { @@ -1616,6 +1787,7 @@ public void drawBackground(Canvas canvas, boolean fromParent) { } } Paint backgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackground); + Paint darkenBackgroundPaint = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); textPaint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); if (overrideBackground >= 0) { int color = getThemedColor(overrideBackground); @@ -1624,7 +1796,7 @@ public void drawBackground(Canvas canvas, boolean fromParent) { overrideBackgroundPaint.setColor(color); overrideTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); overrideTextPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); - overrideTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + overrideTextPaint.setTextSize(dp(Math.max(16, SharedConfig.fontSize) - 2)); overrideTextPaint.setColor(getThemedColor(overrideText)); } backgroundPaint = overrideBackgroundPaint; @@ -1632,10 +1804,12 @@ public void drawBackground(Canvas canvas, boolean fromParent) { } if (invalidatePath) { invalidatePath = false; + backgroundLeft = getWidth(); + backgroundRight = 0; lineWidths.clear(); final int count = textLayout == null ? 0 : textLayout.getLineCount(); - final int corner = AndroidUtilities.dp(11); - final int cornerIn = AndroidUtilities.dp(8); + final int corner = dp(11); + final int cornerIn = dp(8); int prevLineWidth = 0; for (int a = 0; a < count; a++) { @@ -1659,12 +1833,12 @@ public void drawBackground(Canvas canvas, boolean fromParent) { prevLineWidth = lineWidth; } - int y = AndroidUtilities.dp(4); + int y = dp(4); int x = getMeasuredWidth() / 2; int previousLineBottom = 0; - final int cornerOffset = AndroidUtilities.dp(3); - final int cornerInSmall = AndroidUtilities.dp(6); + final int cornerOffset = dp(3); + final int cornerInSmall = dp(6); final int cornerRest = corner - cornerOffset; lineHeights.clear(); @@ -1678,10 +1852,10 @@ public void drawBackground(Canvas canvas, boolean fromParent) { int height = lineBottom - previousLineBottom; if (a == 0 || lineWidth > prevLineWidth) { - height += AndroidUtilities.dp(3); + height += dp(3); } if (a == count - 1 || lineWidth > nextLineWidth) { - height += AndroidUtilities.dp(3); + height += dp(3); } previousLineBottom = lineBottom; @@ -1697,28 +1871,32 @@ public void drawBackground(Canvas canvas, boolean fromParent) { 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; int yOffset = y; if (a != count - 1 && lineWidth < nextLineWidth) { - y -= AndroidUtilities.dp(3); - height -= AndroidUtilities.dp(3); + y -= dp(3); + height -= dp(3); } if (a != 0 && lineWidth < prevLineWidth) { - y -= AndroidUtilities.dp(3); - height -= AndroidUtilities.dp(3); + y -= dp(3); + height -= dp(3); } lineHeights.add(height); 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); } @@ -1740,9 +1918,11 @@ public void drawBackground(Canvas canvas, boolean fromParent) { 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); } @@ -1750,9 +1930,11 @@ public void drawBackground(Canvas canvas, boolean fromParent) { 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); } } @@ -1763,22 +1945,35 @@ public void drawBackground(Canvas canvas, boolean fromParent) { backgroundHeight = parent.getMeasuredHeight(); } if (themeDelegate != null) { - themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + themeDelegate.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } else { - Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, 0, viewTop + AndroidUtilities.dp(4)); + Theme.applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, viewTranslationX, viewTop + dp(4)); } int oldAlpha = -1; int oldAlpha2 = -1; - if (fromParent && getAlpha() != 1f) { + if (fromParent && (getAlpha() != 1f || isFloating())) { oldAlpha = backgroundPaint.getAlpha(); - oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); - backgroundPaint.setAlpha((int) (oldAlpha * getAlpha())); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * getAlpha())); + oldAlpha2 = darkenBackgroundPaint.getAlpha(); + backgroundPaint.setAlpha((int) (oldAlpha * getAlpha() * (isFloating() ? .75f : 1f))); + darkenBackgroundPaint.setAlpha((int) (oldAlpha2 * getAlpha() * (isFloating() ? .75f : 1f))); + } else if (isFloating()) { + oldAlpha = backgroundPaint.getAlpha(); + oldAlpha2 = darkenBackgroundPaint.getAlpha(); + backgroundPaint.setAlpha((int) (oldAlpha * (isFloating() ? .75f : 1f))); + darkenBackgroundPaint.setAlpha((int) (oldAlpha2 * (isFloating() ? .75f : 1f))); } canvas.drawPath(backgroundPath, backgroundPaint); if (hasGradientService()) { - canvas.drawPath(backgroundPath, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawPath(backgroundPath, darkenBackgroundPaint); + } + if (dimAmount > 0) { + int wasAlpha = dimPaint.getAlpha(); + if (fromParent) { + dimPaint.setAlpha((int) (wasAlpha * getAlpha())); + } + canvas.drawPath(backgroundPath, dimPaint); + dimPaint.setAlpha(wasAlpha); } MessageObject messageObject = currentMessageObject; @@ -1786,27 +1981,51 @@ public void drawBackground(Canvas canvas, boolean fromParent) { float x = (getWidth() - giftRectSize) / 2f; float y = textY + textHeight; if (isNewStyleButtonLayout()) { - y += AndroidUtilities.dp(4); + y += dp(4); AndroidUtilities.rectTmp.set(x, y, x + giftRectSize, y + backgroundRectHeight); } else { - y += AndroidUtilities.dp(12); + y += dp(12); AndroidUtilities.rectTmp.set(x, y, x + giftRectSize, y + giftRectSize + giftPremiumAdditionalHeight); } if (backgroundRect == null) { backgroundRect = new RectF(); } backgroundRect.set(AndroidUtilities.rectTmp); - canvas.drawRoundRect(backgroundRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), backgroundPaint); + canvas.drawRoundRect(backgroundRect, dp(16), dp(16), backgroundPaint); if (hasGradientService()) { - canvas.drawRoundRect(backgroundRect, AndroidUtilities.dp(16), AndroidUtilities.dp(16), Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(backgroundRect, dp(16), dp(16), darkenBackgroundPaint); } } if (oldAlpha >= 0) { backgroundPaint.setAlpha(oldAlpha); - Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + darkenBackgroundPaint.setAlpha(oldAlpha2); + } + } + + @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() { @@ -1900,7 +2119,7 @@ private int getThemedColor(int key) { 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); } @@ -1944,6 +2163,15 @@ public void invalidate(int l, int t, int r, int b) { } } + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == wallpaperPreviewDrawable || super.verifyDrawable(who); + } + + public boolean isFloating() { + return false; + } + private ColorFilter adaptiveEmojiColorFilter; private int adaptiveEmojiColor; private ColorFilter getAdaptiveEmojiColorFilter(int color) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java index 9bca14fc9a..c34e19cd4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java @@ -8,8 +8,13 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; +import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -29,19 +34,58 @@ public ChatLoadingCell(Context context, View parent, Theme.ResourcesProvider res super(context); this.resourcesProvider = resourcesProvider; - frameLayout = new FrameLayout(context); - frameLayout.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(18), frameLayout, parent, getThemedPaint(Theme.key_paint_chatActionBackground))); + frameLayout = new FrameLayout(context) { + private final RectF rect = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + applyServiceShaderMatrix(); + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackground)); + if (hasGradientService()) { + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + + super.dispatchDraw(canvas); + } + }; + frameLayout.setWillNotDraw(false); addView(frameLayout, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); progressBar = new RadialProgressView(context, resourcesProvider); - progressBar.setSize(AndroidUtilities.dp(28)); + progressBar.setSize(dp(28)); progressBar.setProgressColor(getThemedColor(Theme.key_chat_serviceText)); frameLayout.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); } + public boolean hasGradientService() { + return resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService(); + } + + private float viewTop; + private int backgroundHeight; + public void applyServiceShaderMatrix() { + applyServiceShaderMatrix(getMeasuredWidth(), backgroundHeight, getX(), viewTop); + } + + private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, float x, float viewTop) { + if (resourcesProvider != null) { + resourcesProvider.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } else { + Theme.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } + } + + public void setVisiblePart(float viewTop, int backgroundHeight) { + if (this.viewTop != viewTop) { + invalidate(); + } + this.viewTop = viewTop; + this.backgroundHeight = backgroundHeight; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(44), MeasureSpec.EXACTLY)); } public void setProgressVisible(boolean value) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 5ea7ba3796..f3ade6b483 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.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.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.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.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.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; @@ -196,7 +204,6 @@ import tw.nekomimi.nekogram.NekoXConfig; import xyz.nextalone.nagram.NaConfig; -import xyz.nextalone.nagram.helper.PeerColorHelper; import static xyz.nextalone.nagram.helper.MessageHelper.showForwardDate; @@ -209,12 +216,14 @@ 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; + public ChannelRecommendationsCell channelRecommendationsCell; + public RadialProgress2 getRadialProgress() { return radialProgress; } @@ -260,7 +269,7 @@ public void didReceivedNotification(int id, int account, Object... args) { 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); } } @@ -279,7 +288,7 @@ public void setAvatar(MessageObject messageObject) { } else { currentPhoto = null; } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, LiteMode.isEnabled(LiteMode.FLAGS_CHAT), VectorAvatarThumbDrawable.TYPE_SMALL, false); } else if (currentChat != null) { if (currentChat.photo != null) { @@ -287,7 +296,7 @@ public void setAvatar(MessageObject messageObject) { } else { currentPhoto = null; } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); avatarImage.setForUserOrChat(currentChat, avatarDrawable); } else if (messageObject.isSponsored()) { if (messageObject.sponsoredWebPage != null) { @@ -297,10 +306,10 @@ public void setAvatar(MessageObject messageObject) { avatarImage.setImage(ImageLocation.getForPhoto(FileLoader.getClosestPhotoSizeWithSize(photo.sizes, AndroidUtilities.dp(50), false, null, true), photo), "50_50", avatarDrawable, null, null, 0); } } else if (messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { - avatarDrawable.setInfo(messageObject.sponsoredChatInvite.chat); + avatarDrawable.setInfo(currentAccount, messageObject.sponsoredChatInvite.chat); avatarImage.setForUserOrChat(messageObject.sponsoredChatInvite.chat, avatarDrawable); } else { - avatarDrawable.setInfo(messageObject.sponsoredChatInvite); + avatarDrawable.setInfo(currentAccount, messageObject.sponsoredChatInvite); if (messageObject.sponsoredChatInvite != null) { TLRPC.Photo photo = messageObject.sponsoredChatInvite.photo; if (photo != null) { @@ -510,6 +519,18 @@ default void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBloc } + default void didPressChannelRecommendation(ChatMessageCell cell, TLRPC.Chat chat, boolean longPress) { + + } + + default void didPressMoreChannelRecommendations(ChatMessageCell cell) { + + } + + default void didPressChannelRecommendationsClose(ChatMessageCell cell) { + + } + default void needOpenWebView(MessageObject message, String url, String title, String description, String originalUrl, int w, int h) { } @@ -567,7 +588,7 @@ default String getAdminRank(long uid) { return null; } - default boolean needPlayMessage(MessageObject messageObject, boolean muted) { + default boolean needPlayMessage(ChatMessageCell cell, MessageObject messageObject, boolean muted) { return false; } @@ -752,6 +773,7 @@ public static class PollButton { 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; @@ -759,7 +781,7 @@ public static class PollButton { private int unmovedTextX; private int linkPreviewY; public int textY; - private int totalHeight; + public int totalHeight; private int additionalTimeOffsetY; private int keyboardHeight; private int linkBlockNum; @@ -799,6 +821,12 @@ public boolean isCellAttachedToWindow() { 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; @@ -812,7 +840,7 @@ public boolean isCellAttachedToWindow() { private boolean checkBoxAnimationInProgress; private float checkBoxAnimationProgress; private long lastCheckBoxAnimationTime; - private int checkBoxTranslation; + public int checkBoxTranslation; public boolean linkPreviewAbove; private boolean isSmallImage; @@ -861,6 +889,7 @@ public boolean isCellAttachedToWindow() { private boolean drawInstantView; private boolean pollInstantViewTouchesBottom; public int drawInstantViewType; + public String instantViewButtonText; private int imageBackgroundColor; private float imageBackgroundIntensity; private int imageBackgroundGradientColor1; @@ -956,6 +985,8 @@ public boolean isCellAttachedToWindow() { private RectF deleteProgressRect = new RectF(); private RectF rect = new RectF(); private TLObject photoParentObject; + private ImageLocation currentPhotoLocation; + private ImageLocation currentPhotoThumbLocation; private TLRPC.PhotoSize currentPhotoObject; private TLRPC.PhotoSize currentPhotoObjectThumb; private BitmapDrawable currentPhotoObjectThumbStripped; @@ -1003,7 +1034,7 @@ class LoadingDrawableLocation { private int seekBarY; private boolean useTranscribeButton; - private TranscribeButton transcribeButton; + public TranscribeButton transcribeButton; private float transcribeX, transcribeY; private StaticLayout durationLayout; @@ -1224,8 +1255,6 @@ class LoadingDrawableLocation { private boolean drawName; private boolean drawNameLayout; - private Paint closeSponsoredPaint; - private Path closeSponsoredPath; private ButtonBounce closeSponsoredBounce; private RectF closeSponsoredBounds; @@ -1307,6 +1336,7 @@ class LoadingDrawableLocation { private Drawable linkPreviewSelector; public int linkPreviewSelectorColor; + @Nullable private ChatMessageCellDelegate delegate; private MessageBackgroundDrawable backgroundDrawable; @@ -1516,7 +1546,20 @@ public void setProgress(float progress) { public void drawStatusWithImage(Canvas canvas, ImageReceiver imageReceiver, int radius) { String formatUserStatus = currentUser != null ? LocaleController.formatUserStatus(this.currentAccount, currentUser) : ""; - if (!NaConfig.INSTANCE.getShowOnlineStatus().Bool() || currentUser == null || currentUser.bot || !formatUserStatus.equals(LocaleController.getString("Online", R.string.Online))) { + if (!NaConfig.INSTANCE.getShowOnlineStatus().Bool() || currentUser == null || currentUser.bot) { + imageReceiver.draw(canvas); + return; + } + int diff = -60 * 60 - 1; + if (NaConfig.INSTANCE.getShowRecentOnlineStatus().Bool()) { + if (currentUser != null && currentUser.status != null) { + diff = currentUser.status.expires - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + } + if (diff < -60 * 60) { + imageReceiver.draw(canvas); + return; + } + } else if (!formatUserStatus.equals(LocaleController.getString("Online", R.string.Online))) { imageReceiver.draw(canvas); return; } @@ -1526,8 +1569,17 @@ public void drawStatusWithImage(Canvas canvas, ImageReceiver imageReceiver, int int spaceLeft = radius - circleRadius; int xCenterRegion = x - spaceLeft; int yCenterRegion = y - spaceLeft; + int colorOnline = diff > 0 + ? Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider) + : diff > -15 * 60 + ? android.graphics.Color.argb(255, 234, 234, 30) + : diff > -30 * 60 + ? android.graphics.Color.argb(255, 234, 132, 30) + : diff > -60 * 60 + ? android.graphics.Color.argb(255, 234, 30, 30) + : Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setColor(Theme.getColor(Theme.key_chats_onlineCircle)); + paint.setColor(colorOnline); canvas.save(); Path p = new Path(); p.addCircle(x - radius, y - radius, radius, Path.Direction.CW); @@ -1551,6 +1603,10 @@ public void setResourcesProvider(Theme.ResourcesProvider resourcesProvider) { } } + public Theme.ResourcesProvider getResourcesProvider() { + return resourcesProvider; + } + private void createPollUI() { if (pollAvatarImages != null) { return; @@ -2175,7 +2231,7 @@ private boolean checkLinkPreviewMotionEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); - if (x >= unmovedTextX && x <= unmovedTextX + backgroundWidth && y >= linkPreviewY && y <= linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(8 + (drawInstantView ? 46 : 0))) { + if (x >= unmovedTextX && x <= unmovedTextX + backgroundWidth - dp(14) && y >= linkPreviewY && y <= linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(8 + (drawInstantView ? 46 : 0))) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (descriptionLayout != null && y >= descriptionY && !currentMessageObject.preview) { try { @@ -2344,13 +2400,13 @@ private boolean checkLinkPreviewMotionEvent(MotionEvent event) { } 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; @@ -2886,7 +2942,7 @@ private boolean checkPhotoImageMotionEvent(MotionEvent event) { 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; } @@ -2964,7 +3020,7 @@ private boolean checkAudioMotionEvent(MotionEvent event) { 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 { @@ -3253,7 +3309,7 @@ private boolean checkBotButtonMotionEvent(MotionEvent event) { @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 { @@ -3293,6 +3349,12 @@ public boolean onTouchEvent(MotionEvent event) { if (!result) { result = checkTextBlockMotionEvent(event); } + if (!result && channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + result = channelRecommendationsCell.checkTouchEvent(event); + if (result) { + disallowLongPress = true; + } + } if (!result) { result = checkNameMotionEvent(event); } @@ -3350,6 +3412,9 @@ public boolean onTouchEvent(MotionEvent event) { if (!result) { result = giveawayMessageCell.checkMotionEvent(event); } + if (!result) { + result = giveawayResultsMessageCell.checkMotionEvent(event); + } if (event.getAction() == MotionEvent.ACTION_CANCEL) { spoilerPressed = null; @@ -3437,7 +3502,11 @@ public boolean onTouchEvent(MotionEvent event) { } else if (drawNameLayout && nameLayout != null && viaWidth != 0 && x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - AndroidUtilities.dp(4) && y <= nameY + AndroidUtilities.dp(20)) { forwardBotPressed = true; result = true; - } else if (drawSideButton != 0 && x >= sideStartX && x <= sideStartX + AndroidUtilities.dp(40) && y >= sideStartY && y <= sideStartY + AndroidUtilities.dp(32 + (drawSideButton == 3 && commentLayout != null ? 18 : 0))) { + } else if ( + drawSideButton != 0 && + x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && + y >= sideStartY - dp(24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)) + ) { if (currentMessageObject.isSent()) { sideButtonPressed = true; } @@ -3651,7 +3720,9 @@ public boolean onTouchEvent(MotionEvent event) { sideButtonPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (drawSideButton == 3) { + if (drawSideButton == 4) { + delegate.didPressSponsoredClose(); + } else if (drawSideButton == 3) { delegate.didPressCommentButton(this); } else { delegate.didPressSideButton(this); @@ -3660,7 +3731,10 @@ public boolean onTouchEvent(MotionEvent event) { } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { sideButtonPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= sideStartX && x <= sideStartX + AndroidUtilities.dp(40) && y >= sideStartY && y <= sideStartY + AndroidUtilities.dp(32 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)))) { + if (!( + x >= sideStartX - dp(24) && x <= sideStartX + dp(40) && + y >= sideStartY - dp(24) && y <= sideStartY + dp(38 + (drawSideButton == 3 && commentLayout != null ? 18 : 0)) + )) { sideButtonPressed = false; } } @@ -3871,7 +3945,9 @@ public void updatePlayingMessageProgress() { } } } - 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) { @@ -3902,7 +3978,9 @@ public void updatePlayingMessageProgress() { 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) { @@ -3937,6 +4015,11 @@ public void updatePlayingMessageProgress() { } } + private long overridenDuration = -1; + public void overrideDuration(long duration) { + overridenDuration = duration; + } + public void setFullyDraw(boolean draw) { fullyDraw = draw; } @@ -3958,7 +4041,7 @@ public void setVisiblePart(int position, int height, int parent, float parentOff this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; - if (!botButtons.isEmpty() && viewTop != visibleTop) { + if ((!botButtons.isEmpty() || channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) && viewTop != visibleTop) { invalidate(); } viewTop = visibleTop; @@ -4087,7 +4170,7 @@ private void didClickedImage() { 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); } @@ -4347,6 +4430,11 @@ public int getChecksY() { } } + private AudioVisualizerDrawable overridenAudioVisualizer; + public void overrideAudioVisualizer(AudioVisualizerDrawable audioVisualizerDrawable) { + this.overridenAudioVisualizer = audioVisualizerDrawable; + } + public TLRPC.User getCurrentUser() { return currentUser; } @@ -4415,6 +4503,9 @@ protected void onDetachedFromWindow() { if (mediaSpoilerEffect2 != null) { mediaSpoilerEffect2.detach(this); } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onDetachedFromWindow(); + } } @Override @@ -4501,6 +4592,9 @@ public void onAttachedToWindow() { mediaSpoilerEffect2.attach(this); } } + if (channelRecommendationsCell != null) { + channelRecommendationsCell.onAttachedToWindow(); + } } boolean imageReceiversAttachState; @@ -4524,6 +4618,7 @@ private void checkImageReceiversAttachState() { } } giveawayMessageCell.onAttachedToWindow(); + giveawayResultsMessageCell.onAttachedToWindow(); replyImageReceiver.onAttachedToWindow(); locationImageReceiver.onAttachedToWindow(); blurredPhotoImage.onAttachedToWindow(); @@ -4555,6 +4650,7 @@ private void checkImageReceiversAttachState() { photoImage.onDetachedFromWindow(); blurredPhotoImage.onDetachedFromWindow(); giveawayMessageCell.onDetachedFromWindow(); + giveawayResultsMessageCell.onDetachedFromWindow(); AnimatedEmojiSpan.release(this, animatedEmojiDescriptionStack); AnimatedEmojiSpan.release(this, animatedEmojiReplyStack); @@ -4779,8 +4875,8 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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; @@ -4791,7 +4887,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe drawVideoSize = false; canStreamVideo = false; animatingNoSound = 0; - if (MessagesController.getInstance(currentAccount).isChatNoForwardsWithOverride(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards && !NekoXConfig.disableFlagSecure)) { + if (messageObject.isSponsored()) { + drawSideButton = 4; + } else if (MessagesController.getInstance(currentAccount).isChatNoForwardsWithOverride(messageObject.getChatId()) || (messageObject.messageOwner != null && messageObject.messageOwner.noforwards && !NekoXConfig.disableFlagSecure)) { drawSideButton = 0; } else { drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) && (currentPosition == null || currentPosition.last) && !needHide ? 1 : 0; @@ -4881,6 +4979,8 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe docTitleLayout = null; drawImageButton = false; drawVideoImageButton = false; + currentPhotoLocation = null; + currentPhotoThumbLocation = null; currentPhotoObject = null; photoParentObject = null; currentPhotoObjectThumb = null; @@ -4902,6 +5002,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe useTranscribeButton = false; drawInstantView = false; drawInstantViewType = 0; + instantViewButtonText = null; drawForwardedName = false; drawCommentButton = false; photoImage.setSideClip(0); @@ -4944,7 +5045,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); @@ -5014,10 +5115,10 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe final int A = a; post(() -> { if (user != null) { - commentAvatarDrawables[A].setInfo(user); + commentAvatarDrawables[A].setInfo(currentAccount, user); commentAvatarImages[A].setForUserOrChat(user, commentAvatarDrawables[A]); } else if (chat != null) { - commentAvatarDrawables[A].setInfo(chat); + commentAvatarDrawables[A].setInfo(currentAccount, chat); commentAvatarImages[A].setForUserOrChat(chat, commentAvatarDrawables[A]); } else { commentAvatarDrawables[A].setInfo(id, "", ""); @@ -5073,11 +5174,24 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe drawCommentNumber = false; } - if (messageObject.isExpiredStory()) { + if (messageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + drawBackground = true; + drawForwardedName = false; + hasReplyQuote = false; + isReplyQuote = false; + replyNameLayout = null; + replyTextLayout = null; + forwardedNameLayout[0] = null; + forwardedNameLayout[1] = null; + drawName = false; + if (channelRecommendationsCell == null) { + channelRecommendationsCell = new ChannelRecommendationsCell(this); + } + channelRecommendationsCell.setMessageObject(messageObject); + } else if (messageObject.isExpiredStory()) { if (!messageIdChanged) { requestLayout(); } - // currentTimeString = null; drawBackground = true; if (expiredStoryView == null) { expiredStoryView = new ExpiredStoryView(); @@ -5096,7 +5210,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe forwardedNameLayout[0] = null; forwardedNameLayout[1] = null; drawName = false; - } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveaway()) { + } else if (messageObject.type == MessageObject.TYPE_TEXT || messageObject.type == MessageObject.TYPE_STORY_MENTION || messageObject.isGiveawayOrGiveawayResults() || messageObject.isSponsored()) { drawForwardedName = !isRepliesChat; int maxWidth; @@ -5144,12 +5258,32 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe TLRPC.Document androidThemeDocument = null; TL_stories.StoryItem storyItem = null; TLRPC.ThemeSettings androidThemeSettings = null; - if (messageObject.isGiveaway()) { + if (messageObject.isGiveawayOrGiveawayResults()) { hasLinkPreview = true; } if (!drawInstantView) { - if (messageObject.isGiveaway()) { + if (messageObject.isSponsored()) { + drawInstantView = true; + hasLinkPreview = true; + instantViewButtonText = messageObject.sponsoredButtonText; + if (messageObject.sponsoredBotApp != null) { + drawInstantViewType = 15; + } else if (messageObject.sponsoredWebPage != null) { + drawInstantViewType = 16; + } else if (messageObject.sponsoredChannelPost != 0) { + drawInstantViewType = 12; + } else { + drawInstantViewType = 1; + long id = MessageObject.getPeerId(messageObject.messageOwner.from_id); + if (id > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); + if (user != null && user.bot) { + drawInstantViewType = 10; + } + } + } + } else if (messageObject.isGiveawayOrGiveawayResults()) { drawInstantView = true; drawInstantViewType = 19; } else if ("telegram_channel_boost".equals(webpageType)) { @@ -5321,6 +5455,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); @@ -5340,12 +5477,23 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe setMessageObjectInternal(messageObject); giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); + giveawayResultsMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth); backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? AndroidUtilities.dp(10) : 0); - totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset; + if (messageObject.isSponsored()) { + totalHeight = AndroidUtilities.dp(22.5f); + } else { + totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset; + } if (!reactionsLayoutInBubble.isSmall) { - reactionsLayoutInBubble.measure(messageObject.isGiveaway() ? giveawayMessageCell.getMeasuredWidth() : maxWidth, Gravity.LEFT); + 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) { @@ -5376,7 +5524,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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)); @@ -5389,6 +5539,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe String title; CharSequence author; String description; + TLObject peerPhoto = null; TLRPC.Photo photo; TLRPC.Document document; WebFile webDocument; @@ -5396,7 +5547,43 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe boolean smallImage; String type; final int smallImageSide = AndroidUtilities.dp(48), smallSideMargin = AndroidUtilities.dp(10); - if (drawInstantViewType == 19) { + CharSequence overrideDescrption = null; + if (messageObject.isSponsored()) { + site_name = LocaleController.getString(messageObject.sponsoredRecommended ? R.string.SponsoredMessage2Recommended : R.string.SponsoredMessage2); + title = messageObject.customName != null ? messageObject.customName : getAuthorName(); + webDocument = null; + overrideDescrption = messageObject.messageText; + description = overrideDescrption != null ? overrideDescrption.toString() : null; + photo = null; + author = null; + document = null; + if (messageObject.sponsoredBotApp != null) { + photo = messageObject.sponsoredBotApp.photo; + } else if (messageObject.sponsoredWebPage != null) { + photo = messageObject.sponsoredWebPage.photo; + } else if (messageObject.sponsoredChatInvite != null && messageObject.sponsoredChatInvite.chat != null) { + peerPhoto = messageObject.sponsoredChatInvite.chat; + currentPhotoLocation = ImageLocation.getForChat(messageObject.sponsoredChatInvite.chat, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForChat(messageObject.sponsoredChatInvite.chat, ImageLocation.TYPE_SMALL); + } else if (messageObject.sponsoredShowPeerPhoto) { + peerPhoto = messageObject.getFromPeerObject(); + if (peerPhoto instanceof TLRPC.User) { + currentPhotoLocation = ImageLocation.getForUser((TLRPC.User) peerPhoto, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForUser((TLRPC.User) peerPhoto, ImageLocation.TYPE_SMALL); + } else if (peerPhoto instanceof TLRPC.Chat) { + currentPhotoLocation = ImageLocation.getForChat((TLRPC.Chat) peerPhoto, ImageLocation.TYPE_BIG); + currentPhotoThumbLocation = ImageLocation.getForChat((TLRPC.Chat) peerPhoto, ImageLocation.TYPE_SMALL); + } + } + if (photo == null && messageObject.sponsoredChatInvite != null) { + photo = messageObject.sponsoredChatInvite.photo; + } + duration = 0; + type = null; + isSmallImage = true; + linkPreviewAbove = false; + smallImage = true; + } else if (drawInstantViewType == 19) { site_name = null; title = null; webDocument = null; @@ -5531,7 +5718,10 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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 { @@ -5597,11 +5787,15 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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(); } @@ -5676,12 +5870,14 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } int restLines = 0; boolean allowAllLines = site_name != null && site_name.toString().toLowerCase().equals("twitter"); - boolean isRTL = AndroidUtilities.isRTL(messageObject.linkDescription); + CharSequence text = overrideDescrption != null ? overrideDescrption : messageObject.linkDescription; + boolean isRTL = AndroidUtilities.isRTL(text); + int maxLines = allowAllLines ? 100 : (currentMessageObject.isRepostPreview ? 3 : 6); if (restLinesCount == 3 && !isSmallImage) { - descriptionLayout = StaticLayoutEx.createStaticLayout(messageObject.linkDescription, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, allowAllLines ? 100 : 6); + descriptionLayout = StaticLayoutEx.createStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, maxLines); } else { restLines = restLinesCount; - descriptionLayout = generateStaticLayout(messageObject.linkDescription, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide : 0), linkPreviewMaxWidth - smallImageSide - (isRTL ? 0 : smallSideMargin), restLinesCount, allowAllLines ? 100 : 6); + descriptionLayout = generateStaticLayout(text, Theme.chat_replyTextPaint, linkPreviewMaxWidth - (isRTL ? smallImageSide + 2 * smallSideMargin : 0), linkPreviewMaxWidth - smallImageSide - 2 * smallSideMargin, restLinesCount, maxLines); } animatedEmojiDescriptionStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiDescriptionStack, descriptionLayout); @@ -5693,7 +5889,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe descriptionLayoutLeft = descriptionLayout.getWidth(); for (int a = 0; a < descriptionLayout.getLineCount(); a++) { descriptionLayoutLeft = (int) Math.min(descriptionLayoutLeft, descriptionLayout.getLineLeft(a)); - float width = descriptionLayout.getLineWidth(a); + float width = Math.min(descriptionLayout.getWidth(), descriptionLayout.getLineWidth(a)); if (a < restLines || restLines != 0 && descriptionLayoutLeft != 0 && isSmallImage) { width += smallImageSide + smallSideMargin; } @@ -5760,7 +5956,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); @@ -5948,6 +6144,17 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } } + } else if (peerPhoto != null) { + checkOnlyButtonPressed = false; + if (peerPhoto instanceof TLRPC.User) { + TLRPC.UserProfilePhoto userProfilePhoto = ((TLRPC.User) peerPhoto).photo; + photoParentObject = userProfilePhoto; + currentPhotoObjectThumbStripped = userProfilePhoto.strippedBitmap; + } else if (peerPhoto instanceof TLRPC.Chat) { + TLRPC.ChatPhoto chatPhoto = ((TLRPC.Chat) peerPhoto).photo; + photoParentObject = chatPhoto; + currentPhotoObjectThumbStripped = chatPhoto.strippedBitmap; + } } else if (photo != null) { boolean isPhoto = type != null && type.equals("photo"); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, isPhoto || !smallImage ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !isPhoto); @@ -5969,7 +6176,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } if (documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { - if (currentPhotoObject != null || webDocument != null || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { + if (currentPhotoObject != null || currentPhotoLocation != null || webDocument != null || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER || documentAttachType == DOCUMENT_ATTACH_TYPE_THEME) { drawImageButton = photo != null && !smallImage || type != null && (type.equals("photo") || type.equals("document") && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER || type.equals("gif") || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_WALLPAPER); if (isSmallImage) { drawImageButton = false; @@ -6137,7 +6344,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } 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) )) { @@ -6164,7 +6371,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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)) { @@ -6178,9 +6385,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } else { boolean photoExist = messageObject.mediaExists; String fileName = FileLoader.getAttachFileName(currentPhotoObject); - if (hasGamePreview || photoExist || DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + if (hasGamePreview || photoExist || DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || currentMessageObject.isSponsored()) { photoNotSet = false; - photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + if (currentPhotoLocation != null) { + photoImage.setImage(currentPhotoLocation, currentPhotoFilter, currentPhotoThumbLocation, currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + } else { + photoImage.setImage(ImageLocation.getForObject(currentPhotoObject, photoParentObject), currentPhotoFilter, ImageLocation.getForObject(currentPhotoObjectThumb, photoParentObject), currentPhotoFilterThumb, currentPhotoObjectThumbStripped, 0, null, messageObject, 0); + } } else { photoNotSet = true; if (currentPhotoObjectThumb != null || currentPhotoObjectThumbStripped != null) { @@ -6265,11 +6476,11 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); } - if (!hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { linkPreviewHeight += AndroidUtilities.dp(6); totalHeight += AndroidUtilities.dp(6); } - if (!hasInvoicePreview && !currentMessageObject.isSponsored() && !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); @@ -6381,7 +6592,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } boolean hasName; if (user != null) { - contactAvatarDrawable.setInfo(user); + contactAvatarDrawable.setInfo(currentAccount, user); hasName = true; } else if (!TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).first_name) || !TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).last_name)) { contactAvatarDrawable.setInfo(0, MessageObject.getMedia(messageObject.messageOwner).first_name, MessageObject.getMedia(messageObject.messageOwner).last_name); @@ -6662,7 +6873,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe TLRPC.Peer id = media.results.recent_voters.get(a); TLObject user = MessagesController.getInstance(currentAccount).getUserOrChat(DialogObject.getPeerDialogId(id)); if (user != null) { - pollAvatarDrawables[a].setInfo(user); + pollAvatarDrawables[a].setInfo(currentAccount, user); pollAvatarImages[a].setForUserOrChat(user, pollAvatarDrawables[a]); } else { pollAvatarDrawables[a].setInfo(DialogObject.getPeerDialogId(id), "", ""); @@ -6856,7 +7067,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } 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; @@ -6866,7 +7077,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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; } @@ -7035,13 +7246,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe updateCurrentUserAndChat(); if (currentUser != null) { - contactAvatarDrawable.setInfo(currentUser); + contactAvatarDrawable.setInfo(currentAccount, currentUser); locationImageReceiver.setForUserOrChat(currentUser, contactAvatarDrawable); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; } - contactAvatarDrawable.setInfo(currentChat); + contactAvatarDrawable.setInfo(currentAccount, currentChat); locationImageReceiver.setForUserOrChat(currentChat, contactAvatarDrawable); } else { locationImageReceiver.setImage(null, null, contactAvatarDrawable, null, null, 0); @@ -7211,7 +7422,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe photoWidth = Math.max(512, photoWidth); photoHeight = Math.max(512, photoHeight); if (MessageObject.isTextColorEmoji(messageObject.getDocument())) { - photoImage.setColorFilter(Theme.chat_animatedEmojiTextColorFilter); + photoImage.setColorFilter(getAdaptiveEmojiColorFilter(0, getThemedColor(Theme.key_windowBackgroundWhiteBlackText))); } } float maxHeight; @@ -7648,7 +7859,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } 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); @@ -7847,7 +8058,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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) { @@ -7857,6 +8068,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } + final int cacheType = currentMessageObject.shouldEncryptPhotoOrVideo() ? ImageLoader.CACHE_TYPE_ENCRYPTED : ImageLoader.CACHE_TYPE_NONE; if (autoPlayingMedia) { photoImage.setAllowStartAnimation(true); photoImage.startAnimation(); @@ -7883,7 +8095,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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)); @@ -7897,11 +8109,11 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); } @@ -7933,19 +8145,19 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); } @@ -7959,19 +8171,19 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe 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); } } } @@ -8215,32 +8427,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } - if (messageObject.isSponsored()) { - drawInstantView = true; - if (messageObject.sponsoredWebPage != null) { - drawInstantViewType = 16; - } else if (messageObject.sponsoredChannelPost != 0) { - drawInstantViewType = 12; - } else { - drawInstantViewType = 1; - } - long id = MessageObject.getPeerId(messageObject.messageOwner.from_id); - if (id > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(id); - if (user != null && user.bot) { - drawInstantViewType = 10; - } - } - createInstantViewButton(); - } - botButtons.clear(); if (messageIdChanged) { botButtonsByData.clear(); 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) { @@ -8548,6 +8741,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe if (transcribeButton != null) { transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), !messageIdChanged); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), !messageIdChanged); + transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), !messageIdChanged); } updateWaveform(); updateButtonState(false, !messageIdChanged && !messageObject.cancelEditing, true); @@ -8684,7 +8878,7 @@ public void invalidate() { } if (replySelector != null) { replySelectorPressed = false; - replySelector.setState(new int[]{}); + replySelector.setState(StateSet.NOTHING); invalidate(); } if (nameStatusSelector != null) { @@ -8754,6 +8948,7 @@ public void invalidate() { timePressed = false; gamePreviewPressed = false; giveawayMessageCell.setButtonPressed(false); + giveawayResultsMessageCell.setButtonPressed(false); if (pressedVoteButton != -1 || pollHintPressed || psaHintPressed || instantPressed || otherPressed || commentButtonPressed) { instantPressed = commentButtonPressed = false; @@ -8876,6 +9071,10 @@ public void invalidate() { if (currentMessageObject == null) { return; } + if (invalidateCallback != null) { + invalidateCallback.run(); + return; + } super.invalidate(); if ((invalidatesParent || currentMessagesGroup != null && invalidateParentForce()) && getParent() != null) { View parent = (View) getParent(); @@ -8890,12 +9089,21 @@ public void invalidate() { } } + 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) { @@ -8989,6 +9197,16 @@ public void onSeekBarReleased() { 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) { @@ -9026,15 +9244,28 @@ private void updateWaveform() { currentMessageObject != null && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && ( - UserConfig.getInstance(currentAccount).isPremium() || + UserConfig.getInstance(currentAccount).isPremium() + || + MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber > 0 && + currentMessageObject.getDuration() <= MessagesController.getInstance(currentAccount).transcribeAudioTrialDurationMax && ( + currentMessageObject.messageOwner != null && ( + !TextUtils.isEmpty(currentMessageObject.messageOwner.voiceTranscription) || + currentMessageObject.messageOwner.voiceTranscriptionFinal + ) || + TranscribeButton.canTranscribeTrial(currentMessageObject) || true + ) + || + MessagesController.getInstance(currentAccount).transcribeAudioTrialWeeklyNumber <= 0 && + !MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && !currentMessageObject.isOutOwner() && ( currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60 - ) && !MessagesController.getInstance(currentAccount).premiumLocked + ) ) && ( 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); } @@ -9252,14 +9483,14 @@ private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) totalHeight += AndroidUtilities.dp(14); } } else { - newLineForTime = !linkPreviewAbove && (hasLinkPreview || hasOldCaptionPreview || hasGamePreview || hasInvoicePreview) || maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; + newLineForTime = !linkPreviewAbove && (hasLinkPreview && !currentMessageObject.isSponsored() || hasOldCaptionPreview || hasGamePreview || hasInvoicePreview) || maxWidth - lastLineWidth < timeMore || currentMessageObject.hasRtl; } int newLineForTimeDp = 14; if ( currentMessageObject.hasCodeAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) || currentMessageObject.hasQuoteAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) - || currentMessageObject.isGiveaway() + || currentMessageObject.isGiveawayOrGiveawayResults() ) { newLineForTime = true; newLineForTimeDp = 18; @@ -9281,9 +9512,9 @@ private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) } public boolean setHighlightedText(String text) { - return setHighlightedText(text, false); + return setHighlightedText(text, false, -1); } - public boolean setHighlightedText(String text, boolean quote) { + public boolean setHighlightedText(String text, boolean quote, int quote_offset) { if (highlightedQuote && !quote && TextUtils.isEmpty(text)) { return false; } @@ -9323,7 +9554,7 @@ public boolean setHighlightedText(String text, boolean quote) { int start = -1, length = -1; String punctuationsChars = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"; if (quote) { - start = message.indexOf(text); + start = MessageObject.findQuoteStart(message, text, quote_offset); length = text.length(); } else { for (int a = 0, N1 = message.length(); a < N1; a++) { @@ -9592,7 +9823,7 @@ public void setIsUpdating(boolean value) { } 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; @@ -9602,6 +9833,17 @@ public void setMessageObject(MessageObject messageObject, MessageObject.GroupedM } } + 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) { @@ -9718,7 +9960,9 @@ private void createInstantViewButton() { if (drawInstantView && instantViewLayout == null) { String str; instantWidth = AndroidUtilities.dp(12 + 9 + 12); - if (drawInstantViewType == 12) { + if (instantViewButtonText != null) { + str = instantViewButtonText; + } else if (drawInstantViewType == 12) { str = LocaleController.getString("OpenChannelPost", R.string.OpenChannelPost); } else if (drawInstantViewType == 1) { str = LocaleController.getString("OpenChannel", R.string.OpenChannel); @@ -9810,7 +10054,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { inLayout = false; } updateSelectionTextPosition(); - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), needHide ? 0: totalHeight + keyboardHeight); + setMeasuredDimension( + isWidthAdaptive() ? getBoundsRight() - getBoundsLeft() : MeasureSpec.getSize(widthMeasureSpec), + needHide ? 0: totalHeight + keyboardHeight + ); } public void forceResetMessageObject() { @@ -9887,7 +10134,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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) { @@ -9908,7 +10155,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto if (currentMessageObject.isAnyKindOfSticker()) { timeX = Math.max(0, timeX); } - if (isAvatarVisible) { + if (isAvatarVisible && !isWidthAdaptive()) { timeX += AndroidUtilities.dp(48); } if (shouldDrawTimeOnMedia()) { @@ -9931,7 +10178,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } 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) { @@ -9955,14 +10202,16 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto if (currentMessageObject.type == MessageObject.TYPE_TEXT) { textY = AndroidUtilities.dp(10) + namesOffset; - if (linkPreviewAbove) { + if (currentMessageObject.isSponsored()) { + linkPreviewY = textY + AndroidUtilities.dp(14); + } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += AndroidUtilities.dp(44); } } else { - linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(!currentMessageObject.isSponsored() ? 10 : 0); + linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(10); } } if (isRoundVideo) { @@ -9973,16 +10222,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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); @@ -10055,7 +10302,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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); @@ -10080,7 +10327,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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); @@ -10096,7 +10343,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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); @@ -10126,7 +10373,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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); @@ -10167,7 +10414,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } 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) { @@ -10397,7 +10644,7 @@ public void drawContent(Canvas canvas, boolean preview) { 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()))) { @@ -10490,7 +10737,7 @@ public void drawContent(Canvas canvas, boolean preview) { canvas.save(); canvas.scale(-1f, 1, photoImage.getCenterX(), photoImage.getCenterY()); if (allowDrawPhotoImage()) { - imageDrawn = photoImage.draw(canvas); + imageDrawn = drawPhotoImage(canvas); } else { imageDrawn = true; } @@ -10500,7 +10747,7 @@ public void drawContent(Canvas canvas, boolean preview) { canvas.restore(); } else { if (allowDrawPhotoImage()) { - imageDrawn = photoImage.draw(canvas); + imageDrawn = drawPhotoImage(canvas); } else { imageDrawn = true; } @@ -10565,7 +10812,7 @@ public void drawContent(Canvas canvas, boolean preview) { } } 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))); @@ -10593,6 +10840,7 @@ public void drawContent(Canvas canvas, boolean preview) { } radialProgress.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); + radialProgress.iconScale = 1f; radialProgress.draw(canvas); canvas.save(); @@ -10676,7 +10924,9 @@ public void drawContent(Canvas canvas, boolean preview) { 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); @@ -10693,7 +10943,8 @@ public void drawContent(Canvas canvas, boolean preview) { 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; @@ -10774,6 +11025,7 @@ protected void onOpen() { }; transcribeButton.setOpen(currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionOpen && currentMessageObject.messageOwner.voiceTranscriptionFinal && TranscribeButton.isVideoTranscriptionOpen(currentMessageObject), false); transcribeButton.setLoading(TranscribeButton.isTranscribing(currentMessageObject), false); + transcribeButton.setLock(TranscribeButton.showTranscribeLock(currentMessageObject), false); } if (drawSideButton != 0) { transcribeX = AndroidUtilities.lerp( @@ -10919,7 +11171,7 @@ protected void onOpen() { canvas.save(); canvas.translate(linkX + AndroidUtilities.dp(10) + descriptionX, descriptionY); SpoilerEffect.layoutDrawMaybe(descriptionLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); } drawTime = true; @@ -11105,6 +11357,8 @@ public void onAnimationEnd(Animator animation) { animator.start(); } + public boolean drawingToBitmap; + private void drawBlurredPhoto(Canvas canvas) { if (currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress == 1f) { return; @@ -11139,7 +11393,7 @@ private void drawBlurredPhoto(Canvas canvas) { 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; @@ -11164,6 +11418,9 @@ private float getUseTranscribeButtonProgress() { } 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()) { @@ -11216,6 +11473,99 @@ private void updateReactionLayoutPosition() { } } + 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; @@ -11236,9 +11586,6 @@ public void drawLinkPreview(Canvas canvas, float alpha) { linkX = unmovedTextX + AndroidUtilities.dp(1); } else if (currentMessageObject.isSponsored()) { startY = this.linkPreviewY - AndroidUtilities.dp(2); - if (hasNewLineForTime) { - startY += AndroidUtilities.dp(12); - } linkX = unmovedTextX + AndroidUtilities.dp(1); } else { if (currentMessageObject.isOutOwner()) { @@ -11278,10 +11625,13 @@ public void drawLinkPreview(Canvas canvas, float alpha) { } 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.isSponsored() && !currentMessageObject.isGiveaway()) { + if (!hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { drawInstantButtonInside = true; if (linkPreviewBounce == null) { @@ -11294,8 +11644,10 @@ public void drawLinkPreview(Canvas canvas, float alpha) { AndroidUtilities.rectTmp.set(linkX, linkPreviewY - AndroidUtilities.dp(6), linkX + width, linkPreviewY + linkPreviewHeight + (drawInstantButtonInside && drawInstantView ? AndroidUtilities.dp(42) : 0)); linkLine.setLoading(loading); - float rad = (float) Math.floor(SharedConfig.bubbleRadius / 3); - linkLine.drawBackground(canvas, AndroidUtilities.rectTmp, rad, rad, rad, alpha); + float rad = (float) Math.floor(SharedConfig.bubbleRadius / (currentMessageObject.isSponsored() ? 2f : 3f)); + 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) { @@ -11331,7 +11683,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { 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); @@ -11553,13 +11905,13 @@ public void drawLinkPreview(Canvas canvas, float alpha) { paint.setAlpha((int) (wasAlpha * alpha)); descriptionLayout.draw(canvas); paint.setAlpha(wasAlpha); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, descriptionLayout, animatedEmojiDescriptionStack, 0, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, descriptionLayout.getPaint().getColor())); canvas.restore(); paint.linkColor = getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); } - 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); } @@ -11677,6 +12029,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { canvas.restore(); } giveawayMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); + giveawayResultsMessageCell.draw(canvas, namesOffset, linkX, resourcesProvider); if (drawInstantView) { Drawable instantDrawable; @@ -11816,12 +12169,12 @@ private float isSmallImage() { } 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); @@ -11983,14 +12336,16 @@ public void layoutTextXY(boolean parent) { textY += AndroidUtilities.dp(5); } } - if (linkPreviewAbove) { + if (currentMessageObject.isSponsored()) { + linkPreviewY = textY + AndroidUtilities.dp(14); + } else if (linkPreviewAbove) { linkPreviewY = textY + AndroidUtilities.dp(10); textY += linkPreviewHeight + AndroidUtilities.dp(13); - if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isSponsored() && !currentMessageObject.isGiveaway()) { + if (drawInstantView && !hasInvoicePreview && !currentMessageObject.isGiveawayOrGiveawayResults()) { textY += AndroidUtilities.dp(44); } } else { - linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(!currentMessageObject.isSponsored() ? 10 : 0); + linkPreviewY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(10); } unmovedTextX = textX; if (currentMessageObject.textXOffset != 0 && replyNameLayout != null) { @@ -12005,7 +12360,7 @@ public void layoutTextXY(boolean parent) { } public void drawMessageText(Canvas canvas) { - if (currentMessageObject == null) { + if (currentMessageObject == null || currentMessageObject.isSponsored()) { return; } float textY = this.textY; @@ -12285,7 +12640,7 @@ public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList 0) { @@ -13084,14 +13440,14 @@ private void didPressButton(boolean animated, boolean video) { 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()); @@ -13166,7 +13522,7 @@ private void didPressButton(boolean animated, boolean video) { 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); @@ -13181,7 +13537,7 @@ private void didPressButton(boolean animated, boolean video) { 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; @@ -13209,9 +13565,11 @@ private void didPressButton(boolean animated, boolean video) { 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); @@ -13252,7 +13610,7 @@ public void onSuccessDownload(String fileName) { 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)) { @@ -13264,7 +13622,7 @@ public void onSuccessDownload(String fileName) { 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 { @@ -13528,9 +13886,9 @@ private void createLoadingProgressLayout(long loadedSize, long totalSize) { 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); } } @@ -13601,13 +13959,11 @@ private void measureTime(MessageObject messageObject) { } } if (currentMessageObject.isSponsored()) { - if (currentMessageObject.sponsoredRecommended) { - timeString = LocaleController.getString("SponsoredMessageRecommended", R.string.SponsoredMessageRecommended); - } else { - timeString = LocaleController.getString("SponsoredMessage", R.string.SponsoredMessage); - } + timeString = ""; } else if (currentMessageObject.scheduled && currentMessageObject.messageOwner.date == 0x7FFFFFFE) { timeString = ""; + } else if (currentMessageObject.isRepostPreview) { + timeString = LocaleController.formatSmallDateChat(messageObject.messageOwner.date) + ", " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); } else if (edited) { String customStr = NaConfig.INSTANCE.getCustomEditedMessage().String(); timeString = (customStr.equals("") ? LocaleController.getString("EditedMessage", R.string.EditedMessage) : customStr) + " " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); @@ -13667,7 +14023,7 @@ private void measureTime(MessageObject messageObject) { timeWidth += AndroidUtilities.dp(18); } } - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { reactionsLayoutInBubble.measure(Integer.MAX_VALUE, Gravity.LEFT); timeWidth += reactionsLayoutInBubble.width; } @@ -13730,8 +14086,8 @@ private boolean isOpenChatByShare(MessageObject messageObject) { 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) { @@ -14117,7 +14473,7 @@ protected void onClick() { 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()); @@ -14213,7 +14569,7 @@ protected void onClick() { 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); @@ -14227,7 +14583,7 @@ protected void onClick() { 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())) { @@ -14400,7 +14756,7 @@ protected void onClick() { 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); } } @@ -14425,15 +14781,16 @@ protected void onClick() { } 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; @@ -14486,7 +14843,7 @@ protected void onClick() { 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()); @@ -14530,16 +14887,19 @@ private String getNameFromDialogId(long fromId) { return name; } - private boolean isNeedAuthorName() { + protected boolean isNeedAuthorName() { if (currentMessageObject.forceAvatar) { return true; } - if (currentMessageObject.isGiveaway()) { + if (currentMessageObject.isSponsored()) { + return false; + } + 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 ); } @@ -14550,6 +14910,9 @@ private String getAuthorName() { } else if (currentChat != null) { return currentChat.title; } else if (currentMessageObject != null && currentMessageObject.isSponsored()) { + if (currentMessageObject.sponsoredBotApp != null) { + return currentMessageObject.sponsoredBotApp.title; + } if (currentMessageObject.sponsoredWebPage != null) { return currentMessageObject.sponsoredWebPage.site_name; } @@ -14624,7 +14987,7 @@ public boolean isDrawPinnedBottom() { } public void drawCheckBox(Canvas canvas) { - if (currentMessageObject != null && !currentMessageObject.isSending() && !currentMessageObject.isSendError() && checkBox != null && (checkBoxVisible || checkBoxAnimationInProgress) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { + if (currentMessageObject != null && !currentMessageObject.isSending() && currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL && !currentMessageObject.isSendError() && checkBox != null && (checkBoxVisible || checkBoxAnimationInProgress) && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0)) { canvas.save(); float y = getY(); if (currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { @@ -14722,6 +15085,20 @@ private void setupTextColors() { } } + 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) { @@ -14735,6 +15112,14 @@ protected void onDraw(Canvas canvas) { return; } + if (channelRecommendationsCell != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + if (delegate == null || delegate.canDrawOutboundsContent()) { + channelRecommendationsCell.draw(canvas); + } + transitionParams.recordDrawingState(); + return; + } + setupTextColors(); if (documentAttach != null) { @@ -14785,6 +15170,10 @@ protected void onDraw(Canvas canvas) { } } } + if (isWidthAdaptive()) { + canvas.save(); + canvas.translate(-getBoundsLeft(), 0); + } drawBackgroundInternal(canvas, false); if (isHighlightedAnimated) { @@ -14976,6 +15365,9 @@ protected void onDraw(Canvas canvas) { if (restore != Integer.MIN_VALUE) { canvas.restoreToCount(restore); } + if (isWidthAdaptive()) { + canvas.restore(); + } updateSelectionTextPosition(); } @@ -15091,7 +15483,7 @@ public void drawBackgroundInternal(Canvas canvas, boolean fromParent) { 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) { @@ -15379,6 +15771,50 @@ public boolean drawBackgroundInParent() { return false; } + public void drawServiceBackground(Canvas canvas, RectF rect, float radius, float alpha) { + applyServiceShaderMatrix(); + if (alpha != 1f) { + int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); + canvas.drawRoundRect(rect, radius, radius, getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + } else { + canvas.drawRoundRect(rect, radius, radius, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); + } + if (hasGradientService()) { + if (alpha != 1f) { + int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); + canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } else { + canvas.drawRoundRect(rect, radius, radius, Theme.chat_actionBackgroundGradientDarkenPaint); + } + } + } + + public void drawServiceBackground(Canvas canvas, Path path, float alpha) { + applyServiceShaderMatrix(); + if (alpha != 1f) { + int oldAlpha = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (alpha * oldAlpha)); + canvas.drawPath(path, getThemedPaint(Theme.key_paint_chatActionBackground)); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha); + } else { + canvas.drawPath(path, getThemedPaint(sideButtonPressed ? Theme.key_paint_chatActionBackgroundSelected : Theme.key_paint_chatActionBackground)); + } + if (hasGradientService()) { + if (alpha != 1f) { + int oldAlpha = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (alpha * oldAlpha)); + canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha); + } else { + canvas.drawPath(path, Theme.chat_actionBackgroundGradientDarkenPaint); + } + } + } + public void drawCommentButton(Canvas canvas, float alpha) { if (drawSideButton != 3) { return; @@ -15453,6 +15889,9 @@ private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, f } public boolean hasOutboundsContent() { + if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + return true; + } if (getAlpha() != 1f) { return false; } @@ -15470,6 +15909,13 @@ public boolean hasOutboundsContent() { } public void drawOutboundsContent(Canvas canvas) { + if (channelRecommendationsCell != null && currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + channelRecommendationsCell.draw(canvas); + return; + } + if (currentMessageObject == null) { + return; + } if (!enterTransitionInProgress) { drawAnimatedEmojis(canvas, 1f); } @@ -15513,12 +15959,11 @@ public void drawOutboundsContent(Canvas canvas) { } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = currentMessageObject.sponsoredChatInvite.color; } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite != null && currentMessageObject.sponsoredChatInvite.chat != null) { - colorId = (currentMessageObject.sponsoredChatInvite.chat.flags2 & 64) != 0 ? currentMessageObject.sponsoredChatInvite.chat.color : (int) (currentMessageObject.sponsoredChatInvite.chat.id % 7); + colorId = ChatObject.getColorId(currentMessageObject.sponsoredChatInvite.chat); } else if (currentMessageObject.isFromUser() && currentUser != null) { - colorId = (currentUser.flags2 & 128) != 0 ? currentUser.color : (int) (currentUser.id % 7); - if (currentUser.self) colorId = PeerColorHelper.replaceColor(colorId); + colorId = UserObject.getColorId(currentUser); } else { - colorId = (currentChat.flags2 & 64) != 0 ? currentChat.color : (int) (currentChat.id % 7); + colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { color = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]); @@ -15526,7 +15971,7 @@ public void drawOutboundsContent(Canvas canvas) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - color = peerColor.getColor1(); + color = peerColor.getColor(0, resourcesProvider); } else { color = getThemedColor(Theme.key_chat_inForwardedNameText); } @@ -15602,6 +16047,9 @@ public void drawAnimatedEmojis(Canvas canvas, float alpha) { } private void drawAnimatedEmojiMessageText(Canvas canvas, float alpha) { + if (currentMessageObject == null || currentMessageObject.isSponsored()) { + return; + } float textY = this.textY; if (transitionParams.animateText) { textY = transitionParams.animateFromTextY * (1f - transitionParams.animateChangeProgress) + this.textY * transitionParams.animateChangeProgress; @@ -15631,7 +16079,7 @@ private void drawAnimatedEmojiMessageText(Canvas canvas, float alpha) { } private void drawAnimatedEmojiMessageText(float textX, float textY, Canvas canvas, ArrayList textLayoutBlocks, AnimatedEmojiSpan.EmojiGroupedSpans stack, boolean origin, float alpha, float rtlOffset, boolean drawAllBlocks) { - if (textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { + if (currentMessageObject == null || textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } int firstVisibleBlockNum; @@ -15664,7 +16112,11 @@ private void drawAnimatedEmojiMessageText(float textX, float textY, Canvas canva if (transitionParams.messageEntering) { top = bottom = 0; } - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, block.textLayout, stack, 0, block.spoilers, top, bottom, drawingYOffset, alpha, currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + int textColorKey = currentMessageObject.isOutOwner() ? Theme.key_chat_messageTextOut : Theme.key_chat_messageTextIn; + if (currentMessageObject.shouldDrawWithoutBackground()) { + textColorKey = Theme.key_windowBackgroundWhiteBlackText; + } + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, block.textLayout, stack, 0, block.spoilers, top, bottom, drawingYOffset, alpha, getAdaptiveEmojiColorFilter(0, getThemedColor(textColorKey))); canvas.restore(); } } @@ -15709,23 +16161,30 @@ private void drawSideButton(Canvas canvas) { sideStartX += currentMessagesGroup.transitionParams.offsetRight - animationOffsetX; } } - sideStartY = layoutHeight + transitionParams.deltaBottom - AndroidUtilities.dp(41); - if (currentMessageObject.type == MessageObject.TYPE_EMOJIS && currentMessageObject.textWidth < timeTextWidth) { - sideStartY -= AndroidUtilities.dp(22); - } - if (currentMessagesGroup != null) { - sideStartY += currentMessagesGroup.transitionParams.offsetBottom; - if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { - sideStartY -= getTranslationY(); + if (drawSideButton == 4) { + sideStartY = AndroidUtilities.dp(6); + } else { + sideStartY = layoutHeight + transitionParams.deltaBottom - AndroidUtilities.dp(41); + if (currentMessageObject.type == MessageObject.TYPE_EMOJIS && currentMessageObject.textWidth < timeTextWidth) { + sideStartY -= AndroidUtilities.dp(22); } - } - if (!reactionsLayoutInBubble.isSmall) { - if (isRoundVideo) { - sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); - } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { - sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); + if (currentMessagesGroup != null) { + sideStartY += currentMessagesGroup.transitionParams.offsetBottom; + if (currentMessagesGroup.transitionParams.backgroundChangeBounds) { + sideStartY -= getTranslationY(); + } + } + if (currentMessageObject.shouldDrawReactions() && !reactionsLayoutInBubble.isSmall) { + if (isRoundVideo) { + sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress) * (1f - getVideoTranscriptionProgress()); + } else if (reactionsLayoutInBubble.drawServiceShaderBackground > 0) { + sideStartY -= reactionsLayoutInBubble.getCurrentTotalHeight(transitionParams.animateChangeProgress); + } } } + if (drawSideButton != 4 && sideStartY < (layoutHeight - AndroidUtilities.dp(32)) / 2f) { + sideStartY = (layoutHeight - AndroidUtilities.dp(32)) / 2f; + } if (!currentMessageObject.isOutOwner() && isRoundVideo && !hasLinkPreview) { float offsetSize = isAvatarVisible ? ((AndroidUtilities.roundPlayingMessageSize - AndroidUtilities.roundMessageSize) * 0.7f) : AndroidUtilities.dp(50); float offsetX = isPlayingRound ? offsetSize * (1f - getVideoTranscriptionProgress()) : 0; @@ -15762,6 +16221,16 @@ private void drawSideButton(Canvas canvas) { if (currentMessageObject.isOutOwner()) { canvas.restore(); } + } else if (drawSideButton == 4) { + final int scx = (int) (sideStartX + AndroidUtilities.dp(16)), scy = (int) (sideStartY + AndroidUtilities.dp(16)); + Drawable drawable = getThemedDrawable(Theme.key_drawable_closeIcon); + final int shw = drawable.getIntrinsicWidth() / 2, shh = drawable.getIntrinsicHeight() / 2; + drawable.setBounds(scx - shw, scy - shh, scx + shw, scy + shh); + setDrawableBounds(drawable, sideStartX + AndroidUtilities.dp(4), sideStartY + AndroidUtilities.dp(4)); + canvas.save(); + canvas.scale(.65f, .65f, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + drawable.draw(canvas); + canvas.restore(); } else { final int scx = (int) (sideStartX + AndroidUtilities.dp(16)), scy = (int) (sideStartY + AndroidUtilities.dp(16)); Drawable drawable = getThemedDrawable(Theme.key_drawable_shareIcon); @@ -15783,7 +16252,8 @@ public float getTimeAlpha() { } 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)); } @@ -15791,10 +16261,10 @@ public int getBackgroundDrawableLeft() { } 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) { @@ -15880,7 +16350,7 @@ public int getBackgroundDrawableBottom() { } 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 { @@ -15955,7 +16425,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } lastNamesAnimationTime = newAnimationTime; - if (currentMessageObject.deleted && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1) { + if (currentMessageObject.deleted && !drawingToBitmap && currentMessagesGroup != null && currentMessagesGroup.messages.size() >= 1) { return; } @@ -15994,9 +16464,9 @@ public void drawNamesLayout(Canvas canvas, float alpha) { 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(); @@ -16044,12 +16514,11 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite instanceof TLRPC.TL_chatInvite) { colorId = currentMessageObject.sponsoredChatInvite.color; } else if (currentMessageObject.isSponsored() && currentMessageObject.sponsoredChatInvite != null && currentMessageObject.sponsoredChatInvite.chat != null) { - colorId = (currentMessageObject.sponsoredChatInvite.chat.flags2 & 64) != 0 ? currentMessageObject.sponsoredChatInvite.chat.color : (int) (currentMessageObject.sponsoredChatInvite.chat.id % 7); + colorId = ChatObject.getColorId(currentMessageObject.sponsoredChatInvite.chat); } else if (currentMessageObject.isFromUser() && currentUser != null) { - colorId = (currentUser.flags2 & 128) != 0 ? currentUser.color : (int) (currentUser.id % 7); - if (currentUser.self) colorId = PeerColorHelper.replaceColor(colorId); + colorId = UserObject.getColorId(currentUser); } else { - colorId = (currentChat.flags2 & 64) != 0 ? currentChat.color : (int) (currentChat.id % 7); + colorId = ChatObject.getColorId(currentChat); } if (colorId < 7) { Theme.chat_namePaint.setColor(getThemedColor(Theme.keys_avatar_nameInMessage[colorId])); @@ -16057,7 +16526,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_namePaint.setColor(peerColor.getColor1()); + Theme.chat_namePaint.setColor(peerColor.getColor(0, resourcesProvider)); } else { Theme.chat_namePaint.setColor(getThemedColor(Theme.key_chat_inForwardedNameText)); } @@ -16178,38 +16647,6 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } adminLayout.draw(canvas); canvas.restore(); - } else if (currentMessageObject.isSponsored()) { - if (closeSponsoredBounce == null) { - closeSponsoredBounce = new ButtonBounce(this); - } - if (closeSponsoredPaint == null) { - closeSponsoredPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - } - if (closeSponsoredPath == null) { - closeSponsoredPath = new Path(); - closeSponsoredPaint.setStrokeCap(Paint.Cap.ROUND); - closeSponsoredPaint.setStyle(Paint.Style.STROKE); - } else { - closeSponsoredPath.rewind(); - } - if (closeSponsoredBounds == null) { - closeSponsoredBounds = new RectF(); - } - closeSponsoredPath.moveTo(0, 0); - closeSponsoredPath.lineTo(dp(8), dp(8)); - closeSponsoredPath.moveTo(0, dp(8)); - closeSponsoredPath.lineTo(dp(8), 0); - closeSponsoredPaint.setStrokeWidth(AndroidUtilities.dpf2(1.33f)); - closeSponsoredPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), .28f)); - canvas.save(); - closeSponsoredBounds.set(0, 0, dp(8), dp(8)); - closeSponsoredBounds.inset(-dp(16), -dp(16)); - closeSponsoredBounds.offset(end - AndroidUtilities.dp(22), nameY + AndroidUtilities.dp(5)); - canvas.translate(end - AndroidUtilities.dp(22), nameY + AndroidUtilities.dp(5)); - final float s = closeSponsoredBounce.getScale(.09f); - canvas.scale(s, s, dp(4), dp(4)); - canvas.drawPath(closeSponsoredPath, closeSponsoredPaint); - canvas.restore(); } } @@ -16229,7 +16666,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } } - 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)) { @@ -16271,7 +16708,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { 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)); @@ -16313,12 +16750,12 @@ public void drawNamesLayout(Canvas canvas, float alpha) { if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + colorId = ChatObject.getColorId(chat); } } else { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + colorId = UserObject.getColorId(user); } } if (colorId < 7) { @@ -16327,7 +16764,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - Theme.chat_forwardNamePaint.setColor(peerColor.getColor1()); + Theme.chat_forwardNamePaint.setColor(peerColor.getColor(0, resourcesProvider)); } } } @@ -16467,6 +16904,9 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } 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); @@ -16519,7 +16959,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_outReplyMessageText); - if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { + if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_outReplyMediaMessageSelectedText : Theme.key_chat_outReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } @@ -16531,7 +16971,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else { float blendPressed = replyPressedT; int color = getThemedColor(Theme.key_chat_inReplyMessageText); - if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { + if (!currentMessageObject.forceAvatar && !(currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.contentType != 1 && currentMessageObject.replyMessageObject.type == MessageObject.TYPE_TEXT || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame || MessageObject.getMedia(currentMessageObject.replyMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice) || hasReplyQuote)) { color = getThemedColor(isDrawSelectionBackground() ? Theme.key_chat_inReplyMediaMessageSelectedText : Theme.key_chat_inReplyMediaMessageText); blendPressed = .6f + (blendPressed * .4f); } @@ -16723,7 +17163,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (1f - transitionParams.animateChangeProgress))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, transitionParams.animateReplyTextLayout, replySpoilers, canvas, false); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } @@ -16744,7 +17184,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) { int wasAlpha2 = paint.getAlpha(); paint.setAlpha((int) (wasAlpha2 * (transitionParams.animateReplyTextLayout != null ? transitionParams.animateChangeProgress : 1))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, replyTextLayout, replySpoilers, canvas, false); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.chat_outAnimatedEmojiTextColorFilter : Theme.chat_animatedEmojiTextColorFilter); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, getAdaptiveEmojiColorFilter(2, paint.getColor())); paint.setAlpha(wasAlpha2); canvas.restore(); } @@ -16802,6 +17242,9 @@ public float getHighlightAlpha(boolean quote) { } public void setCheckBoxVisible(boolean visible, boolean animated) { + if (animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { + return; + } if (visible) { quoteHighlight = null; if (checkBox == null) { @@ -16846,6 +17289,9 @@ public boolean isCheckBoxVisible() { } public void setChecked(boolean checked, boolean allChecked, boolean animated) { + if (!checked && animated && currentMessageObject != null && currentMessageObject.deletedByThanos) { + return; + } if (checkBox != null) { checkBox.setChecked(allChecked, animated); } @@ -16887,7 +17333,7 @@ public Theme.MessageDrawable getCurrentBackgroundDrawable(boolean update) { } 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) { @@ -16913,7 +17359,7 @@ public void drawCaptionLayout(Canvas canvas, boolean selectionOnly, float alpha) 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(); } @@ -17191,7 +17637,7 @@ private void drawCaptionLayout(Canvas canvas, MessageObject.TextLayoutBlocks cap } } - 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(); @@ -17407,7 +17853,7 @@ private boolean findProgressLoadingLink(LoadingDrawableLocation location, LinkPa } public boolean needDrawTime() { - return !forceNotDrawTime; + return !forceNotDrawTime && (currentMessageObject == null || currentMessageObject.type != MessageObject.TYPE_JOINED_CHANNEL); } public boolean shouldDrawTimeOnMedia() { @@ -17421,6 +17867,9 @@ public void drawTime(Canvas canvas, float alpha, boolean fromParent) { if (!drawFromPinchToZoom && delegate != null && delegate.getPinchToZoomHelper() != null && delegate.getPinchToZoomHelper().isInOverlayModeFor(this) && shouldDrawTimeOnMedia()) { return; } + if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL) { + return; + } for (int i = 0; i < 2; i++) { float currentAlpha = alpha; if (i == 0 && isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 1f && !shouldDrawTimeOnMedia()) { @@ -17527,7 +17976,7 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl timeX += animationOffsetX; timeTitleTimeX += animationOffsetX; } - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { if (transitionParams.animateBackgroundBoundsInner && transitionParams.deltaRight != 0) { timeTitleTimeX += reactionsLayoutInBubble.getCurrentWidth(1f); } else { @@ -17557,7 +18006,7 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl } alpha = AndroidUtilities.lerp(0.35f, 1f, progress); } - paint.setAlpha((int) (oldAlpha * timeAlpha * alpha)); + paint.setAlpha((int) (oldAlpha * timeAlpha * alpha * .6f)); int r; if (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { @@ -17609,7 +18058,7 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl alpha = oldAlpha3; float additionalX = -timeLayout.getLineLeft(0); - if (reactionsLayoutInBubble.isSmall) { + if (currentMessageObject.shouldDrawReactions() && reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); reactionsLayoutInBubble.draw(canvas, transitionParams.animateChangeProgress, null); } @@ -17680,7 +18129,7 @@ private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, fl 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); } @@ -18407,8 +18856,8 @@ public void drawOverlays(Canvas canvas) { 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) { @@ -18435,7 +18884,7 @@ public void drawOverlays(Canvas canvas) { 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(); } @@ -18747,7 +19196,7 @@ public void drawOverlays(Canvas canvas) { 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); @@ -18824,7 +19273,7 @@ public void drawOverlays(Canvas canvas) { 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); @@ -19115,14 +19564,16 @@ public void drawOverlays(Canvas canvas) { 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)); @@ -19166,7 +19617,7 @@ public void drawOverlays(Canvas canvas) { } } - if (drawImageButton && photoImage.getVisible() && !isSmallImage) { + if (drawImageButton && photoImage.getVisible() && !isSmallImage && !currentMessageObject.isRepostVideoPreview) { if (controlsAlpha != 1.0f) { radialProgress.setOverrideAlpha(controlsAlpha); } @@ -19196,7 +19647,7 @@ public void drawOverlays(Canvas canvas) { 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) { @@ -19221,6 +19672,7 @@ public void drawOverlays(Canvas canvas) { 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(); @@ -19252,7 +19704,7 @@ public void drawOverlays(Canvas canvas) { 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); } @@ -19309,17 +19761,19 @@ public void drawOverlays(Canvas canvas) { 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(); @@ -20490,7 +20944,7 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) { } } 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); } @@ -20823,6 +21277,10 @@ public class TransitionParams { public int lastReplyTextXOffset; public float animateReplyTextOffset; + public boolean lastDrawingRecommendationsExpanded; + public boolean animateRecommendationsExpanded; + public boolean animateFromRecommendationsExpanded; + public void recordDrawingState() { wasDraw = true; lastDrawingImageX = photoImage.getImageX(); @@ -20849,6 +21307,8 @@ public void recordDrawingState() { lastDrawingLinkPreviewHeight = linkPreviewHeight; lastDrawingLinkAbove = linkPreviewAbove; + lastDrawingRecommendationsExpanded = currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); + if (commentLayout != null) { lastCommentsCount = getRepliesCount(); lastTotalCommentWidth = totalCommentWidth; @@ -21023,6 +21483,14 @@ public boolean animateChange() { changed = true; } + animateRecommendationsExpanded = false; + final boolean channelsExpanded = currentMessageObject.type == MessageObject.TYPE_JOINED_CHANNEL && channelRecommendationsCell != null && channelRecommendationsCell.isExpanded(); + if (channelsExpanded != lastDrawingRecommendationsExpanded) { + animateRecommendationsExpanded = true; + animateFromRecommendationsExpanded = lastDrawingRecommendationsExpanded; + changed = true; + } + animateLinkAbove = false; if (linkPreviewAbove != lastDrawingLinkAbove) { animateLinkAbove = true; @@ -21290,6 +21758,7 @@ public void resetAnimation() { animateSign = false; animateSmallImage = false; animateLinkAbove = false; + animateRecommendationsExpanded = false; animateDrawingTimeAlpha = false; animateLocationIsExpired = false; animatePlayingRound = false; @@ -21382,4 +21851,40 @@ public int getNameStatusX() { public int getNameStatusY() { return (int) (nameY + (nameLayout == null ? 0 : nameLayout.getHeight()) / 2); } + + @Override + public void computeScroll() { + super.computeScroll(); + if (channelRecommendationsCell != null) { + channelRecommendationsCell.computeScroll(); + } + } + + private ColorFilter[] adaptiveEmojiColorFilter; + private int[] adaptiveEmojiColor; + private ColorFilter getAdaptiveEmojiColorFilter(int n, int color) { + if (adaptiveEmojiColorFilter == null) { + adaptiveEmojiColor = new int[3]; + adaptiveEmojiColorFilter = new ColorFilter[3]; + } + if (color != adaptiveEmojiColor[n] || adaptiveEmojiColorFilter[n] == null) { + adaptiveEmojiColorFilter[n] = new PorterDuffColorFilter(adaptiveEmojiColor[n] = color, PorterDuff.Mode.SRC_IN); + } + return adaptiveEmojiColorFilter[n]; + } + + private boolean isDark() { + if (resourcesProvider != null) { + return resourcesProvider.isDark(); + } + return Theme.isCurrentThemeDark(); + } + + 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 7f1ad0f1b0..e74e6d1273 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -15,10 +15,12 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Shader; @@ -33,7 +35,6 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.ReplacementSpan; import android.text.style.StyleSpan; @@ -633,6 +634,10 @@ private void checkOnline() { } } boolean isOnline = isOnline(); + if (NaConfig.INSTANCE.getShowRecentOnlineStatus().Bool() && !isOnline && user != null && !user.self && user.status != null) { + final int diff = user.status.expires - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + isOnline = diff > -60 * 60; + } onlineProgress = isOnline ? 1.0f : 0.0f; } @@ -1173,6 +1178,11 @@ public void buildLayout() { } 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.verifiedExtended(); } @@ -1476,7 +1486,13 @@ public void buildLayout() { } 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; @@ -1527,8 +1543,9 @@ public void buildLayout() { 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; @@ -2187,7 +2204,7 @@ public void buildLayout() { if (messageString instanceof Spannable) { Spannable messageStringSpannable = (Spannable) messageString; for (Object span : messageStringSpannable.getSpans(0, messageStringSpannable.length(), Object.class)) { - if (span instanceof ClickableSpan || span instanceof CodeHighlighting.Span || span instanceof CodeHighlighting.ColorSpan || span instanceof QuoteSpan || span instanceof QuoteSpan.QuoteStyleSpan || (span instanceof StyleSpan && ((StyleSpan) span).getStyle() == android.graphics.Typeface.BOLD)) { + if (span instanceof ClickableSpan || span instanceof CodeHighlighting.Span || span instanceof TypefaceSpan || span instanceof CodeHighlighting.ColorSpan || span instanceof QuoteSpan || span instanceof QuoteSpan.QuoteStyleSpan || (span instanceof StyleSpan && ((StyleSpan) span).getStyle() == android.graphics.Typeface.BOLD)) { messageStringSpannable.removeSpan(span); } } @@ -2745,17 +2762,29 @@ public boolean update(int mask, boolean animated) { 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) { @@ -2910,10 +2939,10 @@ public boolean update(int mask, boolean animated) { avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else { if (useFromUserAsAvatar && message != null) { - avatarDrawable.setInfo(message.getFromPeerObject()); + avatarDrawable.setInfo(currentAccount, message.getFromPeerObject()); avatarImage.setForUserOrChat(message.getFromPeerObject(), avatarDrawable); } else if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); @@ -2924,7 +2953,7 @@ public boolean update(int mask, boolean animated) { avatarImage.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL, false); } } else if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setForUserOrChat(chat, avatarDrawable); } } @@ -3411,7 +3440,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); canvas.translate(nameLeft + nameLayoutTranslateX, AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 10 : 13)); SpoilerEffect.layoutDrawMaybe(nameLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, nameLayout, animatedEmojiStackName, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, nameLayout, animatedEmojiStackName, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(0, nameLayout.getPaint().getColor())); canvas.restore(); if (nameLayoutEllipsizeByGradient && !nameLayoutFits) { canvas.save(); @@ -3456,7 +3485,7 @@ protected void onDraw(Canvas canvas) { canvas.translate(messageNameLeft, messageNameTop); try { SpoilerEffect.layoutDrawMaybe(messageNameLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageNameLayout, animatedEmojiStack2, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageNameLayout, animatedEmojiStack2, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(1, messageNameLayout.getPaint().getColor())); } catch (Exception e) { FileLog.e(e); } @@ -3490,7 +3519,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); SpoilerEffect.clipOutCanvas(canvas, spoilers); SpoilerEffect.layoutDrawMaybe(messageLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, spoilers, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, spoilers, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(2, messageLayout.getPaint().getColor())); canvas.restore(); for (int i = 0; i < spoilers.size(); i++) { @@ -3503,7 +3532,7 @@ protected void onDraw(Canvas canvas) { } } else { SpoilerEffect.layoutDrawMaybe(messageLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, messageLayout, animatedEmojiStack, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(2, messageLayout.getPaint().getColor())); } messageLayout.getPaint().setAlpha(oldAlpha); canvas.restore(); @@ -3598,7 +3627,7 @@ protected void onDraw(Canvas canvas) { canvas.save(); SpoilerEffect.clipOutCanvas(canvas, spoilers2); SpoilerEffect.layoutDrawMaybe(buttonLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, spoilers2, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, spoilers2, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(3, buttonLayout.getPaint().getColor())); canvas.restore(); for (int i = 0; i < spoilers2.size(); i++) { @@ -3611,7 +3640,7 @@ protected void onDraw(Canvas canvas) { } } else { SpoilerEffect.layoutDrawMaybe(buttonLayout, canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, null, 0, 0, 0, 1f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, null, 0, 0, 0, 1f, getAdaptiveEmojiColorFilter(3, buttonLayout.getPaint().getColor())); } canvas.restore(); } @@ -4079,7 +4108,26 @@ public boolean drawAvatarOverlays(Canvas canvas) { if (user != null && !MessagesController.isSupportUser(user) && !user.bot) { boolean isOnline = isOnline(); wasDrawnOnline = isOnline; + int colorOnline = 0; + if (NaConfig.INSTANCE.getShowRecentOnlineStatus().Bool() && !user.self && user.status != null) { + final int diff = user.status.expires - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + colorOnline = diff > 0 + ? Theme.getColor(Theme.key_chats_onlineCircle) + : diff > -15 * 60 + ? android.graphics.Color.argb(255, 234, 234, 30) + : diff > -30 * 60 + ? android.graphics.Color.argb(255, 234, 132, 30) + : diff > -60 * 60 + ? android.graphics.Color.argb(255, 234, 30, 30) + : 0; + if (colorOnline != 0) { + isOnline = true; + } + } if (isOnline || onlineProgress != 0) { + if (onlineProgress != 0 && colorOnline == 0) { + colorOnline = Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider); + } int top = (int) (storyParams.originalAvatarRect.bottom - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 6 : 8)); int left; if (LocaleController.isRTL) { @@ -4090,7 +4138,7 @@ public boolean drawAvatarOverlays(Canvas canvas) { Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); canvas.drawCircle(left, top, AndroidUtilities.dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); - Theme.dialogs_onlineCirclePaint.setColor(Theme.getColor(Theme.key_chats_onlineCircle, resourcesProvider)); + Theme.dialogs_onlineCirclePaint.setColor(colorOnline); canvas.drawCircle(left, top, AndroidUtilities.dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); if (isOnline) { if (onlineProgress < 1.0f) { @@ -5260,4 +5308,17 @@ private void formatTopicsNames(int currentAccount, MessageObject message, TLRPC. } } } + + private ColorFilter[] adaptiveEmojiColorFilter; + private int[] adaptiveEmojiColor; + private ColorFilter getAdaptiveEmojiColorFilter(int n, int color) { + if (adaptiveEmojiColorFilter == null) { + adaptiveEmojiColor = new int[4]; + adaptiveEmojiColorFilter = new ColorFilter[4]; + } + if (color != adaptiveEmojiColor[n] || adaptiveEmojiColorFilter[n] == null) { + adaptiveEmojiColorFilter[n] = new PorterDuffColorFilter(adaptiveEmojiColor[n] = color, PorterDuff.Mode.SRC_IN); + } + return adaptiveEmojiColorFilter[n]; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java index aa6d810888..6f06588655 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogMeUrlCell.java @@ -114,7 +114,7 @@ public void buildLayout() { nameLeft = AndroidUtilities.dp(14); } nameString = chat.title; - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setForUserOrChat(chat, avatarDrawable, recentMeUrl); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlUser) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(recentMeUrl.user_id); @@ -137,7 +137,7 @@ public void buildLayout() { drawVerified = user.verifiedExtended(); } nameString = UserObject.getUserName(user); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImage.setForUserOrChat(user, avatarDrawable, recentMeUrl); } else if (recentMeUrl instanceof TLRPC.TL_recentMeUrlStickerSet) { if (!LocaleController.isRTL) { @@ -155,7 +155,7 @@ public void buildLayout() { nameLeft = AndroidUtilities.dp(14); } if (recentMeUrl.chat_invite.chat != null) { - avatarDrawable.setInfo(recentMeUrl.chat_invite.chat); + avatarDrawable.setInfo(currentAccount, recentMeUrl.chat_invite.chat); nameString = recentMeUrl.chat_invite.chat.title; drawVerified = recentMeUrl.chat_invite.chat.verifiedExtended(); avatarImage.setForUserOrChat(recentMeUrl.chat_invite.chat, avatarDrawable, recentMeUrl); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java index a9c23b56dd..03d271f78e 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 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 DialogsHintCell(@NonNull Context context) { 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 DialogsHintCell(@NonNull Context context) { 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 void updateColors() { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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/DrawerUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java index 608f98cd7a..d7c0f7df52 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -139,7 +139,7 @@ public void setAccount(int account) { if (user == null) { return; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); CharSequence text = ContactsController.formatName(user.first_name, user.last_name); try { text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java index c62b1365b0..74ef91919c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallInvitedCell.java @@ -10,7 +10,6 @@ import android.widget.ImageView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java index c2f0386765..1bac1514f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCallUserCell.java @@ -29,12 +29,13 @@ 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; import org.telegram.messenger.MessageObject; import org.telegram.messenger.R; -import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.voip.VoIPService; @@ -469,15 +470,13 @@ public void setData(AccountInstance account, TLRPC.TL_groupCallParticipant group if (id > 0) { currentUser = accountInstance.getMessagesController().getUser(id); currentChat = null; - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), currentUser); nameTextView.setText(UserObject.getUserName(currentUser)); if (currentUser != null && currentUser.verifiedExtended()) { 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(); @@ -509,12 +508,14 @@ public void draw(@NonNull Canvas canvas) { } else { currentChat = accountInstance.getMessagesController().getChat(-id); currentUser = null; - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(accountInstance.getCurrentAccount(), currentChat); if (currentChat != null) { nameTextView.setText(currentChat.title); if (currentChat.verifiedExtended()) { 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/GroupCreateUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java index bf500bcc2c..937371d01a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/GroupCreateUserCell.java @@ -39,6 +39,8 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import xyz.nextalone.nagram.NaConfig; + public class GroupCreateUserCell extends FrameLayout { private BackupImageView avatarImageView; @@ -321,7 +323,7 @@ public void update(int mask) { return; } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); lastStatus = currentUser.status != null ? currentUser.status.expires : 0; if (currentName != null) { @@ -374,7 +376,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentName != null) { lastName = null; @@ -430,7 +432,12 @@ protected void onDraw(Canvas canvas) { paint.setColor(Theme.getColor(Theme.key_checkboxSquareBackground, resourcesProvider)); float cx = avatarImageView.getLeft() + avatarImageView.getMeasuredWidth() / 2; float cy = avatarImageView.getTop() + avatarImageView.getMeasuredHeight() / 2; - canvas.drawCircle(cx, cy, AndroidUtilities.dp(18) + AndroidUtilities.dp(4) * checkProgress, paint); + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + float dp = AndroidUtilities.dp(18) + AndroidUtilities.dp(4) * checkProgress; + canvas.drawRect(cx - dp, cy - dp, cx + dp, cy + dp, paint); + } else { + canvas.drawCircle(cx, cy, AndroidUtilities.dp(18) + AndroidUtilities.dp(4) * checkProgress, paint); + } } if (drawDivider) { int start = AndroidUtilities.dp(LocaleController.isRTL ? 0 : 72 + padding); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java index 1a254677e8..280caf3af7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/HintDialogCell.java @@ -40,6 +40,7 @@ public class HintDialogCell extends FrameLayout { private TextView nameTextView; private AvatarDrawable avatarDrawable = new AvatarDrawable(); private RectF rect = new RectF(); + private Theme.ResourcesProvider resourcesProvider; private int lastUnreadCount; private TLRPC.User currentUser; @@ -53,7 +54,7 @@ public class HintDialogCell extends FrameLayout { CheckBox2 checkBox; private final boolean drawCheckbox; - public HintDialogCell(Context context, boolean drawCheckbox) { + public HintDialogCell(Context context, boolean drawCheckbox, Theme.ResourcesProvider resourcesProvider) { super(context); this.drawCheckbox = drawCheckbox; @@ -69,7 +70,7 @@ public void setText(CharSequence text, BufferType type) { } }; NotificationCenter.listenEmojiLoading(nameTextView); - nameTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + nameTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); nameTextView.setMaxLines(1); nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); @@ -77,13 +78,13 @@ public void setText(CharSequence text, BufferType type) { nameTextView.setEllipsize(TextUtils.TruncateAt.END); addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 64, 6, 0)); - counterView = new CounterView(context, null); + counterView = new CounterView(context, resourcesProvider); addView(counterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, Gravity.TOP,0 ,4,0,0)); counterView.setColors(Theme.key_chats_unreadCounterText, Theme.key_chats_unreadCounter); counterView.setGravity(Gravity.RIGHT); if (drawCheckbox) { - checkBox = new CheckBox2(context, 21); + checkBox = new CheckBox2(context, 21, resourcesProvider); checkBox.setColor(Theme.key_dialogRoundCheckBox, Theme.key_dialogBackground, Theme.key_dialogRoundCheckBoxCheck); checkBox.setDrawUnchecked(false); checkBox.setDrawBackgroundAsArc(4); @@ -131,16 +132,16 @@ public void update(int mask) { public void update() { if (DialogObject.isUserDialog(dialogId)) { currentUser = MessagesController.getInstance(currentAccount).getUser(dialogId); - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); currentUser = null; } } public void setColors(int textColorKey, int backgroundColorKey) { - nameTextView.setTextColor(Theme.getColor(textColorKey)); + nameTextView.setTextColor(Theme.getColor(textColorKey, resourcesProvider)); this.backgroundColorKey = backgroundColorKey; checkBox.setColor(Theme.key_dialogRoundCheckBox, backgroundColorKey, Theme.key_dialogRoundCheckBoxCheck); } @@ -160,7 +161,7 @@ public void setDialog(long uid, boolean counter, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); imageView.setForUserOrChat(currentUser, avatarDrawable); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); @@ -171,7 +172,7 @@ public void setDialog(long uid, boolean counter, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); currentUser = null; imageView.setForUserOrChat(chat, avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java index 5ae3384b55..671ac9bbe1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/JoinSheetUserCell.java @@ -17,7 +17,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ContactsController; -import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java index 5466fc7796..9a4cbcdbd3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ManageChatUserCell.java @@ -21,49 +21,45 @@ 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; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Stories.StoriesUtilities; public class ManageChatUserCell extends FrameLayout { - private BackupImageView avatarImageView; - private SimpleTextView nameTextView; - private SimpleTextView statusTextView; + private final BackupImageView avatarImageView; + private final SimpleTextView nameTextView; + private final SimpleTextView statusTextView; + private final Theme.ResourcesProvider resourcesProvider; + private final AvatarDrawable avatarDrawable; private ImageView optionsButton; private ImageView customImageView; - private Theme.ResourcesProvider resourcesProvider; - - private AvatarDrawable avatarDrawable; private Object currentObject; - + private TL_stories.StoryItem storyItem; private CharSequence currentName; - private CharSequence currrntStatus; - + private CharSequence currentStatus; private String lastName; private int lastStatus; private TLRPC.FileLocation lastAvatar; private boolean isAdmin; - private boolean needDivider; - private int statusColor; private int statusOnlineColor; - - private int namePadding; - - private int currentAccount = UserConfig.selectedAccount; - + private final int namePadding; private int dividerColor = -1; - private ManageChatUserCellDelegate delegate; + private final int currentAccount = UserConfig.selectedAccount; + private final StoriesUtilities.AvatarStoryParams storyAvatarParams = new StoriesUtilities.AvatarStoryParams(false); public interface ManageChatUserCellDelegate { boolean onOptionsButtonCheck(ManageChatUserCell cell, boolean click); @@ -84,7 +80,24 @@ public ManageChatUserCell(Context context, int avatarPadding, int nPadding, bool avatarDrawable = new AvatarDrawable(); - avatarImageView = new BackupImageView(context); + avatarImageView = new BackupImageView(context) { + @Override + protected void onDraw(Canvas canvas) { + if (storyItem != null) { + int pad = AndroidUtilities.dp(1); + storyAvatarParams.originalAvatarRect.set(pad, pad, getMeasuredWidth() - pad, getMeasuredHeight() - pad); + storyAvatarParams.drawSegments = false; + storyAvatarParams.animate = false; + storyAvatarParams.drawInside = true; + storyAvatarParams.isArchive = false; + storyAvatarParams.resourcesProvider = resourcesProvider; + storyAvatarParams.storyItem = storyItem; + StoriesUtilities.drawAvatarWithStory(storyItem.dialogId, canvas, imageReceiver, storyAvatarParams); + } else { + super.onDraw(canvas); + } + } + }; avatarImageView.setRoundRadius(AndroidUtilities.dp(23)); addView(avatarImageView, LayoutHelper.createFrame(46, 46, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 7 + avatarPadding, 8, LocaleController.isRTL ? 7 + avatarPadding : 0, 0)); @@ -94,6 +107,7 @@ public ManageChatUserCell(Context context, int avatarPadding, int nPadding, bool 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); @@ -113,6 +127,23 @@ public ManageChatUserCell(Context context, int avatarPadding, int nPadding, bool } } + public void setStoryItem(TL_stories.StoryItem storyItem, OnClickListener listener) { + this.storyItem = storyItem; + avatarImageView.setOnClickListener(listener); + } + + public TL_stories.StoryItem getStoryItem() { + return storyItem; + } + + public BackupImageView getAvatarImageView() { + return avatarImageView; + } + + public StoriesUtilities.AvatarStoryParams getStoryAvatarParams() { + return storyAvatarParams; + } + public void setCustomRightImage(int resId) { customImageView = new ImageView(getContext()); customImageView.setImageResource(resId); @@ -130,7 +161,7 @@ public void setCustomImageVisible(boolean visible) { public void setData(Object object, CharSequence name, CharSequence status, boolean divider) { if (object == null) { - currrntStatus = null; + currentStatus = null; currentName = null; currentObject = null; nameTextView.setText(""); @@ -138,7 +169,7 @@ public void setData(Object object, CharSequence name, CharSequence status, boole avatarImageView.setImageDrawable(null); return; } - currrntStatus = status; + currentStatus = status; currentName = name; currentObject = object; if (optionsButton != null) { @@ -229,7 +260,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { @@ -243,9 +274,9 @@ public void update(int mask) { lastName = newName == null ? UserObject.getUserName(currentUser) : newName; nameTextView.setText(Emoji.replaceEmoji(lastName, nameTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(15), false)); } - if (currrntStatus != null) { + if (currentStatus != null) { statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); } else { if (currentUser.bot) { statusTextView.setTextColor(statusColor); @@ -293,7 +324,7 @@ public void update(int mask) { } } - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentName != null) { lastName = null; @@ -302,9 +333,9 @@ public void update(int mask) { lastName = newName == null ? currentChat.title : newName; nameTextView.setText(lastName); } - if (currrntStatus != null) { + if (currentStatus != null) { statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); } else { statusTextView.setTextColor(statusColor); if (currentChat.participants_count != 0) { @@ -326,7 +357,7 @@ public void update(int mask) { } else if (currentObject instanceof Integer) { nameTextView.setText(currentName); statusTextView.setTextColor(statusColor); - statusTextView.setText(currrntStatus); + statusTextView.setText(currentStatus); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SHARES); avatarImageView.setImage(null, "50_50", avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index f13b6490b1..531142d03c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -34,11 +34,11 @@ public class MentionCell extends LinearLayout { - private BackupImageView imageView; - private TextView nameTextView; - private TextView usernameTextView; - private AvatarDrawable avatarDrawable; - private Theme.ResourcesProvider resourcesProvider; + private final BackupImageView imageView; + private final TextView nameTextView; + private final TextView usernameTextView; + private final AvatarDrawable avatarDrawable; + private final Theme.ResourcesProvider resourcesProvider; private Drawable emojiDrawable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java index 4030f5c3a0..01797c4ddb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/NotificationsCheckCell.java @@ -22,6 +22,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; @@ -88,12 +89,25 @@ public NotificationsCheckCell(Context context, int padding, int height, boolean valueTextView.setEllipsize(TextUtils.TruncateAt.END); addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 80 : (withImage ? 64 : padding), 38 - (withImage ? 2 : 0) + (currentHeight - 70) / 2, LocaleController.isRTL ? (withImage ? 64 : padding) : 80, 0)); - checkBox = new Switch(context, resourcesProvider); + checkBox = new Switch(context, resourcesProvider) { + @Override + protected int processColor(int color) { + return NotificationsCheckCell.this.processColor(color); + } + }; checkBox.setColors(Theme.key_switchTrack, Theme.key_switchTrackChecked, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhite); addView(checkBox, LayoutHelper.createFrame(37, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0)); checkBox.setFocusable(false); } + public Switch getCheckBox() { + return checkBox; + } + + protected int processColor(int color) { + return color; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isMultiline) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java index 770df1bbbf..cbe02a5f18 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -10,6 +10,7 @@ import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.text.Layout; @@ -37,7 +38,6 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; @@ -46,9 +46,7 @@ import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.LaunchActivity; import org.telegram.ui.NotificationsSettingsActivity; -import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoriesUtilities; import java.util.Locale; @@ -136,6 +134,13 @@ public ProfileSearchCell(Context context, Theme.ResourcesProvider resourcesProvi statusDrawable.setCallback(this); } + private boolean customPaints; + private TextPaint namePaint, statusPaint; + public ProfileSearchCell useCustomPaints() { + customPaints = true; + return this; + } + @Override protected boolean verifyDrawable(@NonNull Drawable who) { return statusDrawable == who || super.verifyDrawable(who); @@ -305,7 +310,7 @@ public void buildLayout() { 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.verifiedExtended(); @@ -314,7 +319,7 @@ public void buildLayout() { } 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) { @@ -325,7 +330,7 @@ public void buildLayout() { nameLockTop = AndroidUtilities.dp(21); drawCheck = user.verifiedExtended(); 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) { @@ -369,7 +374,19 @@ public void buildLayout() { nameString = LocaleController.getString("HiddenName", R.string.HiddenName); } } - if (encryptedChat != null) { + if (customPaints) { + if (namePaint == null) { + namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + namePaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + namePaint.setTextSize(AndroidUtilities.dp(16)); + if (encryptedChat != null) { + namePaint.setColor(Theme.getColor(Theme.key_chats_secretName, resourcesProvider)); + } else { + namePaint.setColor(Theme.getColor(Theme.key_chats_name, resourcesProvider)); + } + currentNamePaint = namePaint; + } else if (encryptedChat != null) { currentNamePaint = Theme.dialogs_searchNameEncryptedPaint; } else { currentNamePaint = Theme.dialogs_searchNamePaint; @@ -494,6 +511,18 @@ public void buildLayout() { } nameTop = AndroidUtilities.dp(19); } + if (customPaints) { + if (statusPaint == null) { + statusPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + } + statusPaint.setTextSize(AndroidUtilities.dp(15)); + if (currentStatusPaint == Theme.dialogs_offlinePaint) { + statusPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3, resourcesProvider)); + } else if (currentStatusPaint == Theme.dialogs_onlinePaint) { + statusPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText3, resourcesProvider)); + } + currentStatusPaint = statusPaint; + } if (!TextUtils.isEmpty(statusString)) { CharSequence statusStringFinal = TextUtils.ellipsize(statusString, currentStatusPaint, statusWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); @@ -560,16 +589,16 @@ public void buildLayout() { 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); @@ -583,7 +612,7 @@ public void updateStatus(boolean verified, TLRPC.User user, boolean animated) { public void update(int mask) { TLRPC.FileLocation photo = null; if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarImage.setImage(null, null, avatarDrawable, null, null, 0); @@ -608,7 +637,7 @@ public void update(int mask) { thumb = chat.photo.strippedBitmap; } } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImage.setImage(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_STRIPPED), "50_50", thumb, chat, 0); } else if (contact != null) { avatarDrawable.setInfo(0, contact.first_name, contact.last_name); @@ -635,8 +664,8 @@ public void update(int mask) { 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; @@ -691,10 +720,17 @@ protected void onDraw(Canvas canvas) { } if (useSeparator) { + Paint dividerPaint = null; + if (customPaints && resourcesProvider != null) { + dividerPaint = resourcesProvider.getPaint(Theme.key_paint_divider); + } + if (dividerPaint == null) { + dividerPaint = Theme.dividerPaint; + } if (LocaleController.isRTL) { - canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, Theme.dividerPaint); + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, dividerPaint); } else { - canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint); + canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, dividerPaint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java index ae37d0cc64..f8cfed7e35 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.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 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,15 +37,16 @@ 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.Premium.PremiumGradient; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.messenger.LocaleController; import org.telegram.ui.Components.StatusBadgeComponent; @@ -58,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; @@ -74,6 +81,8 @@ public void openStory(long dialogId, Runnable onDone) { 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); @@ -149,6 +158,9 @@ public boolean setText(CharSequence value) { 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)); @@ -156,7 +168,7 @@ public boolean setText(CharSequence value) { } } - 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; @@ -168,7 +180,7 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea int colorFilter = Theme.getColor(style == STYLE_STORY ? Theme.key_windowBackgroundWhiteBlackText : Theme.key_chats_verifiedBackground, resourcesProvider); statusBadgeComponent.updateDrawable(user, chat, colorFilter, false); - avatarDrawable.setInfo(u); + avatarDrawable.setInfo(currentAccount, u); if (user != null) { dialogId = user.id; titleView.setText(UserObject.getUserName(user)); @@ -224,6 +236,24 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea 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); } @@ -231,8 +261,41 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea 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) { @@ -264,7 +327,7 @@ public void setUserReaction(TLRPC.MessagePeerReaction reaction) { } 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/SessionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java index 5b7a24cf4c..497ce21c35 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SessionCell.java @@ -247,7 +247,7 @@ public void setSession(TLObject object, boolean divider) { nameTextView.setText(session.domain); String name; if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); name = UserObject.getFirstName(user); imageView.setForUserOrChat(user, avatarDrawable); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java index 6c5d83b3dc..2960c96b10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -8,8 +8,19 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.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; import android.text.Layout; import android.text.TextUtils; @@ -20,6 +31,8 @@ import android.widget.FrameLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.dynamicanimation.animation.FloatValueHolder; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; @@ -43,16 +56,26 @@ import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; + +import xyz.nextalone.nagram.NaConfig; public class ShareDialogCell extends FrameLayout { - private BackupImageView imageView; - private TextView nameTextView; - private SimpleTextView topicTextView; - private CheckBox2 checkBox; - private AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final BackupImageView imageView; + private final TextView nameTextView; + private final SimpleTextView topicTextView; + private final CheckBox2 checkBox; + private final AvatarDrawable avatarDrawable = new AvatarDrawable() { + @Override + public void invalidateSelf() { + super.invalidateSelf(); + imageView.invalidate(); + } + }; + private RepostStoryDrawable repostStoryDrawable; private TLRPC.User user; - private int currentType; + private final int currentType; private float onlineProgress; private long lastUpdateTime; @@ -60,13 +83,17 @@ public class ShareDialogCell extends FrameLayout { private boolean topicWasVisible; - private int currentAccount = UserConfig.selectedAccount; - private final Theme.ResourcesProvider resourcesProvider; + private final int currentAccount = UserConfig.selectedAccount; + 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; @@ -75,7 +102,7 @@ public ShareDialogCell(Context context, int type, Theme.ResourcesProvider resour currentType = type; imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(28)); + imageView.setRoundRadius(dp(28)); if (type == TYPE_CREATE) { addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); } else { @@ -85,7 +112,7 @@ public ShareDialogCell(Context context, int type, Theme.ResourcesProvider resour nameTextView = new TextView(context) { @Override public void setText(CharSequence text, BufferType type) { - text = Emoji.replaceEmoji(text, getPaint().getFontMetricsInt(), AndroidUtilities.dp(10), false); + text = Emoji.replaceEmoji(text, getPaint().getFontMetricsInt(), dp(10), false); super.setText(text, type); } }; @@ -118,18 +145,28 @@ public void setText(CharSequence text, BufferType type) { }); addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 19, currentType == TYPE_CREATE ? -40 : 42, 0, 0)); - setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); + setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), dp(2), dp(2))); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(currentType == TYPE_CREATE ? 95 : 103), MeasureSpec.EXACTLY)); + } + + protected String repostToCustomName() { + return LocaleController.getString(R.string.FwdMyStory); } public void setDialog(long uid, boolean checked, CharSequence name) { - if (DialogObject.isUserDialog(uid)) { + if (uid == Long.MAX_VALUE) { + nameTextView.setText(repostToCustomName()); + if (repostStoryDrawable == null) { + repostStoryDrawable = new RepostStoryDrawable(getContext(), imageView, true, resourcesProvider); + } + imageView.setImage(null, null, repostStoryDrawable, null); + } else if (DialogObject.isUserDialog(uid)) { user = MessagesController.getInstance(currentAccount).getUser(uid); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (currentType != TYPE_CREATE && UserObject.isReplyUser(user)) { nameTextView.setText(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); @@ -148,7 +185,7 @@ public void setDialog(long uid, boolean checked, CharSequence name) { } imageView.setForUserOrChat(user, avatarDrawable); } - imageView.setRoundRadius(AndroidUtilities.dp(28)); + imageView.setRoundRadius(dp(28)); } else { user = null; TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-uid); @@ -159,9 +196,9 @@ public void setDialog(long uid, boolean checked, CharSequence name) { } else { nameTextView.setText(""); } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageView.setForUserOrChat(chat, avatarDrawable); - imageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(28)); + imageView.setRoundRadius(chat != null && chat.forum ? dp(16) : dp(28)); } currentDialog = uid; checkBox.setChecked(checked, false); @@ -202,8 +239,8 @@ public void setTopic(TLRPC.TL_forumTopic topic, boolean animate) { topicTextView.setAlpha(value); nameTextView.setAlpha(1f - value); - topicTextView.setTranslationX((1f - value) * -AndroidUtilities.dp(10)); - nameTextView.setTranslationX(value * AndroidUtilities.dp(10)); + topicTextView.setTranslationX((1f - value) * -dp(10)); + nameTextView.setTranslationX(value * dp(10)); }) .addEndListener((animation, canceled, value, velocity) -> { topicTextView.setTag(R.id.spring_tag, null); @@ -215,11 +252,11 @@ public void setTopic(TLRPC.TL_forumTopic topic, boolean animate) { topicTextView.setAlpha(1f); nameTextView.setAlpha(0f); topicTextView.setTranslationX(0); - nameTextView.setTranslationX(AndroidUtilities.dp(10)); + nameTextView.setTranslationX(dp(10)); } else { topicTextView.setAlpha(0f); nameTextView.setAlpha(1f); - topicTextView.setTranslationX(-AndroidUtilities.dp(10)); + topicTextView.setTranslationX(-dp(10)); nameTextView.setTranslationX(0); } } @@ -242,12 +279,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean isOnline = !user.self && !user.bot && (user.status != null && user.status.expires > ConnectionsManager.getInstance(currentAccount).getCurrentTime() || MessagesController.getInstance(currentAccount).onlinePrivacy.containsKey(user.id)); if (isOnline || onlineProgress != 0) { - int top = imageView.getBottom() - AndroidUtilities.dp(6); - int left = imageView.getRight() - AndroidUtilities.dp(10); + int top = imageView.getBottom() - dp(6); + int left = imageView.getRight() - dp(10); Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(currentType == TYPE_CALL ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_windowBackgroundWhite)); - canvas.drawCircle(left, top, AndroidUtilities.dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(7) * onlineProgress, Theme.dialogs_onlineCirclePaint); Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(Theme.key_chats_onlineCircle)); - canvas.drawCircle(left, top, AndroidUtilities.dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); + canvas.drawCircle(left, top, dp(5) * onlineProgress, Theme.dialogs_onlineCirclePaint); if (isOnline) { if (onlineProgress < 1.0f) { onlineProgress += dt / 150.0f; @@ -279,9 +316,13 @@ protected void onDraw(Canvas canvas) { int cy = imageView.getTop() + imageView.getMeasuredHeight() / 2; Theme.checkboxSquare_checkPaint.setColor(getThemedColor(Theme.key_dialogRoundCheckBox)); Theme.checkboxSquare_checkPaint.setAlpha((int) (checkBox.getProgress() * 255)); - int radius = AndroidUtilities.dp(currentType == TYPE_CREATE ? 24 : 28); + int radius = dp(currentType == TYPE_CREATE ? 24 : 28); AndroidUtilities.rectTmp.set(cx - radius, cy - radius, cx + radius, cy + radius); - canvas.drawRoundRect(AndroidUtilities.rectTmp, imageView.getRoundRadius()[0], imageView.getRoundRadius()[0], Theme.checkboxSquare_checkPaint); + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + canvas.drawRoundRect(AndroidUtilities.rectTmp, 0, 0, Theme.checkboxSquare_checkPaint); + } else { + canvas.drawRoundRect(AndroidUtilities.rectTmp, imageView.getRoundRadius()[0], imageView.getRoundRadius()[0], Theme.checkboxSquare_checkPaint); + } super.onDraw(canvas); } @@ -296,4 +337,83 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { info.setSelected(true); } } + + 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(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); + + 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); + 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(); + + 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 + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getIntrinsicWidth() { + return dp(56); + } + + @Override + public int getIntrinsicHeight() { + return dp(56); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index 4e9c2476de..cba6cc4a72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -47,10 +47,8 @@ import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LoadingSpan; -import org.telegram.ui.Components.Paint.Views.LocationView; import org.telegram.ui.LocationActivity; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -304,14 +302,14 @@ public void setDialog(LocationActivity.LiveLocation info, Location userLocation) if (DialogObject.isUserDialog(info.id)) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(info.id); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarImageView.setForUserOrChat(user, avatarDrawable); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-info.id); if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); nameTextView.setText(chat.title); avatarImageView.setForUserOrChat(chat, avatarDrawable); } @@ -336,14 +334,14 @@ public void setDialog(LocationController.SharingLocationInfo info) { if (DialogObject.isUserDialog(info.did)) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(info.did); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); avatarImageView.setForUserOrChat(user, avatarDrawable); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-info.did); if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); nameTextView.setText(chat.title); avatarImageView.setForUserOrChat(chat, avatarDrawable); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java index 6360a6e0d4..f625af0896 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StatisticPostInfoCell.java @@ -1,10 +1,16 @@ package org.telegram.ui.Cells; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.URLSpan; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -12,81 +18,105 @@ import android.widget.LinearLayout; import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.StatisticActivity; +import org.telegram.ui.Stories.StoriesUtilities; -public class StatisticPostInfoCell extends FrameLayout { +import java.util.Date; - private TextView message; - private TextView views; - private TextView shares; - private TextView date; - private BackupImageView imageView; - private AvatarDrawable avatarDrawable = new AvatarDrawable(); +@SuppressLint("ViewConstructor") +public class StatisticPostInfoCell extends FrameLayout { + private final BackupImageView imageView; + private final SimpleTextView message; + private final TextView views; + private final TextView shares; + private final TextView date; + private final TextView likes; + private final Paint dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final AvatarDrawable avatarDrawable = new AvatarDrawable(); + private final StoriesUtilities.AvatarStoryParams storyAvatarParams = new StoriesUtilities.AvatarStoryParams(false); + private final Theme.ResourcesProvider resourcesProvider; + private StatisticActivity.RecentPostInfo postInfo; private final TLRPC.ChatFull chat; + private boolean needDivider; - public StatisticPostInfoCell(Context context, TLRPC.ChatFull chat) { + public StatisticPostInfoCell(Context context, TLRPC.ChatFull chat, Theme.ResourcesProvider resourcesProvider) { super(context); this.chat = chat; - imageView = new BackupImageView(context); - addView(imageView, LayoutHelper.createFrame(46, 46, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 16, 0)); + this.resourcesProvider = resourcesProvider; + imageView = new BackupImageView(context) { + @Override + protected void onDraw(Canvas canvas) { + if (postInfo != null && postInfo.isStory()) { + int pad = AndroidUtilities.dp(1); + storyAvatarParams.originalAvatarRect.set(pad, pad, getMeasuredWidth() - pad, getMeasuredHeight() - pad); + storyAvatarParams.drawSegments = false; + storyAvatarParams.animate = false; + storyAvatarParams.drawInside = true; + storyAvatarParams.isArchive = false; + storyAvatarParams.forceState = StoriesUtilities.STATE_HAS_UNREAD; + storyAvatarParams.resourcesProvider = resourcesProvider; + StoriesUtilities.drawAvatarWithStory(0, canvas, imageReceiver, storyAvatarParams); + } else { + super.onDraw(canvas); + } + } + }; + setClipChildren(false); + addView(imageView, LayoutHelper.createFrame(46, 46, (!LocaleController.isRTL ? Gravity.START : Gravity.END) | Gravity.CENTER_VERTICAL, !LocaleController.isRTL ? 12 : 16, 0, !LocaleController.isRTL ? 16 : 12, 0)); LinearLayout contentLayout = new LinearLayout(context); contentLayout.setOrientation(LinearLayout.VERTICAL); LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); - message = new TextView(context) { - AnimatedEmojiSpan.EmojiGroupedSpans stack; - @Override - public void setText(CharSequence text, BufferType type) { - super.setText(text, type); - stack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, stack, getLayout()); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - stack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, stack, getLayout()); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - AnimatedEmojiSpan.release(this, stack); - } - + message = new SimpleTextView(context) { @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, getLayout(), stack, 0, null, 0, 0, 0, 1f); + public boolean setText(CharSequence value) { + value = Emoji.replaceEmoji(value, getPaint().getFontMetricsInt(), false); + return super.setText(value); } }; - message.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - message.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + NotificationCenter.listenEmojiLoading(message); + message.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + message.setTextSize(16); + message.setMaxLines(1); message.setTextColor(Color.BLACK); - message.setLines(1); - message.setEllipsize(TextUtils.TruncateAt.END); - + message.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); views = new TextView(context); - views.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + views.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); views.setTextColor(Color.BLACK); + if (!LocaleController.isRTL) { + linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 16, 0)); + linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + } else { + linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 16, 0, 0, 0)); + } - linearLayout.addView(message, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 16, 0)); - linearLayout.addView(views, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); - contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 8, 0, 0)); + contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 7, 0, 0)); date = new TextView(context); date.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); @@ -97,47 +127,139 @@ protected void onDraw(Canvas canvas) { shares = new TextView(context); shares.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); shares.setTextColor(Color.BLACK); + shares.setGravity(Gravity.CENTER_VERTICAL); + + likes = new TextView(context); + likes.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + likes.setTextColor(Color.BLACK); + likes.setGravity(Gravity.CENTER_VERTICAL); linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); - linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 8, 0)); - linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); - contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 2, 0, 8)); + if (!LocaleController.isRTL) { + linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 0, 0, 8, 0)); + linearLayout.addView(likes, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 10, 0, 0, 0)); + } else { + linearLayout.addView(shares, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); + linearLayout.addView(likes, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout.addView(date, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, Gravity.NO_GRAVITY, 8, 0, 0, 0)); + } + + contentLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, 0, 3, 0, 9)); - addView(contentLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.NO_GRAVITY, 72, 0, 12, 0)); + addView(contentLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.NO_GRAVITY, !LocaleController.isRTL ? 72 : 18, 0, !LocaleController.isRTL ? 18 : 72, 0)); message.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); views.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); date.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); shares.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + likes.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + Drawable likesDrawable = ContextCompat.getDrawable(context, R.drawable.mini_stats_likes).mutate(); + DrawableCompat.setTint(likesDrawable, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + Drawable sharesDrawable = ContextCompat.getDrawable(context, R.drawable.mini_stats_shares).mutate(); + DrawableCompat.setTint(sharesDrawable, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + + CombinedDrawable likesCombinedDrawable = new CombinedDrawable(null, likesDrawable, 0, dp(1)); + likesCombinedDrawable.setCustomSize(sharesDrawable.getIntrinsicWidth(), sharesDrawable.getIntrinsicHeight()); + likes.setCompoundDrawablesWithIntrinsicBounds(likesCombinedDrawable, null, null, null); + likes.setCompoundDrawablePadding(dp(2)); + + CombinedDrawable sharesCombinedDrawable = new CombinedDrawable(null, sharesDrawable, 0, dp(1)); + sharesCombinedDrawable.setCustomSize(sharesDrawable.getIntrinsicWidth(), sharesDrawable.getIntrinsicHeight()); + shares.setCompoundDrawablesWithIntrinsicBounds(sharesCombinedDrawable, null, null, null); + shares.setCompoundDrawablePadding(dp(2)); + setWillNotDraw(false); + } + + public BackupImageView getImageView() { + return imageView; + } + + public StoriesUtilities.AvatarStoryParams getStoryAvatarParams() { + return storyAvatarParams; + } + + public StatisticActivity.RecentPostInfo getPostInfo() { + return postInfo; } - public void setData(StatisticActivity.RecentPostInfo postInfo) { + public void setImageViewAction(View.OnClickListener action){ + imageView.setOnClickListener(action); + } + + public void setData(StatisticActivity.RecentPostInfo postInfo, boolean isLast) { + this.postInfo = postInfo; + this.needDivider = !isLast; MessageObject messageObject = postInfo.message; if (messageObject.photoThumbs != null) { TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs,50); + TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); imageView.setImage( ImageLocation.getForObject(size, messageObject.photoThumbsObject), "50_50", ImageLocation.getForObject(thumbSize, messageObject.photoThumbsObject), "b1", 0, messageObject); - imageView.setRoundRadius(AndroidUtilities.dp(4)); + imageView.setRoundRadius(AndroidUtilities.dp(9)); + imageView.setScaleX(0.96f); + imageView.setScaleY(0.96f); } else if (chat.chat_photo.sizes.size() > 0) { imageView.setImage(ImageLocation.getForPhoto(chat.chat_photo.sizes.get(0), chat.chat_photo), "50_50", null, null, chat); imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); + imageView.setScaleX(0.96f); + imageView.setScaleY(0.96f); + } else { + TLRPC.Chat currentChat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(chat.id); + avatarDrawable.setInfo(currentChat); + imageView.setForUserOrChat(currentChat, avatarDrawable); + imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); + imageView.setScaleX(1f); + imageView.setScaleY(1f); + } + if (messageObject.isStory()) { + imageView.setScaleX(1f); + imageView.setScaleY(1f); + imageView.setRoundRadius(AndroidUtilities.dp(46) >> 1); } - CharSequence text; if (messageObject.isMusic()) { text = String.format("%s, %s", messageObject.getMusicTitle().trim(), messageObject.getMusicAuthor().trim()); + } else if (messageObject.isStory()) { + text = LocaleController.getString("Story", R.string.Story); } else { text = messageObject.caption != null ? messageObject.caption : messageObject.messageText; } + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text == null ? "" : text); + URLSpan[] urlSpans = stringBuilder.getSpans(0, stringBuilder.length(), URLSpan.class); + for (URLSpan urlSpan : urlSpans) { + stringBuilder.removeSpan(urlSpan); + } + message.setText(AndroidUtilities.trim(AndroidUtilities.replaceNewLines(stringBuilder), null)); + views.setText(String.format(LocaleController.getPluralString("Views", postInfo.getViews()), AndroidUtilities.formatWholeNumber(postInfo.getViews(), 0))); + + Date time = new Date(postInfo.getDate() * 1000L); + String monthTxt = LocaleController.getInstance().formatterYear.format(time); + String timeTxt = LocaleController.getInstance().formatterDay.format(time); + date.setText(LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, monthTxt, timeTxt)); - message.setText(AndroidUtilities.trim(AndroidUtilities.replaceNewLines(new SpannableStringBuilder(text)), null)); - views.setText(String.format(LocaleController.getPluralString("Views", postInfo.counters.views), AndroidUtilities.formatCount(postInfo.counters.views))); - date.setText(LocaleController.formatDateAudio(postInfo.message.messageOwner.date, false)); - shares.setText(String.format(LocaleController.getPluralString("Shares", postInfo.counters.forwards), AndroidUtilities.formatCount(postInfo.counters.forwards))); + shares.setText(AndroidUtilities.formatWholeNumber(postInfo.getForwards(), 0)); + likes.setText(AndroidUtilities.formatWholeNumber(postInfo.getReactions(), 0)); + shares.setVisibility(postInfo.getForwards() != 0 ? VISIBLE : GONE); + likes.setVisibility(postInfo.getReactions() != 0 ? VISIBLE : GONE); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (needDivider) { + dividerPaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + int paddingDp = 72; + if (LocaleController.isRTL) { + canvas.drawRect(0, getHeight() - 1, getWidth() - dp(paddingDp), getHeight(), dividerPaint); + } else { + canvas.drawRect(dp(paddingDp), getHeight() - 1, getWidth(), getHeight(), dividerPaint); + } + } } public void setData(StatisticActivity.MemberData memberData) { @@ -149,5 +271,12 @@ public void setData(StatisticActivity.MemberData memberData) { views.setVisibility(View.GONE); shares.setVisibility(View.GONE); + likes.setVisibility(View.GONE); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + storyAvatarParams.onDetachFromWindow(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index 28dca70384..abc4dfb3aa 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; @@ -15,6 +17,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.view.Gravity; import android.view.View; @@ -31,6 +34,8 @@ 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 { @@ -92,11 +97,11 @@ public TextCell(Context context, int left, boolean dialog, boolean needCheck, Th 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); @@ -164,7 +169,7 @@ public void setPrioritizeTitleOverValue(boolean prioritizeTitleOverValue) { @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); @@ -173,16 +178,16 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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)); @@ -191,7 +196,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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)); } @@ -210,43 +215,43 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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()); } } @@ -255,11 +260,26 @@ public void setTextColor(int color) { textView.setTextColor(color); } + protected int processColor(int color) { + return color; + } + + public void updateColors() { + int textKey = textView.getTag() instanceof Integer ? (int) textView.getTag() : Theme.key_windowBackgroundWhiteBlackText; + textView.setTextColor(processColor(Theme.getColor(textKey, resourcesProvider))); + if (imageView.getTag() instanceof Integer) { + imageView.setColorFilter(new PorterDuffColorFilter(processColor(Theme.getColor((int) imageView.getTag(), resourcesProvider)), PorterDuff.Mode.MULTIPLY)); + } + subtitleView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider))); + valueTextView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText, resourcesProvider))); + valueSpoilersTextView.setTextColor(processColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText, resourcesProvider))); + } + public void setColors(int icon, int text) { - textView.setTextColor(Theme.getColor(text, resourcesProvider)); + textView.setTextColor(processColor(Theme.getColor(text, resourcesProvider))); textView.setTag(text); if (icon >= 0) { - imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(icon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + imageView.setColorFilter(new PorterDuffColorFilter(processColor(Theme.getColor(icon, resourcesProvider)), PorterDuff.Mode.MULTIPLY)); imageView.setTag(icon); } } @@ -269,6 +289,7 @@ public void setColors(int icon, int text) { public void setText(CharSequence text, boolean divider) { imageLeft = 21; textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); imageView.setVisibility(GONE); valueTextView.setVisibility(GONE); @@ -278,10 +299,16 @@ public void setText(CharSequence text, boolean divider) { setWillNotDraw(!needDivider); } + 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); if (resId != 0) { imageView.setImageResource(resId); @@ -293,14 +320,16 @@ public void setTextAndIcon(CharSequence text, int resId, boolean divider) { valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); + 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); @@ -313,6 +342,7 @@ public void setTextAndIcon(CharSequence text, Drawable drawable, boolean divider offsetFromImage = 68; imageLeft = 18; textView.setText(text); + textView.setRightDrawable(null); valueTextView.setText(valueText = null, false); imageView.setColorFilter(null); if (drawable instanceof RLottieDrawable) { @@ -323,7 +353,7 @@ public void setTextAndIcon(CharSequence text, Drawable drawable, boolean divider 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); } @@ -344,6 +374,7 @@ public void setTextAndValue(CharSequence text, String value, boolean animated, b 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); @@ -360,6 +391,7 @@ public void setTextAndValueAndColorfulIcon(String text, CharSequence value, bool 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); @@ -376,6 +408,7 @@ public void setTextAndSpoilersValueAndIcon(String text, CharSequence value, int imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueSpoilersTextView.setVisibility(VISIBLE); valueSpoilersTextView.setText(value); valueTextView.setVisibility(GONE); @@ -383,7 +416,7 @@ public void setTextAndSpoilersValueAndIcon(String text, CharSequence value, int 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); @@ -396,6 +429,7 @@ public void setTextAndSpoilersValueAndColorfulIcon(String text, CharSequence val imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueSpoilersTextView.setVisibility(VISIBLE); valueSpoilersTextView.setText(value); valueTextView.setVisibility(GONE); @@ -416,6 +450,7 @@ public void setTextAndValueAndIcon(CharSequence text, String value, boolean anim 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); @@ -423,7 +458,7 @@ public void setTextAndValueAndIcon(CharSequence text, String value, boolean anim 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); @@ -432,20 +467,30 @@ public void setTextAndValueAndIcon(CharSequence text, String value, boolean anim } } + public static CharSequence applyNewSpan(CharSequence str) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + spannableStringBuilder.append(" d"); + FilterCreateActivity.NewSpan span = new FilterCreateActivity.NewSpan(10); + span.setColor(Theme.getColor(Theme.key_premiumGradient1)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + return spannableStringBuilder; + } + public void setColorfulIcon(int color, int resId) { offsetFromImage = getOffsetFromImage(true); imageView.setVisibility(VISIBLE); - 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; @@ -460,6 +505,7 @@ public void setTextAndCheckAndIcon(CharSequence text, boolean checked, int resId imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); @@ -468,7 +514,7 @@ public void setTextAndCheckAndIcon(CharSequence text, boolean checked, int resId 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); @@ -478,6 +524,7 @@ public void setTextAndCheckAndIcon(CharSequence text, boolean checked, Drawable imageLeft = 21; offsetFromImage = getOffsetFromImage(false); textView.setText(text); + textView.setRightDrawable(null); valueTextView.setVisibility(GONE); valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); @@ -486,7 +533,7 @@ public void setTextAndCheckAndIcon(CharSequence text, boolean checked, Drawable 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); @@ -496,13 +543,14 @@ public void setTextAndValueDrawable(CharSequence text, Drawable drawable, boolea 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) { @@ -521,7 +569,7 @@ protected void onDraw(Canvas canvas) { 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); } } @@ -671,16 +719,16 @@ protected void dispatchDraw(Canvas canvas) { 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 4cbb845b9c..d3de4842eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -405,10 +405,13 @@ protected void onDraw(Canvas canvas) { 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(0, getMeasuredHeight() - 3, getMeasuredWidth(), getMeasuredHeight() - 3, 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/TextDetailCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java index 21fed2c04c..1162db5136 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailCell.java @@ -36,7 +36,7 @@ public class TextDetailCell extends FrameLayout { private final TextView textView; - private final LinkSpanDrawable.LinksTextView valueTextView; + public final LinkSpanDrawable.LinksTextView valueTextView; private final TextView showMoreTextView = null; private final ImageView imageView; private boolean needDivider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java index 39fcda2577..9e32989723 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.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.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.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 { @@ -72,8 +76,12 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t this(context, layout, type, 0); } - @SuppressLint("ClickableViewAccessibility") public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int type, long dialogId) { + this(context, layout, type, dialogId, null); + } + + @SuppressLint("ClickableViewAccessibility") + public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int type, long dialogId, Theme.ResourcesProvider resourcesProvider) { super(context); this.type = type; int currentAccount = UserConfig.selectedAccount; @@ -83,7 +91,7 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t setOrientation(LinearLayout.VERTICAL); setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11)); - shadowDrawable = Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + shadowDrawable = Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow, resourcesProvider); int date = (int) (System.currentTimeMillis() / 1000) - 60 * 60; @@ -92,10 +100,6 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t if (type == TYPE_PEER_COLOR) { final boolean isChannel = dialogId < 0; - ChatActionCell actionCell = new ChatActionCell(context); - actionCell.setCustomText(LocaleController.getString(R.string.UserColorPreviewTitle)); - addView(actionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 2, 0, 5)); - TLRPC.Message message = new TLRPC.TL_message(); message.message = LocaleController.getString(isChannel ? R.string.ChannelColorPreview : R.string.UserColorPreview); message.reply_to = new TLRPC.TL_messageReplyHeader(); @@ -277,7 +281,7 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t } for (int a = 0; a < cells.length; a++) { - cells[a] = new ChatMessageCell(context) { + cells[a] = new ChatMessageCell(context, false, null, resourcesProvider) { private GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { @@ -345,7 +349,7 @@ protected void dispatchDraw(Canvas canvas) { MessagesController.PeerColors peerColors = messagesController != null ? messagesController.peerColors : null; MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null; if (peerColor != null) { - final int peerColorValue = messagesController.peerColors.getColor(colorId).getColor1(); + final int peerColorValue = peerColor.getColor1(); color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getPeerColorIndex(peerColorValue)]); color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getPeerColorIndex(peerColorValue)]); } else { @@ -437,14 +441,44 @@ public void invalidate() { } } + 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) { - Drawable newDrawable = Theme.getCachedWallpaperNonBlocking(); + Drawable newDrawable = overrideDrawable != null ? overrideDrawable : Theme.getCachedWallpaperNonBlocking(); if (Theme.wallpaperLoadTask != null) { invalidate(); } if (newDrawable != backgroundDrawable && newDrawable != null) { - if (Theme.isAnimatingColor()) { + if (Theme.isAnimatingColor() || customAnimation) { oldBackgroundDrawable = backgroundDrawable; oldBackgroundGradientDisposable = backgroundGradientDisposable; } else if (backgroundGradientDisposable != null) { @@ -452,15 +486,16 @@ protected void onDraw(Canvas canvas) { 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; @@ -500,6 +535,8 @@ protected void onDraw(Canvas canvas) { } drawable.draw(canvas); canvas.restore(); + } else { + StoryEntry.drawBackgroundDrawable(canvas, drawable, getWidth(), getHeight()); } if (a == 0 && oldBackgroundDrawable != null && themeAnimationValue >= 1.0f) { if (oldBackgroundGradientDisposable != null) { @@ -529,6 +566,9 @@ protected void onDetachedFromWindow() { oldBackgroundGradientDisposable.dispose(); oldBackgroundGradientDisposable = null; } + if (overrideDrawable instanceof ChatBackgroundDrawable) { + ((ChatBackgroundDrawable) overrideDrawable).onDetachedFromWindow(this); + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 1a298c6b48..a22f16ffe6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -525,14 +525,14 @@ public void update(int mask) { ((LayoutParams) nameTextView.getLayoutParams()).topMargin = AndroidUtilities.dp(19); return; } - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } else if (currentName != null) { avatarDrawable.setInfo(currentId, currentName.toString(), null); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java index 56a646e958..f20b89bf65 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell2.java @@ -229,14 +229,14 @@ public void update(int mask) { lastAvatar = photo; if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } else if (currentName != null) { avatarDrawable.setInfo(currentId, currentName.toString(), null); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java index 6b39900c31..a4f9d6ce39 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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 8874f08f2e..e755a53c02 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2087,6 +2087,9 @@ private void updateMessagesVisiblePart() { } else if (view instanceof ChatActionCell) { ChatActionCell cell = (ChatActionCell) view; cell.setVisiblePart(view.getY() + actionBar.getMeasuredHeight() - contentView.getBackgroundTranslationY(), contentView.getBackgroundSizeY()); + if (cell.hasGradientService()) { + cell.invalidate(); + } } if (view.getBottom() <= chatListView.getPaddingTop()) { continue; @@ -2371,7 +2374,7 @@ public void didPressSideButton(ChatMessageCell cell) { } @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); @@ -2676,6 +2679,10 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { @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 0000000000..c255fb1691 --- /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 0000000000..4bda72b241 --- /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/BaseChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java index b2bfc7ce67..cc0da46303 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java @@ -65,6 +65,7 @@ public abstract class BaseChartView private final static int BOTTOM_SIGNATURE_OFFSET = AndroidUtilities.dp(10); private final static int DP_12 = AndroidUtilities.dp(12); + private final static int DP_8 = AndroidUtilities.dp(8); private final static int DP_6 = AndroidUtilities.dp(6); private final static int DP_5 = AndroidUtilities.dp(5); private final static int DP_2 = AndroidUtilities.dp(2); @@ -226,9 +227,15 @@ public void onAnimationEnd(Animator animation) { private float startFromMaxH; private float startFromMinH; private float minMaxUpdateStep; + protected Theme.ResourcesProvider resourcesProvider; public BaseChartView(Context context) { + this(context, null); + } + + public BaseChartView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + this.resourcesProvider = resourcesProvider; init(); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @@ -262,23 +269,23 @@ protected void init() { } protected LegendSignatureView createLegendView() { - return new LegendSignatureView(getContext()); + return new LegendSignatureView(getContext(), resourcesProvider); } public void updateColors() { if (useAlphaSignature) { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignatureAlpha)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignatureAlpha, resourcesProvider)); } else { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); } - bottomSignaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); - linePaint.setColor(Theme.getColor(Theme.key_statisticChartHintLine)); - selectedLinePaint.setColor(Theme.getColor(Theme.key_statisticChartActiveLine)); - pickerSelectorPaint.setColor(Theme.getColor(Theme.key_statisticChartActivePickerChart)); - unactiveBottomChartPaint.setColor(Theme.getColor(Theme.key_statisticChartInactivePickerChart)); - selectionBackgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - ripplePaint.setColor(Theme.getColor(Theme.key_statisticChartRipple)); + bottomSignaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); + linePaint.setColor(Theme.getColor(Theme.key_statisticChartHintLine, resourcesProvider)); + selectedLinePaint.setColor(Theme.getColor(Theme.key_statisticChartActiveLine, resourcesProvider)); + pickerSelectorPaint.setColor(Theme.getColor(Theme.key_statisticChartActivePickerChart, resourcesProvider)); + unactiveBottomChartPaint.setColor(Theme.getColor(Theme.key_statisticChartInactivePickerChart, resourcesProvider)); + selectionBackgroundPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + ripplePaint.setColor(Theme.getColor(Theme.key_statisticChartRipple, resourcesProvider)); legendSignatureView.recolor(); hintLinePaintAlpha = linePaint.getAlpha(); @@ -729,13 +736,13 @@ HORIZONTAL_PADDING, getMeasuredHeight() - PICKER_PADDING - pikerHeight, canvas.drawPath(RoundedRect(pathTmp, pickerRect.left, pickerRect.top - DP_1, pickerRect.left + DP_12, - pickerRect.bottom + DP_1, DP_6, DP_6, + pickerRect.bottom + DP_1, DP_8, DP_8, true, false, false, true), pickerSelectorPaint); canvas.drawPath(RoundedRect(pathTmp, pickerRect.right - DP_12, pickerRect.top - DP_1, pickerRect.right, - pickerRect.bottom + DP_1, DP_6, DP_6, + pickerRect.bottom + DP_1, DP_8, DP_8, false, true, true, false), pickerSelectorPaint); canvas.drawRect(pickerRect.left + DP_12, @@ -1592,10 +1599,16 @@ public static class SharedUiComponents { private RectF rectF = new RectF(); private Paint xRefP = new Paint(Paint.ANTI_ALIAS_FLAG); + private Theme.ResourcesProvider resourcesProvider; public SharedUiComponents() { + this(null); + } + + public SharedUiComponents(Theme.ResourcesProvider resourcesProvider) { xRefP.setColor(0); xRefP.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + this.resourcesProvider = resourcesProvider; } int k = 0; @@ -1609,8 +1622,8 @@ Bitmap getPickerMaskBitmap(int h, int w) { canvas = new Canvas(pickerRoundBitmap); rectF.set(0, 0, w, h); - canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), xRefP); + canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(6), AndroidUtilities.dp(6), xRefP); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java index 1a360db042..a604d66c0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java @@ -14,7 +14,11 @@ public class DoubleLinearChartView extends BaseChartView { public DoubleLinearChartView(Context context) { - super(context); + this(context, null); + } + + public DoubleLinearChartView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); } @Override @@ -240,7 +244,7 @@ protected void drawSignaturesToHorizontalLines(Canvas canvas, ChartHorizontalLin int y = (int) ((getMeasuredHeight() - chartBottom) - chartHeight * ((a.values[i] - currentMinHeight) / (currentMaxHeight - currentMinHeight))); if (a.valuesStr != null && lines.size() > 0) { if (a.valuesStr2 == null || lines.size() < 2) { - signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature)); + signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature, resourcesProvider)); signaturePaint.setAlpha((int) (a.alpha * signaturePaintAlpha * transitionAlpha * additionalOutAlpha)); } else { signaturePaint.setColor(lines.get(leftIndex).lineColor); @@ -259,7 +263,7 @@ protected void drawSignaturesToHorizontalLines(Canvas canvas, ChartHorizontalLin @Override public LineViewData createLineViewData(ChartData.Line line) { - return new LineViewData(line); + return new LineViewData(line, resourcesProvider); } public int findMaxValue(int startXIndex, int endXIndex) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java index d772343b09..a131107e60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/StackBarChartView.java @@ -8,6 +8,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.SegmentTree; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Charts.data.ChartData; import org.telegram.ui.Charts.data.StackBarChartData; import org.telegram.ui.Charts.view_data.LineViewData; @@ -18,14 +19,18 @@ public class StackBarChartView extends BaseChartView { datesTmp.setPivotX(datesTmp.getMeasuredWidth() * 0.7f); @@ -87,11 +93,11 @@ public ChartHeaderView(Context context) { public void recolor() { - title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - dates.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - datesTmp.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - back.setTextColor(Theme.getColor(Theme.key_statisticChartBackZoomColor)); - zoomIcon.setColorFilter(Theme.getColor(Theme.key_statisticChartBackZoomColor), PorterDuff.Mode.SRC_IN); + title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + dates.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + datesTmp.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + back.setTextColor(Theme.getColor(Theme.key_statisticChartBackZoomColor, resourcesProvider)); + zoomIcon.setColorFilter(Theme.getColor(Theme.key_statisticChartBackZoomColor, resourcesProvider), PorterDuff.Mode.SRC_IN); } public void setDates(long start, long end) { @@ -105,9 +111,9 @@ public void setDates(long start, long end) { } final String newText; if (end - start >= 86400000L) { - newText = formatter.format(new Date(start)) + " — " + formatter.format(new Date(end)); + newText = LocaleController.getInstance().formatterYear.format(new Date(start)) + " — " + LocaleController.getInstance().formatterYear.format(new Date(end)); } else { - newText = formatter.format(new Date(start)); + newText = LocaleController.getInstance().formatterYear.format(new Date(start)); } dates.setText(newText); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/ChartHorizontalLinesData.java index 4d8313fcf3..5213589210 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 ChartHorizontalLinesData(int newMaxHeight, int newMinHeight, boolean useM 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/Charts/view_data/LegendSignatureView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java index c1091e04c6..056965b8cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LegendSignatureView.java @@ -56,6 +56,7 @@ public class LegendSignatureView extends FrameLayout { Drawable shadowDrawable; Drawable backgroundDrawable; + private Theme.ResourcesProvider resourcesProvider; Runnable showProgressRunnable = new Runnable() { @Override @@ -72,7 +73,12 @@ public void run() { }; public LegendSignatureView(Context context) { + this(context, null); + } + + public LegendSignatureView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + this.resourcesProvider = resourcesProvider; setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); content = new LinearLayout(getContext()); content.setOrientation(LinearLayout.VERTICAL); @@ -102,13 +108,13 @@ public LegendSignatureView(Context context) { } public void recolor() { - time.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - hourTime.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - chevron.setColorFilter(Theme.getColor(Theme.key_statisticChartChevronColor)); - progressView.setProgressColor(Theme.getColor(Theme.key_statisticChartChevronColor)); + time.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + hourTime.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + chevron.setColorFilter(Theme.getColor(Theme.key_statisticChartChevronColor, resourcesProvider)); + progressView.setProgressColor(Theme.getColor(Theme.key_statisticChartChevronColor, resourcesProvider)); shadowDrawable = getContext().getResources().getDrawable(R.drawable.stats_tooltip).mutate(); - backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_dialogBackground), Theme.getColor(Theme.key_listSelector), 0xff000000); + backgroundDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_dialogBackground, resourcesProvider), Theme.getColor(Theme.key_listSelector, resourcesProvider), 0xff000000); CombinedDrawable drawable = new CombinedDrawable(shadowDrawable, backgroundDrawable, AndroidUtilities.dp(3), AndroidUtilities.dp(3)); drawable.setFullsize(true); setBackground(drawable); @@ -169,15 +175,15 @@ public void setData(int index, long date, ArrayList lines, boolean h.value.setText(formatWholeNumber(l.y[index])); h.signature.setText(l.name); if (l.colorKey >= 0 && Theme.hasThemeKey(l.colorKey)) { - h.value.setTextColor(Theme.getColor(l.colorKey)); + h.value.setTextColor(Theme.getColor(l.colorKey, resourcesProvider)); } else { h.value.setTextColor(Theme.getCurrentTheme().isDark() ? l.colorDark : l.color); } - h.signature.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + h.signature.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); if (showPercentage && h.percentage != null) { h.percentage.setVisibility(VISIBLE); - h.percentage.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + h.percentage.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); float v = lines.get(i).line.y[index] / (float) sum; if (v < 0.1f && v != 0f) { h.percentage.setText(String.format(Locale.ENGLISH, "%.1f%s", (100f * v), "%")); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java index 7c81692e8b..0d1f7256a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/LineViewData.java @@ -35,7 +35,14 @@ public class LineViewData { public float alpha = 1f; + private Theme.ResourcesProvider resourcesProvider; + public LineViewData(ChartData.Line line) { + this(line, null); + } + + public LineViewData(ChartData.Line line, Theme.ResourcesProvider resourcesProvider) { + this.resourcesProvider = resourcesProvider; this.line = line; paint.setStrokeWidth(AndroidUtilities.dpf2(2)); @@ -61,9 +68,9 @@ public LineViewData(ChartData.Line line) { public void updateColors() { if (line.colorKey >= 0 && Theme.hasThemeKey(line.colorKey)) { - lineColor = Theme.getColor(line.colorKey); + lineColor = Theme.getColor(line.colorKey, resourcesProvider); } else { - int color = Theme.getColor(Theme.key_windowBackgroundWhite); + int color = Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider); boolean darkBackground = ColorUtils.calculateLuminance(color) < 0.5f; lineColor = darkBackground ? line.colorDark : line.color; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java index 62b09d71ec..9ca28a2c4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/view_data/StackBarViewData.java @@ -13,13 +13,20 @@ public class StackBarViewData extends LineViewData { public final Paint unselectedPaint = new Paint(); public int blendColor = 0; + private Theme.ResourcesProvider resourcesProvider; + public void updateColors() { super.updateColors(); - blendColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhite),lineColor,0.3f); + blendColor = ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider),lineColor,0.3f); } public StackBarViewData(ChartData.Line line) { + this(line, null); + } + + public StackBarViewData(ChartData.Line line, Theme.ResourcesProvider resourcesProvider) { super(line); + this.resourcesProvider = resourcesProvider; paint.setStrokeWidth(AndroidUtilities.dpf2(1)); paint.setStyle(Paint.Style.STROKE); unselectedPaint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 331277fe5c..b472d87d1c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -8,6 +8,8 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -48,8 +50,10 @@ import android.graphics.Region; import android.graphics.Shader; import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -206,123 +210,33 @@ 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.AvatarDrawable; -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.EmojiTextView; -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.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.ByteArrayOutputStream; @@ -476,6 +390,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ActionBarMenuItem.Item toTheMessage; private ActionBarMenuItem.Item hideTitleItem; private ClippingImageView animatingImageView; + private ThanosEffect chatListThanosEffect; public RecyclerListView chatListView; private ChatListItemAnimator chatListItemAnimator; private GridLayoutManagerFixed chatLayoutManager; @@ -821,7 +736,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean[] cacheEndReached = new boolean[2]; private boolean[] forwardEndReached = new boolean[]{true, true}; private boolean hideForwardEndReached; - private boolean loading; + private boolean loading = true; private boolean firstLoading = true; private boolean chatWasReset; private boolean firstUnreadSent; @@ -897,6 +812,7 @@ public int getColor(int key) { public int highlightMessageId = Integer.MAX_VALUE; public boolean showNoQuoteAlert; public String highlightMessageQuote; + public int highlightMessageQuoteOffset = -1; private int scrollToMessagePosition = -10000; private Runnable unselectRunnable; @@ -1007,11 +923,12 @@ public void run() { private boolean openImport; - private float chatListViewPaddingTop; - private int chatListViewPaddingVisibleOffset; + public float chatListViewPaddingTop; + public int chatListViewPaddingVisibleOffset; private int contentPaddingTop; private float contentPanTranslation; + private float contentPanTranslationT; private float floatingDateViewOffset; private float topChatPanelViewOffset; private float pinnedMessageEnterOffset; @@ -1051,6 +968,7 @@ public void run() { }; private ChatSelectionReactionMenuOverlay selectionReactionsOverlay; + private SecretVoicePlayer secretVoicePlayer; private boolean isPauseOnThemePreview; private ChatThemeBottomSheet chatThemeBottomSheet; @@ -1242,6 +1160,10 @@ public int getTopicId() { return isTopic ? threadMessageId : 0; } + public boolean isForumInViewAsMessagesMode() { + return ChatObject.isForum(currentChat) && !isTopic; + } + @Override public List onGetDebugItems() { List items = new ArrayList<>(); @@ -1293,7 +1215,6 @@ public Object get(Object object) { } })); } - return items; } @@ -1492,7 +1413,7 @@ public boolean onItemClick(View view, int position, float x, float y) { } processRowSelect(view, outside, x, y); } - if (view instanceof ChatMessageCell) { + if (view instanceof ChatMessageCell && (((ChatMessageCell) view).getMessageObject() != null && ((ChatMessageCell) view).getMessageObject().type != MessageObject.TYPE_JOINED_CHANNEL)) { startMultiselect(position); result = true; } @@ -1639,6 +1560,19 @@ public void onItemClick(View view, int position, float x, float y) { processRowSelect(view, outside, x, y); return; } + if (view instanceof ChatMessageCell) { + MessageObject msg = ((ChatMessageCell) view).getMessageObject(); + if (msg != null && msg.type == MessageObject.TYPE_JOINED_CHANNEL) { + msg.toggleChannelRecommendations(); + msg.forceUpdate = true; + ((ChatMessageCell) view).forceResetMessageObject(); + view.requestLayout(); + if (position >= 0) { + chatAdapter.notifyItemChanged(position); + } + return; + } + } createMenu(view, true, false, x, y); } @@ -1719,18 +1653,13 @@ public void onDoubleTap(View view, int position, float x, float y) { if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_NONE || !(view instanceof ChatMessageCell) || getParentActivity() == null || isSecretChat() || isInScheduleMode() || isInPreviewMode()) { return; } - if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SHOW_REACTIONS) { - if (isSecretChat() || isInScheduleMode()) { - return; - } - createMenu(view, true, false, x, y, true, true); - } else if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SEND_REACTIONS) { + if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SEND_REACTIONS) { if (isSecretChat() || isInScheduleMode()) { return; } ChatMessageCell cell = (ChatMessageCell) view; MessageObject primaryMessage = cell.getPrimaryMessageObject(); - if (primaryMessage.isSecretMedia()) { + if (primaryMessage.isSecretMedia() || primaryMessage.isExpiredStory() || primaryMessage.type == MessageObject.TYPE_JOINED_CHANNEL) { return; } ReactionsEffectOverlay.removeCurrent(false); @@ -1758,6 +1687,8 @@ public void onDoubleTap(View view, int position, float x, float y) { } selectReaction(primaryMessage, null, null, x, y, ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction), true, false, false); } + } else if (NaConfig.INSTANCE.getDoubleTapAction().Int() == DoubleTap.DOUBLE_TAP_ACTION_SHOW_REACTIONS) { + createMenu(view, true, false, x, y, true, true); } else { var cell = (ChatMessageCell) view; var message = cell.getMessageObject(); @@ -1868,7 +1799,7 @@ public void onMessageSend(CharSequence message, boolean notify, int scheduleDate chatActivityEnterView.getEmojiView().onMessageSend(); } - if (!getMessagesController().premiumLocked && !getMessagesController().didPressTranscribeButtonEnough() && !getUserConfig().isPremium() && !TextUtils.isEmpty(message) && messages != null) { + if (!getMessagesController().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()) { @@ -2180,7 +2111,7 @@ public void didPressAttachButton() { } @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) { @@ -2188,7 +2119,7 @@ public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { 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); } @@ -2322,6 +2253,11 @@ public void onKeyboardRequested() { checkAdjustResize(); } + @Override + public boolean onceVoiceAvailable() { + return currentUser != null && !UserObject.isUserSelf(currentUser) && !currentUser.bot && currentEncryptedChat == null && chatMode == 0; + } + @Override public ReplyQuote getReplyQuote() { return replyingQuote; @@ -2625,6 +2561,8 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messageTranslating); getNotificationCenter().addObserver(this, NotificationCenter.onReceivedChannelDifference); getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); + getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); + getNotificationCenter().addObserver(this, NotificationCenter.updateTranscriptionLock); super.onFragmentCreate(); @@ -2748,7 +2686,7 @@ public boolean onFragmentCreate() { } themeDelegate = new ThemeDelegate(); - if (themeDelegate.isThemeChangeAvailable()) { + if (themeDelegate.isThemeChangeAvailable(false)) { NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.needSetDayNightTheme); } @@ -2992,6 +2930,8 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslating); getNotificationCenter().removeObserver(this, NotificationCenter.onReceivedChannelDifference); getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); + getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); + getNotificationCenter().removeObserver(this, NotificationCenter.updateTranscriptionLock); if (currentEncryptedChat != null) { getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } @@ -3267,6 +3207,7 @@ public void onItemClick(final int id) { } } } else if (id == view_as_topics) { + getMessagesController().getTopicsController().toggleViewForumAsMessages(-dialog_id, false); TopicsFragment.prepareToSwitchAnimation(ChatActivity.this); } else if (id == copy) { SpannableStringBuilder str = new SpannableStringBuilder(); @@ -3887,7 +3828,7 @@ public void toggleMute() { 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) { @@ -4099,6 +4040,12 @@ public void setTranslationY(float translationY) { } } + @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(); @@ -4376,18 +4323,12 @@ private void processTouchEvent(MotionEvent e) { } slidingView = (ChatMessageCell) view; MessageObject message = slidingView.getMessageObject(); - boolean allowReplyOnOpenTopic = false; - if (message != null && ChatObject.isForum(currentChat)) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, MessageObject.getTopicId(message.messageOwner, true)); - if (topic != null) { - allowReplyOnOpenTopic = !topic.closed || ChatObject.canManageTopic(currentAccount, currentChat, topic); - } - } + boolean allowReplyOnOpenTopic = canSendMessageToTopic(message); if (chatMode != 0 || threadMessageObjects != null && threadMessageObjects.contains(message) || getMessageType(message) == 1 && (message.getDialogId() == mergeDialogId || message.needDrawBluredPreview()) || currentEncryptedChat == null && message.getId() < 0 || bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE && !(bottomOverlayChatWaitsReply && allowReplyOnOpenTopic || message.wasJustSent) || - currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat)) || + currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat) || (ChatObject.isForum(currentChat) && !allowReplyOnOpenTopic)) || textSelectionHelper.isInSelectionMode()) { if (!canSendInCommentGroup()) { slidingView.setSlidingOffset(0); @@ -4746,8 +4687,12 @@ public void draw(Canvas canvas) { int alpha = skeletonPaint.getAlpha(); int wasServiceAlpha = skeletonServicePaint.getAlpha(); int wasOutlineAlpha = skeletonOutlinePaint.getAlpha(); - skeletonServicePaint.setAlpha((int) (0xFF * topSkeletonAlpha)); - skeletonPaint.setAlpha((int) (topSkeletonAlpha * alpha)); + float adaptDark = 1f; + if (themeDelegate != null && themeDelegate.isDark && skeletonServicePaint.getShader() != null) { + adaptDark *= .3f; + } + skeletonServicePaint.setAlpha((int) (0xFF * topSkeletonAlpha * adaptDark)); + skeletonPaint.setAlpha((int) (topSkeletonAlpha * adaptDark * alpha)); skeletonOutlinePaint.setAlpha((int) (topSkeletonAlpha * alpha)); while (lastTop > blurredViewTopOffset) { lastTop -= AndroidUtilities.dp(3f); @@ -4962,6 +4907,9 @@ private void drawChatBackgroundElements(Canvas canvas) { 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; @@ -5093,7 +5041,7 @@ private void drawChatBackgroundElements(Canvas canvas) { 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(); @@ -5226,7 +5174,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { 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; } @@ -5368,7 +5316,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { 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(); } @@ -5698,6 +5646,7 @@ public void endAnimations() { }); } }; + chatListItemAnimator.setOnSnapMessage(this::supportsThanosEffect, this::getChatThanosEffect); } chatLayoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, true) { @@ -6002,6 +5951,9 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { @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) { @@ -6104,8 +6056,29 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { progressView.setVisibility(View.INVISIBLE); contentView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); - progressView2 = new View(context); - progressView2.setBackground(Theme.createServiceDrawable(AndroidUtilities.dp(18), progressView2, contentView, getThemedPaint(Theme.key_paint_chatActionBackground))); + progressView2 = new View(context) { + private final RectF rect = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rect.set(0, 0, getWidth(), getHeight()); + applyServiceShaderMatrix(); + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackground)); + if (themeDelegate != null ? themeDelegate.hasGradientService() : Theme.hasGradientService()) { + canvas.drawRoundRect(rect, dp(18), dp(18), getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + super.dispatchDraw(canvas); + } + public void applyServiceShaderMatrix() { + applyServiceShaderMatrix(getMeasuredWidth(), getServiceHeight(this), getX(), getServiceTop(this)); + } + private void applyServiceShaderMatrix(int measuredWidth, int backgroundHeight, float x, float viewTop) { + if (themeDelegate != null) { + themeDelegate.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } else { + Theme.applyServiceShaderMatrix(measuredWidth, backgroundHeight, x, viewTop); + } + } + }; progressView.addView(progressView2, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); progressBar = new RadialProgressView(context, themeDelegate); @@ -6114,6 +6087,10 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { progressView.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); floatingDateView = new ChatActionCell(context, false, themeDelegate) { + @Override + public boolean isFloating() { + return true; + } @Override public void setTranslationY(float translationY) { @@ -10222,7 +10199,7 @@ public void processInlineBotWebView(TLRPC.TL_inlineBotWebView object) { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), getResourceProvider()); webViewSheet.setParentActivity(getParentActivity()); webViewSheet.requestWebView(currentAccount, currentUser != null ? currentUser.id : currentChat.id, mentionContainer.getAdapter().getFoundContextBot().id, object.text, object.url, BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON, 0, false, BotWebViewSheet.FLAG_FROM_INLINE_SWITCH); - webViewSheet.show(); + showDialog(webViewSheet); }; if (approved) { open.run(); @@ -11774,6 +11751,7 @@ public void searchLinks(final CharSequence charSequence, final boolean force) { } textToCheck = charSequence; } + final String firstUrl = urls == null || urls.isEmpty() ? null : urls.get(0).toString(); if (currentEncryptedChat != null && messagesController.secretWebpagePreview == 2) { AndroidUtilities.runOnUIThread(() -> { @@ -12010,11 +11988,11 @@ private ReplyQuote(long peerId, @NonNull MessageObject message, int start, int e update(); } - public static ReplyQuote from(MessageObject messageObject, String text) { + public static ReplyQuote from(MessageObject messageObject, String text, int offset) { if (messageObject == null || messageObject.messageOwner == null || messageObject.messageOwner.message == null || text == null) { return null; } - int start = messageObject.messageOwner.message.indexOf(text); + int start = MessageObject.findQuoteStart(messageObject.messageOwner.message, text, offset); if (start < 0) { return null; } @@ -12322,12 +12300,27 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes } } else if (messageObjectToReply != null) { editingMessageObject = null; + + // set it for a case when replying in in View as messages mode + MessageObject topicTopMessageObject = null; + if (isForumInViewAsMessagesMode()) { + int topicId = MessageObject.getTopicId(messageObjectToReply.messageOwner, true); + if (topicId != 0) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null && topic.topicStartMessage != null) { + topicTopMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, false, false); + topicTopMessageObject.isTopicMainMessage = true; + topicTopMessageObject.replyToForumTopic = topic; + } + } + } + replyingMessageObject = messageObjectToReply; replyingQuote = quote; if (replyingQuote != null && replyingQuote.getText() == null) { replyingQuote = null; } - chatActivityEnterView.setReplyingMessageObject(messageObjectToReply, quote); + chatActivityEnterView.setReplyingMessageObject(messageObjectToReply, quote, topicTopMessageObject); chatActivityEnterView.setEditingMessageObject(null, false); forbidForwardingWithDismiss = false; if (messagePreviewParams == null) { @@ -12559,7 +12552,9 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes 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) { @@ -13161,8 +13156,8 @@ public void updateMessagesVisiblePart(boolean inLayout) { minAdapterPosition = adapterPosition; } } - int top = (int) view.getY(); - int bottom = top + view.getMeasuredHeight(); + final int top = (int) view.getY(); + final int bottom = top + view.getMeasuredHeight(); ChatMessageCell messageCell = null; if (view instanceof ChatMessageCell) { messageCell = (ChatMessageCell) view; @@ -13195,6 +13190,12 @@ public void updateMessagesVisiblePart(boolean inLayout) { keyboardOffset = chatActivityEnterView.getEmojiPadding(); } + // in channels mark as read messages that are visible 80% on the screen + final boolean visibleToBeRead = currentChat == null || !ChatObject.isChannelAndNotMegaGroup(currentChat) || view.getMeasuredHeight() > 0 && top + view.getMeasuredHeight() * .80f < clipBottomFinal; + + final float visibleTop = getServiceTop(view); + final int visibleBackgroundHeight = getServiceHeight(view); + if (messageCell != null) { messageObject = messageCell.getMessageObject(); if (messageObject.getDialogId() == dialog_id && messageObject.getId() > maxVisibleId) { @@ -13203,7 +13204,7 @@ public void updateMessagesVisiblePart(boolean inLayout) { } messageCell.setParentBounds(chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4), chatListView.getMeasuredHeight() - blurredViewBottomOffset); - messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, keyboardOffset, view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY(), contentView.getMeasuredWidth(), contentView.getBackgroundSizeY(), blurredViewTopOffset, blurredViewBottomOffset); + messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, keyboardOffset, view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY() - (1f - contentPanTranslationT) * chatListViewPaddingTop, contentView.getMeasuredWidth(), contentView.getBackgroundSizeY(), blurredViewTopOffset, blurredViewBottomOffset); markSponsoredAsRead(messageObject); if (!threadMessageVisible && messageStarter != null && (messageObject == messageStarter || isTopic && messageObject != null && messageObject.getId() == messageStarter.getId()) && messageCell.getBottom() > chatListViewPaddingTop) { threadMessageVisible = true; @@ -13267,13 +13268,18 @@ public void updateMessagesVisiblePart(boolean inLayout) { if (messageObject != null && messageObject.getDialogId() == dialog_id && messageObject.getId() > maxVisibleId) { maxVisibleId = Math.max(maxVisibleId, messageObject.getId()); } - cell.setVisiblePart(view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY(), contentView.getBackgroundSizeY()); + cell.setVisiblePart(visibleTop, visibleBackgroundHeight); } else if (view instanceof BotHelpCell) { view.invalidate(); + } else if (view instanceof ChatLoadingCell) { + ((ChatLoadingCell) view).setVisiblePart(visibleTop, visibleBackgroundHeight); } if (chatMode != MODE_SCHEDULED && messageObject != null) { int id = messageObject.getId(); - if (!isThreadChat() && (!messageObject.isOut() && messageObject.isUnread() || messageObject.messageOwner.from_scheduled && id > currentReadMaxId) || id > 0 && isThreadChat() && id > currentReadMaxId && id > replyMaxReadId) { + if ( + !isThreadChat() && visibleToBeRead && (!messageObject.isOut() && messageObject.isUnread() || messageObject.messageOwner.from_scheduled && id > currentReadMaxId) || + isThreadChat() && id > 0 && id > currentReadMaxId && id > replyMaxReadId + ) { if (id > 0) { maxPositiveUnreadId = Math.max(maxPositiveUnreadId, messageObject.getId()); } @@ -13548,6 +13554,17 @@ public void updateMessagesVisiblePart(boolean inLayout) { } } } + if (progressView2 != null) { + progressView2.invalidate(); + } + } + + private float getServiceTop(View view) { + return view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY() - (1f - contentPanTranslationT) * chatListViewPaddingTop; + } + + public int getServiceHeight(View view) { + return contentView.getBackgroundSizeY(); } private boolean pinnedOnlyStarterMessage() { @@ -13637,7 +13654,7 @@ private int scrollOffsetForQuote(MessageObject object) { return 0; } - int index = text.toString().indexOf(highlightMessageQuote); + int index = MessageObject.findQuoteStart(text.toString(), highlightMessageQuote, highlightMessageQuoteOffset); if (index < 0) { return 0; } @@ -13682,6 +13699,7 @@ private void startMessageUnselect() { unselectRunnable = () -> { highlightMessageId = Integer.MAX_VALUE; highlightMessageQuote = null; + highlightMessageQuoteOffset = -1; showNoQuoteAlert = false; updateVisibleRows(); unselectRunnable = null; @@ -14091,6 +14109,10 @@ public void onAnimationEnd(Animator animation) { public class ChatActivityFragmentView extends SizeNotifierFrameLayout { + public ChatActivity getChatActivity() { + return ChatActivity.this; + } + public ChatActivityFragmentView(Context context, INavigationLayout parentLayout) { super(context, parentLayout); adjustPanLayoutHelper = new AdjustPanLayoutHelper(this) { @@ -14128,6 +14150,7 @@ protected void onPanTranslationUpdate(float y, float progress, boolean keyboardV return; } contentPanTranslation = y; + contentPanTranslationT = progress; if (chatAttachAlert != null && chatAttachAlert.isShowing()) { setNonNoveTranslation(y); } else { @@ -15035,7 +15058,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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) { @@ -15254,7 +15277,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { } } 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)); @@ -15307,6 +15330,7 @@ private void setNonNoveTranslation(float y) { emptyViewContainer.setTranslationY(0); progressView.setTranslationY(0); contentPanTranslation = 0; + contentPanTranslationT = 0; contentView.setBackgroundTranslation(0); if (instantCameraView != null) { instantCameraView.onPanTranslationUpdate(0); @@ -15969,6 +15993,13 @@ public void onAnimationEnd(Animator animation) { newVisibility = View.GONE; } else if (selectedCount == 1) { newVisibility = View.VISIBLE; + for (int b = 0, N = selectedMessagesIds[0].size(); b < N; b++) { + MessageObject message = selectedMessagesIds[0].valueAt(b); + if (ChatObject.isForum(currentChat) && !canSendMessageToTopic(message)) { + newVisibility = View.GONE; + break; + } + } } else { newVisibility = View.VISIBLE; long lastGroupId = 0; @@ -15976,7 +16007,7 @@ public void onAnimationEnd(Animator animation) { for (int b = 0, N = selectedMessagesIds[a].size(); b < N; b++) { MessageObject message = selectedMessagesIds[a].valueAt(b); long groupId = message.getGroupId(); - if (groupId == 0 || lastGroupId != 0 && lastGroupId != groupId) { + if (groupId == 0 || lastGroupId != 0 && lastGroupId != groupId || (ChatObject.isForum(currentChat) && !canSendMessageToTopic(message))) { newVisibility = View.GONE; break; } @@ -16142,7 +16173,7 @@ private void processRowSelect(View view, boolean outside, float touchX, float to if (message != null && message.isAnyGift()) { return; } - if (type < 2 || type == 20 || type == MessageObject.TYPE_SUGGEST_PHOTO || (message != null && message.isWallpaperAction())) { + if (type < 2 || type == 20 || type == MessageObject.TYPE_SUGGEST_PHOTO || message != null && message.type == MessageObject.TYPE_JOINED_CHANNEL || (message != null && message.isWallpaperAction())) { return; } addToSelectedMessages(message, outside); @@ -16199,7 +16230,7 @@ public void updateTitle(boolean animated) { } 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)); @@ -17532,7 +17563,6 @@ public void didReceivedNotification(int id, int account, final Object... args) { messages.get(messages.size() - 1).stableId = lastStableId++; messages.add(messages.size() - 1, obj); } - MessageObject prevObj; if (currentEncryptedChat == null) { if (createUnreadMessageAfterId != 0 && load_type != 1 && a + 1 < messArr.size()) { @@ -18662,6 +18692,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (pendingRequestsDelegate != null) { pendingRequestsDelegate.setChatInfo(chatInfo, true); } + checkLeaveChannelButton(); } } else if (id == NotificationCenter.chatInfoCantLoad) { long chatId = (Long) args[0]; @@ -19521,7 +19552,8 @@ public void didReceivedNotification(int id, int account, final Object... args) { } 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); } } @@ -19818,6 +19850,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); loadingPinnedMessagesList = true; } + updateVisibleWallpaperActions(); } } else if (id == NotificationCenter.didSetNewWallpapper) { if (fragmentView != null) { @@ -20148,6 +20181,41 @@ public void didReceivedNotification(int id, int account, final Object... args) { if (avatarContainer != null) { avatarContainer.avatarImageView.invalidate(); } + } else if (id == NotificationCenter.channelRecommendationsLoaded) { + final long chatId = (long) args[0]; + if (chatListView != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell){ + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.channelRecommendationsCell != null && cell.channelRecommendationsCell.chatId == chatId) { + boolean wasExpanded = cell.channelRecommendationsCell.isExpanded(); + cell.channelRecommendationsCell.update(); + if (cell.channelRecommendationsCell.isExpanded() != wasExpanded) { + cell.getMessageObject().forceUpdate = true; + cell.forceResetMessageObject(); + cell.requestLayout(); + final int position = chatListView.getChildAdapterPosition(child); + if (position >= 0) { + chatAdapter.notifyItemChanged(position); + } + } + } + } + } + } + } else if (id == NotificationCenter.updateTranscriptionLock) { + if (chatListView != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell){ + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.transcribeButton != null) { + cell.transcribeButton.setLock(TranscribeButton.showTranscribeLock(cell.getMessageObject()), true); + } + } + } + } } } @@ -20723,7 +20791,7 @@ private void rotateMotionBackgroundDrawable() { wallpaper = ((SizeNotifierFrameLayout) fragmentView).getBackgroundImage(); } if (wallpaper instanceof ChatBackgroundDrawable) { - wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(); + wallpaper = ((ChatBackgroundDrawable) wallpaper).getDrawable(true); } if (wallpaper instanceof MotionBackgroundDrawable) { ((MotionBackgroundDrawable) wallpaper).switchToNextPosition(); @@ -20763,12 +20831,19 @@ private void processNewMessages(ArrayList arr) { messagesDict[0].put(messageObject.getId(), messageObject); messageObject.copyStableParams(messages.get(i)); if (type == MessageObject.TYPE_ACTION_WALLPAPER) { - messageObject.messageOwner.action.wallpaper = messages.get(i).messageOwner.action.wallpaper; + final TLRPC.WallPaper oldWallpaper = messages.get(i).messageOwner.action.wallpaper; + final long newId = messageObject.messageOwner.action.wallpaper != null ? messageObject.messageOwner.action.wallpaper.id : (oldWallpaper != null ? oldWallpaper.id : 0); + messageObject.messageOwner.action.wallpaper = oldWallpaper; + if (messageObject.messageOwner.action.wallpaper != null) { + messageObject.messageOwner.action.wallpaper.id = newId; + } } else if (type == MessageObject.TYPE_SUGGEST_PHOTO) { PhotoUtilities.replacePhotoImagesInCache(currentAccount, messages.get(i).messageOwner.action.photo, messageObject.messageOwner.action.photo); } messages.set(i, messageObject); - chatAdapter.notifyItemChanged(chatAdapter.messagesStartRow + i); + if (type != MessageObject.TYPE_ACTION_WALLPAPER) { + chatAdapter.notifyItemChanged(chatAdapter.messagesStartRow + i); + } break; } } @@ -21448,7 +21523,7 @@ private void saveScrollPosition() { if (scrollToMessageObject != null) { int scrollToIndex = messages.indexOf(scrollToMessageObject); if (scrollToIndex > 0) { - chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); +// chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top); } } } @@ -21466,6 +21541,7 @@ private int getSponsoredMessagesCount() { 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) { @@ -21566,6 +21642,10 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, lo 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()); @@ -21681,7 +21761,8 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, lo 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); @@ -22047,7 +22128,7 @@ public void onBecomeFullyVisible() { @Override public void onBecomeFullyHidden() { - if (!getMessagesController().premiumLocked && !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))) { @@ -22479,7 +22560,6 @@ private void updateBottomOverlay() { if (bottomOverlayChatText == null || chatMode == MODE_SCHEDULED || getContext() == null) { return; } - boolean haveBeenWaiting = bottomOverlayChatWaitsReply; bottomOverlayChatWaitsReply = false; if (reportType >= 0) { updateActionModeTitle(); @@ -22525,7 +22605,7 @@ private void updateBottomOverlay() { } showBottomOverlayProgress(false, false); } - } else if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting)) { + } else if (shouldDisplaySwipeToLeftToReplyInForum()) { bottomOverlayChatWaitsReply = true; showBottomOverlayProgress(false, false); bottomOverlayChatText.setTextInfo(LocaleController.getString("ForumReplyToMessagesInTopic", R.string.ForumReplyToMessagesInTopic)); @@ -22548,7 +22628,7 @@ private void updateBottomOverlay() { } showBottomOverlayProgress(false, false); } - } else if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting)) { + } else if (shouldDisplaySwipeToLeftToReplyInForum()) { bottomOverlayChatWaitsReply = true; showBottomOverlayProgress(false, false); bottomOverlayChatText.setTextInfo(LocaleController.getString("ForumReplyToMessagesInTopic", R.string.ForumReplyToMessagesInTopic)); @@ -22730,7 +22810,7 @@ public void onAnimationEnd(Animator animation) { bottomOverlayChat.setVisibility(View.VISIBLE); chatActivityEnterView.setVisibility(View.INVISIBLE); } else if (chatMode == MODE_PINNED || - currentChat != null && ((ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) && (currentChat.join_to_send || !isThreadChat() || ChatObject.isForum(currentChat)) || forumTopic != null && forumTopic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic) || currentChat.forum && !isTopic && replyingMessageObject == null) || + currentChat != null && ((ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) && (currentChat.join_to_send || !isThreadChat() || ChatObject.isForum(currentChat)) || forumTopic != null && forumTopic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic) || shouldDisplaySwipeToLeftToReplyInForum()) || currentUser != null && (UserObject.isDeleted(currentUser) || userBlocked || UserObject.isReplyUser(currentUser))) { if (chatActivityEnterView.isEditingMessage()) { chatActivityEnterView.setVisibility(View.VISIBLE); @@ -22771,20 +22851,6 @@ public void onAnimationEnd(Animator animation) { topViewWasVisible = 0; } } - if (ChatObject.isForum(currentChat) && !isTopic && (replyingMessageObject == null || haveBeenWaiting) && bottomOverlayChatWaitsReply) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, 1); - if (topic != null) { - if (topic.closed && !ChatObject.canManageTopic(currentAccount, currentChat, forumTopic)) { - Drawable lock = getContext().getResources().getDrawable(R.drawable.msg_mini_lock2).mutate(); - lock.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.MULTIPLY)); - bottomOverlayChatText.setTextInfo(lock, LocaleController.getString("TopicClosedByAdmin", R.string.TopicClosedByAdmin)); - bottomOverlayChatText.setEnabled(false); - } else { - bottomOverlayChat.setVisibility(View.INVISIBLE); - chatActivityEnterView.setVisibility(View.VISIBLE); - } - } - } if (sentBotStart) { getMessagesController().sendBotStart(currentUser, botUser); @@ -22795,6 +22861,30 @@ public void onAnimationEnd(Animator animation) { checkRaiseSensors(); } + private boolean shouldDisplaySwipeToLeftToReplyInForum() { + return isForumInViewAsMessagesMode() && replyingMessageObject == null && !canSendMessageToGeneralTopic(); + } + + private boolean canSendMessageToTopic(MessageObject message) { + if (message != null && ChatObject.isForum(currentChat)) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, MessageObject.getTopicId(message.messageOwner, true)); + return canSendMessageToTopic(topic); + } + return false; + } + + private boolean canSendMessageToGeneralTopic() { + if (isForumInViewAsMessagesMode() && currentChat != null) { + TLRPC.TL_forumTopic generalTopic = getMessagesController().getTopicsController().findTopic(currentChat.id, 1); + return canSendMessageToTopic(generalTopic); + } + return false; + } + + private boolean canSendMessageToTopic(TLRPC.TL_forumTopic topic) { + return topic != null && (!topic.closed || ChatObject.canManageTopic(currentAccount, currentChat, topic)); + } + public void updateReplyMessageHeader(boolean notify) { if (avatarContainer != null && threadMessageId != 0) { if (isTopic) { @@ -23864,7 +23954,7 @@ private void updateTopPanel(boolean animated) { 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; @@ -24701,8 +24791,8 @@ public void applyDraftMaybe(boolean canClear) { } TLRPC.DraftMessage draftMessage = null; Integer topicId = null; - if (ChatObject.isForum(currentChat) && !isTopic) { - Pair pair = getMediaDataController().getOneThreadDraft(dialog_id);; + if (isForumInViewAsMessagesMode()) { + Pair pair = getMediaDataController().getOneThreadDraft(dialog_id); if (pair != null) { topicId = pair.first; draftMessage = pair.second; @@ -24790,29 +24880,29 @@ public void applyDraftMaybe(boolean canClear) { }, 700); } } - } /*else if (canClear && draftMessage == null) { - chatActivityEnterView.setFieldText(""); - hideFieldPanel(true); - }*/ - if ((replyingMessageObject == null || threadMessageObject == replyingMessageObject) && draftReplyMessage != null && !(threadMessageObject != null && threadMessageObject.getId() == draftReplyMessage.id)) { - replyingMessageObject = new MessageObject(currentAccount, draftReplyMessage, getMessagesController().getUsers(), false, false); - if (draftMessage.reply_to != null && (draftMessage.reply_to.flags & 4) != 0) { - replyingQuote = ReplyQuote.from(replyingMessageObject, draftMessage.reply_to.quote_text); - } - checkNewMessagesOnQuoteEdit(false); - if (replyingQuote != null) { - showFieldPanelForReplyQuote(replyingMessageObject, replyingQuote); - } else { - showFieldPanelForReply(replyingMessageObject); - } - updateBottomOverlay(); - } else if (topicId != null && topicId != 0 && currentChat != null) { - TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); - if (topic != null && topic.topicStartMessage != null) { - replyingMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, getMessagesController().getUsers(), false, false); - replyingMessageObject.replyToForumTopic = topic; - showFieldPanelForReply(replyingMessageObject); + } + if (replyingMessageObject == null || threadMessageObject == replyingMessageObject) { + if (draftReplyMessage != null && !(threadMessageObject != null && threadMessageObject.getId() == draftReplyMessage.id)) { + replyingMessageObject = new MessageObject(currentAccount, draftReplyMessage, getMessagesController().getUsers(), false, false); + if (draftMessage.reply_to != null && (draftMessage.reply_to.flags & 4) != 0) { + replyingQuote = ReplyQuote.from(replyingMessageObject, draftMessage.reply_to.quote_text, (draftMessage.reply_to.flags & 16) != 0 ? draftMessage.reply_to.quote_offset : -1); + } + checkNewMessagesOnQuoteEdit(false); + if (replyingQuote != null) { + showFieldPanelForReplyQuote(replyingMessageObject, replyingQuote); + } else { + showFieldPanelForReply(replyingMessageObject); + } updateBottomOverlay(); + } else if (topicId != null && topicId != 0 && currentChat != null) { + // user created a draft in topic + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null && topic.topicStartMessage != null) { + replyingMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, getMessagesController().getUsers(), false, false); + replyingMessageObject.replyToForumTopic = topic; + showFieldPanelForReply(replyingMessageObject); + updateBottomOverlay(); + } } } } @@ -25183,11 +25273,15 @@ private boolean createMenu(View v, boolean single, boolean listView, float x, fl } final int type = getMessageType(message); if (single) { - if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + boolean isGiveawayResultsMessage = false; + if (message.messageOwner.action instanceof TLRPC.TL_messageActionGiveawayResults) { + isGiveawayResultsMessage = true; + } + if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || isGiveawayResultsMessage) { if (message.getReplyMsgId() != 0) { - scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, message.getDialogId() == mergeDialogId ? 1 : 0, false, 0); + AndroidUtilities.runOnUIThread(() -> scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, message.getDialogId() == mergeDialogId ? 1 : 0, false, 0)); } else { - Toast.makeText(getParentActivity(), LocaleController.getString("MessageNotFound", R.string.MessageNotFound), Toast.LENGTH_SHORT).show(); + BulletinFactory.of(this).createErrorBulletin(LocaleController.getString("MessageNotFound", R.string.MessageNotFound), themeDelegate).show(); } return true; } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent && message.replyMessageObject != null && message.replyMessageObject.isInvoice()) { @@ -25228,7 +25322,9 @@ private boolean createMenu(View v, boolean single, boolean listView, float x, fl return true; } } else if (message.messageOwner.action instanceof TLRPC.TL_messageActionSetChatTheme) { - showChatThemeBottomSheet(); + if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { + showChatThemeBottomSheet(); + } return true; } } @@ -25316,7 +25412,7 @@ private boolean createMenu(View v, boolean single, boolean listView, float x, fl 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); @@ -25390,7 +25486,7 @@ public void setAutoDeleteHistory(int time, int action) { 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); @@ -26147,7 +26243,7 @@ public void setAutoDeleteHistory(int time, int action) { isReactionsAvailable = nekoXShowReactionsView && !message.isSecretMedia() && !isSecretChat() && !isInScheduleMode() && message.isReactionsAvailable() && (chatInfo != null && !(chatInfo.available_reactions instanceof TLRPC.TL_chatReactionsNone) || (chatInfo == null && !ChatObject.isChannel(currentChat)) || currentUser != null) && !availableReacts.isEmpty(); } boolean showMessageSeen = !isReactionsViewAvailable && !isInScheduleMode() && currentChat != null && message.isOutOwner() && message.isSent() && !message.isEditing() && !message.isSending() && !message.isSendError() && !message.isContentUnread() && !message.isUnread() && (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - message.messageOwner.date < getMessagesController().chatReadMarkExpirePeriod) && (ChatObject.isMegagroup(currentChat) || !ChatObject.isChannel(currentChat)) && chatInfo != null && chatInfo.participants_count <= getMessagesController().chatReadMarkSizeThreshold && !(message.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByRequest) && (v instanceof ChatMessageCell); - boolean showSponsorInfo = selectedObject != null && selectedObject.isSponsored() && (selectedObject.sponsoredInfo != null || selectedObject.sponsoredAdditionalInfo != null || selectedObject.sponsoredWebPage != null || selectedObject.sponsoredWebPage != null); + boolean showSponsorInfo = selectedObject != null && selectedObject.isSponsored() && (selectedObject.sponsoredInfo != null || selectedObject.sponsoredAdditionalInfo != null || selectedObject.sponsoredWebPage != null || selectedObject.sponsoredBotApp != null); int flags = 0; if (isReactionsViewAvailable || showMessageSeen || showSponsorInfo) { @@ -26964,7 +27060,7 @@ public void onSwipeBackProgress(PopupSwipeBackLayout layout, float toProgress, f } } - 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)); @@ -27115,6 +27211,9 @@ public void dismiss(boolean animated) { if (chatActivityEnterView != null && (chatActivityEnterView.isRecordingAudioVideo() || chatActivityEnterView.isRecordLocked())) { return false; } + if (message != null && message.type == MessageObject.TYPE_JOINED_CHANNEL) { + return false; + } createActionMode(); final ActionBarMenu actionMode = actionBar.createActionMode(); @@ -27303,12 +27402,39 @@ private void closeMenu(boolean hideDim) { Runnable updateReactionRunnable; + private void showMultipleReactionsPromo(ChatMessageCell cell, ReactionsLayoutInBubble.VisibleReaction visibleReaction, int currentChosenReactions) { + if (SharedConfig.multipleReactionsPromoShowed || cell == null || cell.getMessageObject() == null || visibleReaction == null || getUserConfig().isPremium()) { + return; + } + if (currentChosenReactions == 1) { + SharedConfig.setMultipleReactionsPromoShowed(true); + TLRPC.Document document; + if (visibleReaction.documentId == 0) { + TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); + if (availableReaction == null) { + return; + } + document = availableReaction.center_icon; + } else { + document = AnimatedEmojiDrawable.findDocument(currentAccount, visibleReaction.documentId); + } + if (document == null) { + return; + } + BulletinFactory.of(ChatActivity.this).createEmojiBulletin( + document, + LocaleController.getString(R.string.ChatMultipleReactionsPromo) + ).setDuration(Bulletin.DURATION_PROLONG).show(); + } + } + public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { if (isInScheduleMode() || primaryMessage == null) { return; } ReactionsEffectOverlay.removeCurrent(false); + int currentChosenReactions = primaryMessage.getChoosenReactions().size(); boolean added = primaryMessage.selectReaction(visibleReaction, bigEmoji, fromDoubleTap); int messageIdForCell = primaryMessage.getId(); if (groupedMessagesMap.get(primaryMessage.getGroupId()) != null) { @@ -27321,9 +27447,12 @@ public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayou int finalMessageIdForCell = messageIdForCell; - if (added && !fromDoubleTap) { + if (added) { ChatMessageCell cell = findMessageCell(finalMessageIdForCell, true); - ReactionsEffectOverlay.show(ChatActivity.this, reactionsLayout, cell, fromView, x, y, visibleReaction, currentAccount, reactionsLayout != null ? (bigEmoji ? ReactionsEffectOverlay.LONG_ANIMATION : ReactionsEffectOverlay.ONLY_MOVE_ANIMATION) : ReactionsEffectOverlay.SHORT_ANIMATION); + showMultipleReactionsPromo(cell, visibleReaction, currentChosenReactions); + if (!fromDoubleTap) { + ReactionsEffectOverlay.show(ChatActivity.this, reactionsLayout, cell, fromView, x, y, visibleReaction, currentAccount, reactionsLayout != null ? (bigEmoji ? ReactionsEffectOverlay.LONG_ANIMATION : ReactionsEffectOverlay.ONLY_MOVE_ANIMATION) : ReactionsEffectOverlay.SHORT_ANIMATION); + } } if (added) { if (visibleReaction.emojicon != null) { @@ -28666,7 +28795,10 @@ public boolean checkRecordLocked(boolean forceCloseOnDiscard) { @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; @@ -28761,9 +28893,10 @@ public void setHighlightMessageId(int id) { highlightMessageId = id; } - public void setHighlightQuote(int id, String quote) { + public void setHighlightQuote(int id, String quote, int quote_offset) { highlightMessageId = id; highlightMessageQuote = quote; + highlightMessageQuoteOffset = quote_offset; showNoQuoteAlert = true; } @@ -28846,7 +28979,7 @@ private void updateVisibleRows(boolean suppressUpdateMessageObject) { startMessageUnselect(); } if (cell.isHighlighted() && highlightMessageQuote != null) { - if (!cell.setHighlightedText(highlightMessageQuote, true) && showNoQuoteAlert) { + if (!cell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset) && showNoQuoteAlert) { showNoQuoteFound(); } showNoQuoteAlert = false; @@ -28904,7 +29037,7 @@ private ArrayList createVoiceMessagesPlaylist(MessageObject start 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); } } @@ -30316,14 +30449,24 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { ((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); } @@ -30348,7 +30491,6 @@ public void end(boolean replaced) { } } }; - GiftInfoBottomSheet.show(getBaseFragment(), slug, progressDialogCurrent); } @Override @@ -30356,6 +30498,28 @@ public void needShowEffectOverlay(ChatActionCell cell, TLRPC.Document document, emojiAnimationsOverlay.showAnimationForActionCell(cell, document, videoSize); } + @Override + public void didClickButton(ChatActionCell cell) { + if (cell == null) return; + MessageObject message = cell.getMessageObject(); + if (message == null) return; + if (message.type == MessageObject.TYPE_ACTION_WALLPAPER && !cell.getMessageObject().isOutOwner() && cell.getMessageObject().isWallpaperForBoth() && cell.getMessageObject().isCurrentWallpaper()) { + AlertDialog d = new AlertDialog.Builder(getContext(), getResourceProvider()) + .setTitle(LocaleController.getString(R.string.RemoveWallpaperTitle)) + .setMessage(LocaleController.getString(R.string.RemoveWallpaperMessage)) + .setPositiveButton(LocaleController.getString(R.string.Remove), (w, di) -> { + ChatThemeController.getInstance(currentAccount).clearWallpaper(dialog_id, true, true); + }) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .create(); + showDialog(d); + TextView button = (TextView) d.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(getThemedColor(Theme.key_text_RedBold)); + } + } + } + @Override public void didClickImage(ChatActionCell cell) { MessageObject message = cell.getMessageObject(); @@ -30368,16 +30532,15 @@ public void didClickImage(ChatActionCell cell) { return; } if (cell.getMessageObject().type == MessageObject.TYPE_ACTION_WALLPAPER) { - MessagesController messagesController = MessagesController.getInstance(currentAccount); - if (message.getId() < 0 && messagesController.uploadingWallpaper != null && TextUtils.equals(message.messageOwner.action.wallpaper.uploadingImage, messagesController.uploadingWallpaper)) { + if (cell.showingCancelButton() && message.getId() < 0 && messagesController.uploadingWallpaper != null && TextUtils.equals(message.messageOwner.action.wallpaper.uploadingImage, messagesController.uploadingWallpaper)) { messagesController.cancelUploadWallpaper(); removeMessageObject(message); return; } if (cell.hasButton()) { ThemePreviewActivity.showFor(ChatActivity.this, message); - } else { + } else if (currentChat == null || ChatObject.canChangeChatInfo(currentChat)) { showChatThemeBottomSheet(); } return; @@ -30688,9 +30851,16 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (currentChat != null) { long fromId = prevMessage.getFromChatId(); pinnedTop = fromId == message.getFromChatId() && !message.isImportedForward() && !prevMessage.isImportedForward(); -// if (!pinnedTopByGroup && pinnedTop && fromId < 0 && currentChat.megagroup) { -// pinnedTop = false; -// } + if (!pinnedTopByGroup && pinnedTop && fromId < 0 && currentChat.megagroup) { + pinnedTop = false; + } + if (pinnedTop && isForumInViewAsMessagesMode()) { + int topicId = message.replyToForumTopic == null ? MessageObject.getTopicId(message.messageOwner, true) : message.replyToForumTopic.id; + int prevTopicId = prevMessage.replyToForumTopic == null ? MessageObject.getTopicId(prevMessage.messageOwner, true) : prevMessage.replyToForumTopic.id; + if (topicId != prevTopicId) { + pinnedTop = false; + } + } } else if (UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser)) { if (message.isPrivateForward() || prevMessage.isPrivateForward()) { pinnedTop = false; @@ -30719,7 +30889,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { messageCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); if (messageCell.isHighlighted() && highlightMessageQuote != null) { - messageCell.setHighlightedText(highlightMessageQuote, true); + messageCell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset); } if (highlightMessageId != Integer.MAX_VALUE) { startMessageUnselect(); @@ -31045,7 +31215,7 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { if (!inPreviewMode || !messageCell.isHighlighted()) { messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && (messageCell.getMessageObject().getId() == highlightMessageId || messageCell.getCurrentMessagesGroup() != null && messageCell.getCurrentMessagesGroup().contains(highlightMessageId))); if (messageCell.isHighlighted() && highlightMessageQuote != null) { - if (!messageCell.setHighlightedText(highlightMessageQuote, true) && showNoQuoteAlert) { + if (!messageCell.setHighlightedText(highlightMessageQuote, true, highlightMessageQuoteOffset) && showNoQuoteAlert) { showNoQuoteFound(); } showNoQuoteAlert = false; @@ -31331,6 +31501,26 @@ public void notifyItemRemoved(int position) { } } + 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) { @@ -31626,7 +31816,9 @@ public void didPressSideButton(ChatMessageCell cell) { arrayList = new ArrayList<>(); arrayList.add(messageObject); } - showDialog(new ShareAlert(getContext(), ChatActivity.this, arrayList, null, null, ChatObject.isChannel(currentChat), null, null, false, false, themeDelegate) { + 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(); @@ -31636,6 +31828,50 @@ public void dismissInternal() { } } + @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(); @@ -31655,8 +31891,30 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } @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; @@ -31732,10 +31990,7 @@ public void didPressUserStatus(ChatMessageCell cell, TLRPC.User user, TLRPC.Docu premiumPreviewBottomSheet.startEnterFromX1 = cell.getLeft(); premiumPreviewBottomSheet.startEnterFromY1 = cell.getTop(); premiumPreviewBottomSheet.startEnterFromView = cell; - int colorId = user != null ? (int) (user.id % 7) : 0; - if (user != null && (user.flags2 & 128) != 0) { - colorId = user.color; - } + int colorId = UserObject.getColorId(user); if (colorId < 7) { premiumPreviewBottomSheet.accentColor = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]); } else { @@ -31990,6 +32245,37 @@ public void needShowPremiumBulletin(int type) { if (!NekoConfig.disableVibration.Bool()) topUndoView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignored) {} + } else if (type == 1) { + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + CharSequence text = getMessagesController().transcribeAudioTrialCooldownUntil > 0 ? + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeftUntil", TranscribeButton.getTranscribeTrialCount(currentAccount), until)) : + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialLeft", TranscribeButton.getTranscribeTrialCount(currentAccount))); + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.transcribe, text, 6).show(true); + try { + fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) {} + } else if (type == 2 || type == 3) { + String until = LocaleController.formatDateTime(getMessagesController().transcribeAudioTrialCooldownUntil); + BulletinFactory.of(ChatActivity.this).createSimpleBulletin( + R.raw.transcribe, + new SpannableStringBuilder().append( + AndroidUtilities.replaceTags(LocaleController.formatPluralString("TranscriptionTrialEnd", getMessagesController().transcribeAudioTrialWeeklyNumber)) + ).append(" ").append( + type == 2 ? + AndroidUtilities.replaceSingleTag(LocaleController.getString(R.string.TranscriptionTrialEndBuy), () -> { + new PremiumFeatureBottomSheet(ChatActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT, true).show(); + getMessagesController().pressTranscribeButton(); + }) : + getMessagesController().transcribeAudioTrialCooldownUntil <= 0 ? "" : + AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TranscriptionTrialEndWaitOrBuy, until), () -> { + new PremiumFeatureBottomSheet(ChatActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT, true).show(); + getMessagesController().pressTranscribeButton(); + }) + ), + 6, + 7000 + ).show(true); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); } } @@ -32281,9 +32567,83 @@ public void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBlock BulletinFactory.of(ChatActivity.this).createCopyBulletin(LocaleController.getString(R.string.CodeCopied)).show(); } + @Override + public void didPressMoreChannelRecommendations(ChatMessageCell cell) { + if (getUserConfig().isPremium()) { + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + args.putInt("start_from", SharedMediaLayout.TAB_RECOMMENDED_CHANNELS); + presentFragment(new MediaActivity(args, avatarContainer.getSharedMediaPreloader())); + } else { + BulletinFactory.of(ChatActivity.this).createSimpleBulletin( + R.raw.star_premium_2, + AndroidUtilities.replaceSingleTag(LocaleController.formatPluralStringComma("UnlockSimilarChannelsPremium", getMessagesController().recommendedChannelsLimitPremium), () -> { + presentFragment(new PremiumPreviewFragment("similar_channels")); + }) + ).show(); + } + } + + @Override + public void didPressChannelRecommendation(ChatMessageCell cell, TLRPC.Chat chat, boolean longPress) { + if (chat == null || parentLayout != null && parentLayout.isInPreviewMode()) { + return; + } + Bundle args = new Bundle(); + args.putLong("chat_id", chat.id); + if (longPress) { + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getParentActivity(), R.drawable.popup_fixed_alert, getResourceProvider(), ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_SHOWN_FROM_BOTTOM); + previewMenu.setBackgroundColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + + ActionBarMenuSubItem openChannel = new ActionBarMenuSubItem(getParentActivity(), false, false); + openChannel.setTextAndIcon(LocaleController.getString(R.string.OpenChannel2), R.drawable.msg_channel); + openChannel.setMinimumWidth(160); + openChannel.setOnClickListener(view -> { + if (parentLayout != null) { + parentLayout.expandPreviewFragment(); + } + }); + previewMenu.addView(openChannel); + + ActionBarMenuSubItem joinChannel = new ActionBarMenuSubItem(getParentActivity(), false, false); + joinChannel.setTextAndIcon(LocaleController.getString(R.string.ProfileJoinChannel), R.drawable.msg_addbot); + joinChannel.setMinimumWidth(160); + joinChannel.setOnClickListener(view -> { + finishPreviewFragment(); + chat.left = false; + if (cell != null && cell.channelRecommendationsCell != null) { + getNotificationCenter().postNotificationName(NotificationCenter.channelRecommendationsLoaded, cell.channelRecommendationsCell.chatId); + } + getMessagesController().addUserToChat(chat.id, getUserConfig().getCurrentUser(), 0, null, ChatActivity.this, () -> { + BulletinFactory.of(ChatActivity.this).createSimpleBulletin(R.raw.contact_check, LocaleController.formatString(R.string.YouJoinedChannel, chat == null ? "" : chat.title)).show(true); + }); + }); + previewMenu.addView(joinChannel); + + ChatActivity chatActivity = new ChatActivity(args); + chatActivity.allowExpandPreviewByClick = true; + presentFragmentAsPreviewWithMenu(chatActivity, previewMenu); + checkShowBlur(true); + } else { + presentFragment(new ChatActivity(args)); + } + } + + @Override + public void didPressChannelRecommendationsClose(ChatMessageCell cell) { + MessageObject msg = cell.getMessageObject(); + if (msg != null && msg.type == MessageObject.TYPE_JOINED_CHANNEL) { + msg.toggleChannelRecommendations(); + msg.forceUpdate = true; + cell.forceResetMessageObject(); + cell.requestLayout(); + chatAdapter.updateRowWithMessageObject(msg, false, false); + } + } + @Override public boolean didPressAnimatedEmoji(ChatMessageCell cell, AnimatedEmojiSpan span) { - if (getMessagesController().premiumLocked || span == null || span.standard) { + if (getMessagesController().premiumFeaturesBlocked() || span == null || span.standard) { return false; } long documentId = span.getDocumentId(); @@ -32347,6 +32707,9 @@ public void didPressWebPage(ChatMessageCell cell, TLRPC.WebPage webpage, String if (uri == null) { return; } + if (!safe && Browser.isTelegraphUrl(url, false)) { + safe = true; + } if (progressDialogCurrent != null) { progressDialogCurrent.cancel(true); } @@ -32396,8 +32759,12 @@ public void didPressReplyMessage(ChatMessageCell cell, int id) { finishFragment(); } else { String quote = null; + int quoteOffset = -1; if (messageObject.messageOwner != null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.quote) { quote = messageObject.messageOwner.reply_to.quote_text; + if ((messageObject.messageOwner.reply_to.flags & 1024) != 0) { + quoteOffset = messageObject.messageOwner.reply_to.quote_offset; + } } long did = dialog_id; boolean couldBeDifferentTopic = false; @@ -32472,11 +32839,12 @@ public void end(boolean replaced) { AndroidUtilities.runOnUIThread(ChatActivity.this::resetProgressDialogLoading, 250); } } - }, messageObject.getId()); + }, messageObject.getId(), quoteOffset); } } else { if (messageObject.messageOwner != null && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.quote) { highlightMessageQuote = messageObject.messageOwner.reply_to.quote_text; + highlightMessageQuoteOffset = quoteOffset; showNoQuoteAlert = true; } scrollToMessageId(id, messageObject.getId(), true, messageObject.getDialogId() == mergeDialogId ? 1 : 0, true, 0, () -> { @@ -32785,7 +33153,49 @@ public void end(boolean replaced) { if (messageObject.isSponsored()) { logSponsoredClicked(messageObject); Bundle args = new Bundle(); - if (messageObject.sponsoredWebPage != null) { + if (messageObject.sponsoredBotApp != null) { + TLRPC.TL_messages_getBotApp getBotApp = new TLRPC.TL_messages_getBotApp(); + TLRPC.TL_inputBotAppShortName app = new TLRPC.TL_inputBotAppShortName(); + if (messageObject.messageOwner == null || messageObject.messageOwner.from_id == null) { + return; + } + TLRPC.User bot = MessagesController.getInstance(currentAccount).getUser(messageObject.messageOwner.from_id.user_id); + if (bot == null) { + return; + } + app.bot_id = MessagesController.getInstance(currentAccount).getInputUser(bot); + app.short_name = messageObject.sponsoredBotApp.short_name; + getBotApp.app = app; + ConnectionsManager.getInstance(currentAccount).sendRequest(getBotApp, (response1, error1) -> { +// if (progress != null) { +// progress.end(); +// } + if (error1 != null) { + BulletinFactory.of(ChatActivity.this).createErrorBulletin(LocaleController.getString(R.string.UnknownError)).show(true); + } else { + TLRPC.TL_messages_botApp botApp = (TLRPC.TL_messages_botApp) response1; + AndroidUtilities.runOnUIThread(() -> { +// dismissLoading.run(); + AtomicBoolean allowWrite = new AtomicBoolean(); + Runnable loadBotSheet = () -> { + BotWebViewSheet sheet = new BotWebViewSheet(getContext(), getResourceProvider()); + sheet.setParentActivity(getParentActivity()); + sheet.requestWebView(currentAccount, bot.id, bot.id, null, null, BotWebViewSheet.TYPE_WEB_VIEW_BOT_APP, 0, false, ChatActivity.this, botApp.app, allowWrite.get(), messageObject.botStartParam, bot); + showDialog(sheet); + if (botApp.inactive) { + sheet.showJustAddedBulletin(); + } + }; + + if (botApp.request_write_access) { + AlertsCreator.createBotLaunchAlert(ChatActivity.this, allowWrite, bot, loadBotSheet); + } else { + loadBotSheet.run(); + } + }); + } + }); + } else if (messageObject.sponsoredWebPage != null) { Browser.openUrl(getContext(), messageObject.sponsoredWebPage.url, true, false); } else if (messageObject.sponsoredChatInvite != null) { showDialog(new JoinGroupAlert(getContext(), messageObject.sponsoredChatInvite, messageObject.sponsoredChatInviteHash, ChatActivity.this, themeDelegate)); @@ -32860,14 +33270,21 @@ public void end(boolean replaced) { @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)); } } @@ -33396,7 +33813,7 @@ public ArrayList getThemeDescriptions() { } 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)); @@ -33570,7 +33987,7 @@ public ArrayList getThemeDescriptions() { 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)); @@ -34182,6 +34599,10 @@ private void setTransitionToChatProgress(float p) { } 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); @@ -34211,9 +34632,9 @@ private void checkThemeEmoticonOrWallpaper() { 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); }); } @@ -34229,13 +34650,7 @@ private void setChatThemeEmoticon(final String emoticon) { 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); } @@ -34295,7 +34710,7 @@ public class ThemeDelegate implements Theme.ResourcesProvider, ChatActionCell.Th 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) { @@ -34409,8 +34824,11 @@ public Paint getPaint(String paintKey) { 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() { @@ -34439,7 +34857,7 @@ public void setCurrentTheme(final EmojiThemes chatTheme, TLRPC.WallPaper newWall 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; } @@ -34458,7 +34876,7 @@ public void setCurrentTheme(final EmojiThemes chatTheme, TLRPC.WallPaper newWall startServiceIconColor = drawServiceGradient ? 0xffffffff : Theme.getColor(Theme.key_chat_serviceIcon); } else if (drawServiceGradient && backgroundDrawable instanceof MotionBackgroundDrawable) { startServiceBitmap = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); - } else if (backgroundDrawable != null){ + } else if (backgroundDrawable != null) { initServiceMessageColors(backgroundDrawable); } startServiceColor = currentServiceColor; @@ -34475,6 +34893,8 @@ public void setCurrentTheme(final EmojiThemes chatTheme, TLRPC.WallPaper newWall } animationSettings.applyTheme = false; + if (dialog_id < 0) + animationSettings.applyTrulyTheme = false; animationSettings.afterStartDescriptionsAddedRunnable = () -> { setupChatTheme(chatTheme, newWallpaper, animated, true); initServiceMessageColors(backgroundDrawable); @@ -34574,7 +34994,9 @@ private void setupChatTheme(EmojiThemes chatTheme, TLRPC.WallPaper wallPaper, bo } 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); @@ -34616,7 +35038,7 @@ public void onAnimationEnd(Animator animation) { patternAlphaAnimator.start(); } - if (chatTheme == null) { + if (chatTheme == null && dialog_id >= 0) { Theme.ThemeInfo activeTheme; if (Theme.getActiveTheme().isDark() == isDark) { activeTheme = Theme.getActiveTheme(); @@ -34713,7 +35135,7 @@ private void initPaints() { } int colorKey = Theme.getThemePaintColorKey(entry.getKey()); - if (colorKey >= 0) { + if (colorKey >= 0 && !Theme.key_paint_chatActionBackgroundDarken.equals(entry.getKey())) { newPaint.setColor(getColor(colorKey)); } currentPaints.put(entry.getKey(), newPaint); @@ -34732,6 +35154,8 @@ private void initPaints() { boolean drawServiceGradient; boolean drawSelectedGradient; + final Rect src = new Rect(), dst = new Rect(); + private void initServiceMessageColors(Drawable backgroundDrawable) { int[] result = AndroidUtilities.calcDrawableColor(backgroundDrawable); int currentServiceMessageColor = result[0]; @@ -34744,20 +35168,56 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { } currentServiceColor = serviceColor; + float dimAmount = 0; if (backgroundDrawable instanceof ChatBackgroundDrawable) { - backgroundDrawable = ((ChatBackgroundDrawable) backgroundDrawable).getDrawable(); + dimAmount = ((ChatBackgroundDrawable) backgroundDrawable).getDimAmount(); + backgroundDrawable = ((ChatBackgroundDrawable) backgroundDrawable).getDrawable(false); } - drawServiceGradient = backgroundDrawable instanceof MotionBackgroundDrawable && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW; + drawServiceGradient = (backgroundDrawable instanceof MotionBackgroundDrawable || backgroundDrawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW; drawSelectedGradient = drawServiceGradient; if (drawServiceGradient) { - serviceBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); - serviceBitmapSource = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); - serviceCanvas = new Canvas(serviceBitmap); - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, null); - serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - useSourceShader = true; + if (backgroundDrawable instanceof BitmapDrawable) { + Bitmap source = ((BitmapDrawable) backgroundDrawable).getBitmap(); + int w, h; + if (source.getWidth() > source.getHeight()) { + w = 40; + h = (int) ((float) w / source.getWidth() * source.getHeight()); + } else { + h = 40; + w = (int) ((float) h / source.getHeight() * source.getWidth()); + } + serviceBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + serviceCanvas = new Canvas(serviceBitmap); + src.set(0, 0, source.getWidth(), source.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(source, src, dst, null); + Utilities.blurBitmap(serviceBitmap, 3, 1, serviceBitmap.getWidth(), serviceBitmap.getHeight(), serviceBitmap.getRowBytes()); + serviceCanvas.drawColor(ColorUtils.setAlphaComponent(0xff000000, (int) (0xFF * dimAmount))); + serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + serviceBitmapSource = Bitmap.createBitmap(serviceBitmap); + serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + serviceShaderSource.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } + useSourceShader = true; + } else { + serviceBitmap = Bitmap.createBitmap(60, 80, Bitmap.Config.ARGB_8888); + serviceBitmapSource = ((MotionBackgroundDrawable) backgroundDrawable).getBitmap(); + serviceCanvas = new Canvas(serviceBitmap); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, null); + serviceCanvas.drawColor(ColorUtils.setAlphaComponent(0xff000000, (int) (0xFF * dimAmount))); + serviceShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + serviceShaderSource = new BitmapShader(serviceBitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + serviceShader.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + serviceShaderSource.setFilterMode(BitmapShader.FILTER_MODE_LINEAR); + } + useSourceShader = true; + } } else { serviceBitmap = null; serviceShader = null; @@ -34771,22 +35231,49 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { Paint msgBackgroundSelectedPaint = getPaint(Theme.key_paint_chatMessageBackgroundSelected); if (actionBackgroundPaint != null) { + Paint darkenPaint = currentPaints.get(Theme.key_paint_chatActionBackgroundDarken); + if (darkenPaint == null) { + currentPaints.put(Theme.key_paint_chatActionBackgroundDarken, darkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG)); + darkenPaint.setColor(0); + } if (drawServiceGradient) { ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(((MotionBackgroundDrawable) backgroundDrawable).getIntensity() >= 0 ? 1.8f : 0.5f); + if (backgroundDrawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) backgroundDrawable).getIntensity(); + if (intensity >= 0) { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .97f : .92f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.12f : -.06f); + } else { + colorMatrix.setSaturation(1.1f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .4f : .8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.08f : -.06f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, isDark ? .9f : .84f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, isDark ? +.04f : +.06f); + } - actionBackgroundPaint.setAlpha(127); + actionBackgroundPaint.setAlpha(0xff); actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); actionBackgroundPaint.setShader(serviceShaderSource); + actionBackgroundPaint.setFilterBitmap(true); - actionBackgroundSelectedPaint.setAlpha(127); + actionBackgroundSelectedPaint.setAlpha(0xFF); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.26f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .92f); actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); actionBackgroundSelectedPaint.setShader(serviceShaderSource); + actionBackgroundSelectedPaint.setFilterBitmap(true); + darkenPaint.setAlpha(0); } else { actionBackgroundPaint.setColorFilter(null); actionBackgroundPaint.setShader(null); actionBackgroundSelectedPaint.setColorFilter(null); actionBackgroundSelectedPaint.setShader(null); + darkenPaint.setAlpha(0x15); } } @@ -34801,6 +35288,7 @@ private void initServiceMessageColors(Drawable backgroundDrawable) { msgBackgroundSelectedPaint.setAlpha(64); msgBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix2)); msgBackgroundSelectedPaint.setShader(serviceShaderSource); + msgBackgroundSelectedPaint.setFilterBitmap(true); } else { if (selectedBackgroundColor == 0) { selectedBackgroundColor = getColor(Theme.key_chat_selectedBackground); @@ -34863,9 +35351,13 @@ private void updateServiceMessageColor(float progress) { if (serviceCanvas != null && serviceBitmapSource != null) { if (progress != 1f && startServiceBitmap != null) { useSourceShader = false; - serviceCanvas.drawBitmap(startServiceBitmap, 0, 0, null); + src.set(0, 0, startServiceBitmap.getWidth(), startServiceBitmap.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(startServiceBitmap, src, dst, null); paint.setAlpha((int) (255 * progress)); - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, paint); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, paint); if (actionBackgroundPaint != null) { actionBackgroundPaint.setShader(serviceShader); actionBackgroundSelectedPaint.setShader(serviceShader); @@ -34875,7 +35367,9 @@ private void updateServiceMessageColor(float progress) { } } else { useSourceShader = true; - serviceCanvas.drawBitmap(serviceBitmapSource, 0, 0, null); + src.set(0, 0, serviceBitmapSource.getWidth(), serviceBitmapSource.getHeight()); + dst.set(0, 0, serviceBitmap.getWidth(), serviceBitmap.getHeight()); + serviceCanvas.drawBitmap(serviceBitmapSource, src, dst, null); if (actionBackgroundPaint != null) { actionBackgroundPaint.setShader(serviceShaderSource); actionBackgroundSelectedPaint.setShader(serviceShaderSource); @@ -34893,7 +35387,7 @@ private Drawable getBackgroundDrawableFromTheme(EmojiThemes chatTheme, int prevP Theme.ThemeInfo themeInfo = EmojiThemes.getDefaultThemeInfo(isDark); SparseIntArray currentColors = chatTheme.getPreviewColors(currentAccount, isDark ? 1 : 0); String wallpaperLink = chatTheme.getWallpaperLink(isDark ? 1 : 0); - Theme.BackgroundDrawableSettings settings = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink, prevPhase); + Theme.BackgroundDrawableSettings settings = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink, prevPhase, false); drawable = settings.wallpaper; drawable = new ColorDrawable(Color.BLACK); } else { @@ -35768,4 +36262,68 @@ public void updateClip(int[] clip) { clip[1] = chatListView.getMeasuredHeight() - (chatListView.getPaddingBottom() - AndroidUtilities.dp(3)); } } + + private void updateVisibleWallpaperActions() { + if (chatListView != null && chatAdapter != null) { + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + int position = chatListView.getChildAdapterPosition(child) - chatAdapter.messagesStartRow; + if (child instanceof ChatActionCell && position >= 0 && position < messages.size()) { + MessageObject msg = messages.get(position); + if (msg != null && msg.isWallpaperForBoth()) { + ((ChatActionCell) child).setMessageObject(msg, true); + } + } + } + } + } + + private void checkLeaveChannelButton() { + if (headerItem == null) return; + if (!headerItem.hasSubItem(delete_chat)) { + if (!isTopic) { + if (ChatObject.isChannel(currentChat) && !currentChat.creator) { + if (!ChatObject.isNotInChat(currentChat)) { + if (currentChat.megagroup) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("LeaveMegaMenu", R.string.LeaveMegaMenu)); + } else { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("LeaveChannelMenu", R.string.LeaveChannelMenu)); + } + } + } else if (!ChatObject.isChannel(currentChat)) { + if (currentChat != null) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_leave, LocaleController.getString("DeleteAndExit", R.string.DeleteAndExit)); + } else if (currentUser != null && currentUser.bot) { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_block2, LocaleController.getString(R.string.DeleteAndBlock)).setColors(getThemedColor(Theme.key_text_RedRegular), getThemedColor(Theme.key_text_RedRegular)); + } else { + headerItem.lazilyAddSubItem(delete_chat, R.drawable.msg_delete, LocaleController.getString("DeleteChatUser", R.string.DeleteChatUser)); + } + } + } + } + } + + 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 b5371b5aa6..3db6c721e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatBackgroundDrawable.java @@ -138,6 +138,9 @@ public ChatBackgroundDrawable(TLRPC.WallPaper wallPaper, boolean themeIsDark, bo public static Drawable createThumb(TLRPC.WallPaper wallPaper) { Drawable thumb = null; + if (wallPaper.thumbDrawable != null) { + return wallPaper.thumbDrawable; + } if (wallPaper.stripedThumb != null) { return new BitmapDrawable(wallPaper.stripedThumb); } @@ -151,7 +154,7 @@ public static Drawable createThumb(TLRPC.WallPaper wallPaper) { } } } 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 @@ -171,7 +174,7 @@ public static Drawable createThumb(TLRPC.WallPaper wallPaper) { } } } - return thumb; + return wallPaper.thumbDrawable = thumb; } private static Drawable bitmapDrawableOf(Drawable drawable) { @@ -205,6 +208,13 @@ public void draw(@NonNull Canvas canvas) { } } + public float getDimAmount() { + if (motionBackgroundDrawable == null) { + return dimAmount; + } + return 0; + } + @Override public void setAlpha(int alpha) { if (this.alpha != alpha) { @@ -255,16 +265,18 @@ public void onDetachedFromWindow(View view) { } } - public Drawable getDrawable() { + public Drawable getDrawable(boolean prioritizeThumb) { if (motionBackgroundDrawable != null) { return motionBackgroundDrawable; } - if (imageReceiver.getStaticThumb() != null) { + if (prioritizeThumb && imageReceiver.getStaticThumb() != null) { return imageReceiver.getStaticThumb(); } else if (imageReceiver.getThumb() != null) { return imageReceiver.getThumb(); - } else { + } else if (imageReceiver.getDrawable() != null) { return imageReceiver.getDrawable(); + } else { + return imageReceiver.getStaticThumb(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 1d2bd23ed5..9a3f4f9273 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -44,6 +44,7 @@ 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; @@ -74,6 +75,7 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BulletinFactory; @@ -85,6 +87,8 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; +import org.telegram.ui.Components.Reactions.ChatCustomReactionsEditActivity; +import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.UndoView; @@ -181,6 +185,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image private int realAdminCount = 0; private boolean hasUploadedPhoto; + private final List preloadedReactions = new ArrayList<>(); private PhotoViewer.PhotoViewerProvider provider = new PhotoViewer.EmptyPhotoViewerProvider() { @@ -401,6 +406,7 @@ public void onResume() { @Override public void onPause() { super.onPause(); + ReactionsUtils.stopPreloadReactions(preloadedReactions); if (nameTextView != null) { nameTextView.onPause(); } @@ -887,11 +893,15 @@ public void afterTextChanged(Editable editable) { } if (ChatObject.isChannelAndNotMegaGroup(currentChat) && ChatObject.canChangeChatInfo(currentChat)) { - colorCell = new PeerColorActivity.ChangeNameColorCell(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(); }); } @@ -1033,11 +1043,15 @@ public void afterTextChanged(Editable editable) { reactionsCell = new TextCell(context); reactionsCell.setBackground(Theme.getSelectorDrawable(false)); reactionsCell.setOnClickListener(v -> { - Bundle args = new Bundle(); - args.putLong(ChatReactionsEditActivity.KEY_CHAT_ID, chatId); - ChatReactionsEditActivity reactionsEditActivity = new ChatReactionsEditActivity(args); - reactionsEditActivity.setInfo(info); - presentFragment(reactionsEditActivity); + if (ChatObject.isChannelAndNotMegaGroup(currentChat)) { + presentFragment(new ChatCustomReactionsEditActivity(chatId, info)); + } else { + Bundle args = new Bundle(); + args.putLong(ChatReactionsEditActivity.KEY_CHAT_ID, chatId); + ChatReactionsEditActivity reactionsEditActivity = new ChatReactionsEditActivity(args); + reactionsEditActivity.setInfo(info); + presentFragment(reactionsEditActivity); + } }); adminCell = new TextCell(context); @@ -1668,8 +1682,7 @@ private void processDone() { getParentLayout().removeFragmentFromStack(i); Bundle bundle = new Bundle(); bundle.putLong("chat_id",chatId); - TopicsFragment topicsFragment = new TopicsFragment(bundle); - getParentLayout().addFragmentToStack(topicsFragment, i); + getParentLayout().addFragmentToStack(TopicsFragment.getTopicsOrChat(this, bundle), i); } } } @@ -1773,6 +1786,8 @@ public void setInfo(TLRPC.ChatFull chatFull) { } historyHidden = !ChatObject.isChannel(currentChat) || info.hidden_prehistory; availableReactions = info.available_reactions; + preloadedReactions.clear(); + preloadedReactions.addAll(ReactionsUtils.startPreloadReactions(currentChat, info)); } } @@ -1896,9 +1911,6 @@ private void updateFields(boolean updateChat, boolean animated) { if (!currentChat.default_banned_rights.send_plain) { count++; } - if (!currentChat.default_banned_rights.send_gifs) { - count++; - } count += ChatUsersActivity.getSendMediaSelectedCount(currentChat.default_banned_rights); if (!currentChat.default_banned_rights.pin_messages) { count++; @@ -1912,16 +1924,10 @@ private void updateFields(boolean updateChat, boolean animated) { if (!currentChat.default_banned_rights.change_info) { count++; } - if (!currentChat.default_banned_rights.send_games) { - count++; - } - if (!currentChat.default_banned_rights.send_inline) { - count++; - } } else { - count = forum ? 14 : 13; + count = forum ? 17 : 16; } - blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 14 : 13), R.drawable.msg_permissions, true); + blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 17 : 16), R.drawable.msg_permissions, true); } if (memberRequestsCell != null) { memberRequestsCell.setTextAndValueAndIcon(LocaleController.getString("MemberRequests", R.string.MemberRequests), String.format("%d", info.requests_pending), R.drawable.msg_requests, logCell != null && logCell.getVisibility() == View.VISIBLE); @@ -1971,7 +1977,7 @@ private void updateFields(boolean updateChat, boolean animated) { if (logCell != null && !ChatObject.hasAdminRights(currentChat)) logCell.setVisibility(View.GONE); } - 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)); } @@ -2051,6 +2057,7 @@ public void onAnimationEnd(Animator animation) { } private void updateReactionsCell(boolean animated) { + boolean isChannelAndNotMegaGroup = ChatObject.isChannelAndNotMegaGroup(currentChat); String finalString; if (availableReactions == null || availableReactions instanceof TLRPC.TL_chatReactionsNone) { finalString = LocaleController.getString("ReactionsOff", R.string.ReactionsOff); @@ -2065,15 +2072,21 @@ private void updateReactionsCell(boolean animated) { if (reaction != null && !reaction.inactive) { count++; } + } else if (someReaction instanceof TLRPC.TL_reactionCustomEmoji) { + count++; } } - int reacts = Math.min(getMediaDataController().getEnabledReactionsList().size(), count); - finalString = reacts == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : - LocaleController.formatString("ReactionsCount", R.string.ReactionsCount, reacts, getMediaDataController().getEnabledReactionsList().size()); + if (isChannelAndNotMegaGroup) { + finalString = count == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : String.valueOf(count); + } else { + int reacts = Math.min(getMediaDataController().getEnabledReactionsList().size(), count); + finalString = reacts == 0 ? LocaleController.getString("ReactionsOff", R.string.ReactionsOff) : + LocaleController.formatString("ReactionsCount", R.string.ReactionsCount, reacts, getMediaDataController().getEnabledReactionsList().size()); + } } else { finalString = LocaleController.getString("ReactionsAll", R.string.ReactionsAll); } - reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, R.drawable.msg_reactions2, true); + reactionsCell.setTextAndValueAndIcon(LocaleController.getString("Reactions", R.string.Reactions), finalString, animated, R.drawable.msg_reactions2, true); } @Override @@ -2180,6 +2193,12 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(reactionsCell, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(reactionsCell, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); + if (statsAndBoosts != null) { + themeDescriptions.add(new ThemeDescription(statsAndBoosts, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); + themeDescriptions.add(new ThemeDescription(statsAndBoosts, ThemeDescription.FLAG_TEXTCOLOR, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); + themeDescriptions.add(new ThemeDescription(statsAndBoosts, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); + } + return themeDescriptions; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 3ac9ceea3e..4662585748 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -266,6 +266,9 @@ public void onItemClick(int id) { if (id == -1) { finishFragment(); } else if (id == done_button) { + if (doneButtonDrawable != null && doneButtonDrawable.getProgress() > 0) { + return; + } processDone(); } } @@ -686,10 +689,7 @@ public void setInfo(TLRPC.ChatFull chatFull) { 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(); } } @@ -1120,6 +1120,26 @@ protected void dispatchDraw(Canvas canvas) { } } + 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 @@ private boolean trySetUsername() { 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 @@ private boolean tryDeactivateAllLinks() { 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 @@ private boolean tryDeactivateAllLinks() { } deactivatingLinks = false; AndroidUtilities.runOnUIThread(this::processDone); - }); + })); + } else { + deactivatingLinks = false; } return !hasActive; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index c20d987493..ef70073263 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -541,7 +541,7 @@ private void showLinkAlert(TLRPC.Chat chat, boolean query) { frameLayout2.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 21 : 76), 11, (LocaleController.isRTL ? 76 : 21), 0)); frameLayout2.addView(messageTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 24, 57, 24, 9)); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageView.setForUserOrChat(chat, avatarDrawable); builder.setPositiveButton(LocaleController.getString("DiscussionLinkGroup", R.string.DiscussionLinkGroup), (dialogInterface, i) -> { if (chatFull.hidden_prehistory) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java index 44c1e1a180..1e51b4788f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatPullingDownDrawable.java @@ -5,7 +5,6 @@ import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; @@ -14,13 +13,10 @@ import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; -import android.util.Log; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; -import androidx.core.graphics.ColorUtils; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; @@ -132,7 +128,7 @@ public void updateDialog() { MessagesController.getInstance(currentAccount).getChat(dialog.id); } AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setInfo(nextChat); + avatarDrawable.setInfo(currentAccount, nextChat); imageReceiver.setImage(ImageLocation.getForChat(nextChat, ImageLocation.TYPE_SMALL), "50_50", avatarDrawable, null, UserConfig.getInstance(0).getCurrentUser(), 0); MessagesController.getInstance(currentAccount).ensureMessagesLoaded(dialog.id, 0, null); counterDrawable.setCount(dialog.unread_count, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 1e7a95bbe1..09ac6fae30 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -8,6 +8,8 @@ package org.telegram.ui; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.DatePickerDialog; import android.app.TimePickerDialog; @@ -155,10 +157,10 @@ public class ChatRightsEditActivity extends BaseFragment { private int sendRoundRow; private int sendStickersRow; -// private int sendGamesRow; -// private int sendInlineRow; -// -// private int sendGifsRow; + private int sendGamesRow; + private int sendInlineRow; + + private int sendGifsRow; private int sendPollsRow; private int embedLinksRow; private int startVoiceChatRow; @@ -822,7 +824,13 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } else if (position == sendVoiceRow) { value = bannedRights.send_voices = !bannedRights.send_voices; } else if (position == sendStickersRow) { - value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; + value = bannedRights.send_stickers = !bannedRights.send_stickers; + } else if (position == sendGifsRow) { + value = bannedRights.send_gifs = !bannedRights.send_gifs; + } else if (position == sendGamesRow) { + value = bannedRights.send_games = !bannedRights.send_games; + } else if (position == sendInlineRow) { + value = bannedRights.send_inline = !bannedRights.send_inline; } else if (position == embedLinksRow) { if (bannedRights.send_plain || defaultBannedRights.send_plain) { View senMessagesView = linearLayoutManager.findViewByPosition(sendMessagesRow); @@ -1163,6 +1171,9 @@ private void updateRows(boolean update) { sendVoiceRow = -1; sendRoundRow = -1; sendStickersRow = -1; + sendGifsRow = -1; + sendGamesRow = -1; + sendInlineRow = -1; sendPollsRow = -1; embedLinksRow = -1; startVoiceChatRow = -1; @@ -1218,6 +1229,9 @@ private void updateRows(boolean update) { sendVoiceRow = rowCount++; sendRoundRow = rowCount++; sendStickersRow = rowCount++; + sendGifsRow = rowCount++; + sendGamesRow = rowCount++; + sendInlineRow = rowCount++; sendPollsRow = rowCount++; embedLinksRow = rowCount++; } @@ -1340,6 +1354,14 @@ private void onDonePressed() { } }, err -> { setLoading(false); + if (err != null && "USER_PRIVACY_RESTRICTED".equals(err.text)) { + LimitReachedBottomSheet restrictedUsersBottomSheet = new LimitReachedBottomSheet(ChatRightsEditActivity.this, getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, getResourceProvider()); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(currentUser); + restrictedUsersBottomSheet.setRestrictedUsers(currentChat, arrayList); + restrictedUsersBottomSheet.show(); + return false; + } return true; }); } else if (currentType == TYPE_BANNED) { @@ -1418,19 +1440,26 @@ private void onDonePressed() { private ValueAnimator doneDrawableAnimator; - public void setLoading(boolean enable) { + public void setLoading(boolean newLoading) { if (doneDrawableAnimator != null) { doneDrawableAnimator.cancel(); } - loading = !enable; - actionBar.getBackButton().setEnabled(!enable); + loading = newLoading; + actionBar.getBackButton().setEnabled(!loading); if (doneDrawable != null) { - doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), enable ? 1f : 0f); + doneDrawableAnimator = ValueAnimator.ofFloat(doneDrawable.getProgress(), loading ? 1f : 0f); doneDrawableAnimator.addUpdateListener(a -> { doneDrawable.setProgress((float) a.getAnimatedValue()); doneDrawable.invalidateSelf(); }); - doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (enable ? 1 : 0)))); + doneDrawableAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + doneDrawable.setProgress(loading ? 1 : 0); + doneDrawable.invalidateSelf(); + } + }); + doneDrawableAnimator.setDuration((long) (150 * Math.abs(doneDrawable.getProgress() - (loading ? 1 : 0)))); doneDrawableAnimator.start(); } } @@ -1722,8 +1751,18 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { boolean animated = checkBoxCell.getTag() != null && (Integer) checkBoxCell.getTag() == position; checkBoxCell.setTag(position); if (position == sendStickersRow) { - checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true, animated); + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendStickers2", R.string.UserRestrictionsSendStickers2), "", !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true, animated); +// checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true, animated); checkBoxCell.setIcon(defaultBannedRights.send_stickers ? R.drawable.permission_locked : 0); + } else if (position == sendGifsRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendGifs", R.string.UserRestrictionsSendGifs), "", !bannedRights.send_gifs && !defaultBannedRights.send_gifs, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_gifs ? R.drawable.permission_locked : 0); + } else if (position == sendGamesRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendGames", R.string.UserRestrictionsSendGames), "", !bannedRights.send_games && !defaultBannedRights.send_games, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_games ? R.drawable.permission_locked : 0); + } else if (position == sendInlineRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendInline", R.string.UserRestrictionsSendInline), "", !bannedRights.send_inline && !defaultBannedRights.send_inline, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_inline ? R.drawable.permission_locked : 0); } else if (position == embedLinksRow) { checkBoxCell.setText(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), "", !bannedRights.embed_links && !defaultBannedRights.embed_links && !bannedRights.send_plain && !defaultBannedRights.send_plain, true, animated); checkBoxCell.setIcon(defaultBannedRights.embed_links ? R.drawable.permission_locked : 0); @@ -1826,7 +1865,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (position == sendMediaRow) { int sentMediaCount = getSendMediaSelectedCount(); checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, true); - checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, () -> { + checkCell.setCollapseArrow(String.format(Locale.US, "%d/12", sentMediaCount), !sendMediaExpanded, () -> { if (allDefaultMediaBanned()) { new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) @@ -2150,7 +2189,7 @@ private boolean allDefaultMediaBanned() { } private boolean isExpandableSendMediaRow(int position) { - if (position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || + if (position == sendStickersRow || position == sendGifsRow || position == sendGamesRow || position == sendInlineRow || position == embedLinksRow || position == sendPollsRow || position == sendPhotosRow || position == sendVideosRow || position == sendFilesRow || position == sendMusicRow || position == sendRoundRow || position == sendVoiceRow || position == channelPostMessagesRow || position == channelEditMessagesRow || position == channelDeleteMessagesRow || diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index dcaac72c69..9d5bf0343f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -125,6 +125,10 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int sendMediaPhotosRow; private int sendMediaVideosRow; private int sendMediaStickerGifsRow; + private int sendMediaGamesRow; + private int sendMediaInlineRow; + + private int sendMediaGifsRow; private int sendMediaMusicRow; private int sendMediaFilesRow; private int sendMediaVoiceMessagesRow; @@ -320,6 +324,9 @@ private void updateRows() { sendMediaPhotosRow = -1; sendMediaVideosRow = -1; sendMediaStickerGifsRow = -1; + sendMediaGifsRow = -1; + sendMediaGamesRow = -1; + sendMediaInlineRow = -1; sendMediaMusicRow = -1; sendMediaFilesRow = -1; sendMediaVoiceMessagesRow = -1; @@ -335,6 +342,9 @@ private void updateRows() { sendMediaPhotosRow = rowCount++; sendMediaVideosRow = rowCount++; sendMediaStickerGifsRow = rowCount++; + sendMediaGifsRow = rowCount++; + sendMediaGamesRow = rowCount++; + sendMediaInlineRow = rowCount++; sendMediaMusicRow = rowCount++; sendMediaFilesRow = rowCount++; sendMediaVoiceMessagesRow = rowCount++; @@ -731,7 +741,13 @@ protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { } else if (position == sendMediaVideosRow) { defaultBannedRights.send_videos = !defaultBannedRights.send_videos; } else if (position == sendMediaStickerGifsRow) { - defaultBannedRights.send_stickers = defaultBannedRights.send_games = defaultBannedRights.send_gifs = defaultBannedRights.send_inline = !defaultBannedRights.send_stickers; + defaultBannedRights.send_stickers = !defaultBannedRights.send_stickers; + } else if (position == sendMediaGifsRow) { + defaultBannedRights.send_gifs = !defaultBannedRights.send_gifs; + } else if (position == sendMediaGamesRow) { + defaultBannedRights.send_games = !defaultBannedRights.send_games; + } else if (position == sendMediaInlineRow) { + defaultBannedRights.send_inline = !defaultBannedRights.send_inline; } else if (position == sendMediaMusicRow) { defaultBannedRights.send_audios = !defaultBannedRights.send_audios; } else if (position == sendMediaFilesRow) { @@ -3313,7 +3329,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == sendMediaRow) { int sentMediaCount = getSendMediaSelectedCount(); checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, animated); - checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, new Runnable() { + checkCell.setCollapseArrow(String.format(Locale.US, "%d/12", sentMediaCount), !sendMediaExpanded, new Runnable() { @Override public void run() { if (!checkCell.isEnabled()) return; @@ -3393,7 +3409,14 @@ public void run() { } else if (position == sendMediaVideosRow) { checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos), "", !defaultBannedRights.send_videos, true, animated); } else if (position == sendMediaStickerGifsRow) { - checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !defaultBannedRights.send_stickers, true, animated); + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendStickers2", R.string.UserRestrictionsSendStickers2), "", !defaultBannedRights.send_stickers, true, animated); +// checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !defaultBannedRights.send_stickers, true, animated); + } else if (position == sendMediaGifsRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendGifs", R.string.UserRestrictionsSendGifs), "", !defaultBannedRights.send_gifs, true, animated); + } else if (position == sendMediaGamesRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendGames", R.string.UserRestrictionsSendGames), "", !defaultBannedRights.send_games, true, animated); + } else if (position == sendMediaInlineRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsSendInline", R.string.UserRestrictionsSendInline), "", !defaultBannedRights.send_inline, true, animated); } else if (position == sendMediaMusicRow) { checkBoxCell.setText(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic), "", !defaultBannedRights.send_audios, true, animated); } else if (position == sendMediaFilesRow) { @@ -3486,7 +3509,7 @@ private void setSendMediaEnabled(boolean enabled) { } private boolean isExpandableSendMediaRow(int position) { - return position == sendMediaPhotosRow || position == sendMediaVideosRow || position == sendMediaStickerGifsRow || + return position == sendMediaPhotosRow || position == sendMediaVideosRow || position == sendMediaStickerGifsRow || position == sendMediaGifsRow || position == sendMediaGamesRow || position == sendMediaInlineRow || position == sendMediaMusicRow || position == sendMediaFilesRow || position == sendMediaVoiceMessagesRow || position == sendMediaVideoMessagesRow || position == sendMediaEmbededLinksRow || position == sendPollsRow; } @@ -3649,6 +3672,15 @@ public static int getSendMediaSelectedCount(TLRPC.TL_chatBannedRights bannedRigh if (!bannedRights.send_stickers) { i++; } + if (!bannedRights.send_gifs) { + i++; + } + if (!bannedRights.send_games) { + i++; + } + if (!bannedRights.send_inline) { + i++; + } if (!bannedRights.send_audios) { i++; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 414dca81e3..6a45565969 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -1401,11 +1401,11 @@ public static void createImportDialogAlert(BaseFragment fragment, String title, imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(account, user); imageView.setForUserOrChat(user, avatarDrawable); } } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(account, chat); imageView.setForUserOrChat(chat, avatarDrawable); } @@ -1482,7 +1482,7 @@ public void setText(CharSequence text, BufferType type) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1603,7 +1603,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } @@ -1780,11 +1780,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { imageView.setImage(null, null, avatarDrawable, user); } else { avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); imageView.setForUserOrChat(user, avatarDrawable); } } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(fragment.getCurrentAccount(), chat); imageView.setForUserOrChat(chat, avatarDrawable); } @@ -2069,7 +2069,7 @@ public void setText(CharSequence text, BufferType type) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); avatarDrawable.setScaleSize(1f); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(fragment.getCurrentAccount(), user); BackupImageView imageView = new BackupImageView(context); imageView.setRoundRadius(AndroidUtilities.dp(20)); @@ -2409,7 +2409,7 @@ public static void showChatWithAdmin(BaseFragment fragment, TLRPC.User user, Str buttonTextView.setText(LocaleController.getString("IUnderstand", R.string.IUnderstand)); buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); - buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); + buttonTextView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); linearLayout.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 16, 12, 16, 8)); @@ -2512,9 +2512,9 @@ public static void checkRestrictedInviteUsers(int currentAccount, TLRPC.Chat cur AndroidUtilities.runOnUIThread(() -> { BaseFragment lastFragment = LaunchActivity.getLastFragment(); if (lastFragment != null && lastFragment.getParentActivity() != null) { - LimitReachedBottomSheet restricterdUsersBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, null); - restricterdUsersBottomSheet.setRestrictedUsers(currentChat, finalArrayList); - restricterdUsersBottomSheet.show(); + LimitReachedBottomSheet restrictedUsersBottomSheet = new LimitReachedBottomSheet(lastFragment, lastFragment.getParentActivity(), LimitReachedBottomSheet.TYPE_ADD_MEMBERS_RESTRICTED, currentAccount, null); + restrictedUsersBottomSheet.setRestrictedUsers(currentChat, finalArrayList); + restrictedUsersBottomSheet.show(); } }, 200); } @@ -3238,7 +3238,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("SetTimeLimit", R.string.SetTimeLimit)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3427,7 +3427,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("SetEmojiStatusUntilButton", R.string.SetEmojiStatusUntilButton)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -3572,7 +3572,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(AndroidUtilities.dp(14)); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setText(LocaleController.getString("DisableAutoDeleteTimer", R.string.DisableAutoDeleteTimer)); @@ -3717,7 +3717,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); @@ -3889,7 +3889,7 @@ public CharSequence getAccessibilityClassName() { buttonTextView.setTextColor(datePickerColors.buttonTextColor); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), datePickerColors.buttonBackgroundColor, datePickerColors.buttonBackgroundPressedColor)); buttonTextView.setText(LocaleController.getString("AutoDeleteConfirm", R.string.AutoDeleteConfirm)); container.addView(buttonTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); buttonTextView.setOnClickListener(v -> { @@ -5845,28 +5845,32 @@ public static void createDeleteMessagesAlert(BaseFragment fragment, TLRPC.User u } } - 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 1d8d97a1d8..bf959b9cfe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -70,6 +70,8 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC = 13; public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW = 14; public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; + public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB = 16; + public static final int CACHE_TYPE_EMOJI_CALL = 17; public int rawDrawIndex; @@ -462,7 +464,7 @@ private void updateSize() { 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; @@ -520,17 +522,17 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b } imageReceiver.setVideoThumbIsSame(true); boolean onlyStaticPreview = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW && cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_KEYBOARD && !liteModeKeyboard || cacheType == CACHE_TYPE_ALERT_PREVIEW && !liteModeReactions; - if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB) { onlyStaticPreview = true; } String filter = sizedp + "_" + sizedp; 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) { @@ -572,21 +574,29 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b imageReceiver.setImage(null, null, mediaLocation, mediaFilter, null, null, thumbDrawable, document.size, null, document, 1); } else { if (onlyStaticPreview || (!liteModeKeyboard && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW)) { + ImageLocation thumbLocation = null; + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB) { + thumbLocation = ImageLocation.getForDocument(thumb, document); + } if ("video/webm".equals(document.mime_type)) { - imageReceiver.setImage(null, null, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(null, null, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } else if (MessageObject.isAnimatedStickerDocument(document, true)) { - imageReceiver.setImage(mediaLocation, mediaFilter + "_firstframe", null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(mediaLocation, mediaFilter + "_firstframe", thumbLocation, null, thumbDrawable, document.size, null, document, 1); } else { - imageReceiver.setImage(ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + imageReceiver.setImage(ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, thumbLocation, null, thumbDrawable, document.size, null, document, 1); } } else { - imageReceiver.setImage(mediaLocation, mediaFilter, ImageLocation.getForDocument(thumb, document), sizedp + "_" + sizedp, null, null, thumbDrawable, document.size, null, document, 1); + 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); } } updateAutoRepeat(imageReceiver); - if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC_WITH_THUMB || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { imageReceiver.setLayerNum(7); } if (cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS) { @@ -617,6 +627,8 @@ private void updateAutoRepeat(ImageReceiver imageReceiver) { 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); } } @@ -1059,7 +1071,7 @@ public void resetAnimation() { changeProgress.set(1, true); } - public boolean set(long documentId, int cacheType, boolean animated) { + public boolean set(long documentId, int cacheType, boolean animated) { if (drawables[0] instanceof AnimatedEmojiDrawable && ((AnimatedEmojiDrawable) drawables[0]).getDocumentId() == documentId) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java index e7c20ab131..af509b0f27 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java @@ -1,5 +1,8 @@ package org.telegram.ui.Components; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -32,10 +35,12 @@ import java.util.List; public class AnimatedEmojiSpan extends ReplacementSpan { + private static boolean lockPositionChanging; public long documentId; public TLRPC.Document document; private float scale; + private float extraScale = 1f; public boolean standard; public boolean full = false; public boolean top = false; @@ -52,6 +57,80 @@ public class AnimatedEmojiSpan extends ReplacementSpan { float lastDrawnCy; private boolean recordPositions = true; public boolean fromEmojiKeyboard; + private boolean isAdded; + private boolean isRemoved; + private Runnable removedAction; + private boolean animateChanges; + private ValueAnimator moveAnimator; + private ValueAnimator scaleAnimator; + + /** + * To correctly move emoji to a new line, we need to return the final size in {@link #getSize}. + * However, this approach causes flickering. So fix this using {@link #lockPositionChanging} flag. + */ + public void setAdded() { + isAdded = true; + extraScale = 0f; + lockPositionChanging = true; + } + + public void setAnimateChanges() { + this.animateChanges = true; + } + + public void setRemoved(Runnable action) { + removedAction = action; + isRemoved = true; + extraScale = 1f; + } + + public float getExtraScale() { + if (isAdded) { + isAdded = false; + extraScale = 0f; + scaleAnimator = ValueAnimator.ofFloat(extraScale, 1f); + scaleAnimator.addUpdateListener(animator -> { + extraScale = (float) animator.getAnimatedValue(); + scale = AndroidUtilities.lerp(.2f, 1f, extraScale); + lockPositionChanging = false; + }); + scaleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scaleAnimator = null; + } + }); + scaleAnimator.setDuration(130); + scaleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + scaleAnimator.start(); + } else if (isRemoved) { + isRemoved = false; + extraScale = 1f; + if (scaleAnimator != null) { + scaleAnimator.removeAllListeners(); + scaleAnimator.cancel(); + } + scaleAnimator = ValueAnimator.ofFloat(extraScale, 0f); + scaleAnimator.addUpdateListener(animator -> { + extraScale = (float) animator.getAnimatedValue(); + scale = AndroidUtilities.lerp(0f, 1f, extraScale); + }); + scaleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + scaleAnimator = null; + if (removedAction != null) { + removedAction.run(); + removedAction = null; + } + } + }); + scaleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + scaleAnimator.setDuration(130); + scaleAnimator.start(); + } + return extraScale; + } public AnimatedEmojiSpan(@NonNull TLRPC.Document document, Paint.FontMetricsInt fontMetrics) { this(document.id, 1.2f, fontMetrics); @@ -146,19 +225,19 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon if (fm != null) { if (!full) { - fm.ascent = (int) (fontMetrics.ascent); + fm.ascent = (int) (fontMetrics.ascent); fm.descent = (int) (fontMetrics.descent); - fm.top = (int) (fontMetrics.top); - fm.bottom = (int) (fontMetrics.bottom); + fm.top = (int) (fontMetrics.top); + fm.bottom = (int) (fontMetrics.bottom); } else { float height = Math.abs(fontMetrics.bottom) + Math.abs(fontMetrics.top); - fm.ascent = (int) Math.ceil(fontMetrics.top / height * measuredSize); + fm.ascent = (int) Math.ceil(fontMetrics.top / height * measuredSize); fm.descent = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); - fm.top = (int) Math.ceil(fontMetrics.top / height * measuredSize); - fm.bottom = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); + fm.top = (int) Math.ceil(fontMetrics.top / height * measuredSize); + fm.bottom = (int) Math.ceil(fontMetrics.bottom / height * measuredSize); } } } @@ -167,12 +246,41 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon fm.ascent += diff; fm.descent -= diff; } - return measuredSize - 1; + return Math.max(0, measuredSize - 1); } - private int asizeDp; - public void addSize(int asizeDp) { -// this.asizeDp = asizeDp; + private boolean isAnimating() { + return moveAnimator != null || scaleAnimator != null; + } + + private boolean animateChanges(float cx, float cy) { + if (moveAnimator != null) { + return true; + } + if (!animateChanges) { + return false; + } + animateChanges = false; + final float fromCx = lastDrawnCx; + final float fromCy = lastDrawnCy; + final float toCx = cx; + final float toCy = cy; + moveAnimator = ValueAnimator.ofFloat(0f, 1f); + moveAnimator.addUpdateListener(animator -> { + float percent = (float) animator.getAnimatedValue(); + lastDrawnCy = AndroidUtilities.lerp(fromCy, toCy, percent); + lastDrawnCx = AndroidUtilities.lerp(fromCx, toCx, percent); + }); + moveAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + moveAnimator = null; + } + }); + moveAnimator.setDuration(140); + moveAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + moveAnimator.start(); + return true; } @Override @@ -181,6 +289,12 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i spanDrawn = true; float cx = x + measuredSize / 2f; float cy = top + (bottom - top) / 2f; + if ((cy != lastDrawnCy && lastDrawnCy != 0 || cx != lastDrawnCx && lastDrawnCx != 0) && animateChanges(cx, cy)) { + return; + } + if (lockPositionChanging) { + return; + } if (cx != lastDrawnCx || cy != lastDrawnCy) { lastDrawnCx = cx; lastDrawnCy = cy; @@ -300,7 +414,18 @@ public void draw(Canvas canvas, long time, float boundTop, float boundBottom, fl if (drawable.getImageReceiver() != null) { drawable.setColorFilter(colorFilter == null ? Theme.chat_animatedEmojiTextColorFilter : colorFilter); drawable.setTime(time); - drawable.draw(canvas, drawableBounds, alpha * this.alpha); + float scale = span.getExtraScale(); + if (scale != 1f) { + canvas.save(); + canvas.scale(scale, scale, drawableBounds.centerX(), drawableBounds.centerY()); + drawable.draw(canvas, drawableBounds, alpha * this.alpha); + canvas.restore(); + } else { + drawable.draw(canvas, drawableBounds, alpha * this.alpha); + } + if (span.isAnimating()) { + invalidate(); + } } } @@ -337,15 +462,15 @@ public static EmojiGroupedSpans update(int cacheType, View view, boolean invalid return update(cacheType, view, invalidateParent, prev, clone, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, EmojiGroupedSpans prev, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, EmojiGroupedSpans prev, Layout... layouts) { return update(cacheType, view, false, prev, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, Layout... layouts) { return update(cacheType, view, invalidateParent, prev, false, layouts); } - public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, boolean clone, Layout ...layouts) { + public static EmojiGroupedSpans update(int cacheType, View view, boolean invalidateParent, EmojiGroupedSpans prev, boolean clone, Layout... layouts) { if (layouts == null || layouts.length <= 0) { if (prev != null) { prev.holders.clear(); @@ -645,14 +770,6 @@ public void clearPositions() { } } - public void incrementFrames(int inc) { - for (int i = 0; i < holders.size(); i++) { - if (holders.get(i).drawable != null && holders.get(i).drawable.getImageReceiver() != null) { - holders.get(i).drawable.getImageReceiver().incrementFrames(inc); - } - } - } - public void recordPositions(boolean record) { for (int i = 0; i < holders.size(); i++) { holders.get(i).span.recordPositions = record; @@ -706,7 +823,7 @@ private void checkBackgroundRendering() { private final ArrayList backgroundHolders = new ArrayList<>(); @Override - public void drawInBackground(Canvas canvas) { + public void drawInBackground(Canvas canvas) { for (int i = 0; i < backgroundHolders.size(); i++) { AnimatedEmojiHolder holder = backgroundHolders.get(i); if (holder != null && holder.backgroundDrawHolder[threadIndex] != null) { @@ -826,6 +943,8 @@ public static AnimatedEmojiSpan cloneSpan(AnimatedEmojiSpan span) { animatedEmojiSpan = new AnimatedEmojiSpan(span.documentId, span.scale, span.fontMetrics); } animatedEmojiSpan.fromEmojiKeyboard = span.fromEmojiKeyboard; + animatedEmojiSpan.isAdded = span.isAdded; + animatedEmojiSpan.isRemoved = span.isRemoved; return animatedEmojiSpan; } @@ -854,7 +973,7 @@ public static CharSequence cloneSpans(CharSequence text, int newCacheType) { if (spans[i] instanceof AnimatedEmojiSpan) { int start = spanned.getSpanStart(spans[i]); - int end = spanned.getSpanEnd(spans[i]); + int end = spanned.getSpanEnd(spans[i]); AnimatedEmojiSpan oldSpan = (AnimatedEmojiSpan) spans[i]; newText.removeSpan(oldSpan); @@ -876,6 +995,7 @@ public TextViewEmojis(Context context) { } AnimatedEmojiSpan.EmojiGroupedSpans stack; + @Override public void setText(CharSequence text, TextView.BufferType type) { super.setText(text, type); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index 489e53d303..d8acbd1ca5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -62,7 +62,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, private static native void stopDecoder(long ptr); - private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride, boolean preview, float startTimeSeconds, float endTimeSeconds); + private static native int getVideoFrame(long ptr, Bitmap bitmap, int[] params, int stride, boolean preview, float startTimeSeconds, float endTimeSeconds, boolean loop); private static native void seekToMs(long ptr, long ms, boolean precise); @@ -431,7 +431,7 @@ public void run() { if (backgroundBitmap != null) { lastFrameDecodeTime = System.currentTimeMillis(); - if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime) == 0) { + if (getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime, true) == 0) { AndroidUtilities.runOnUIThread(uiRunnableNoFrame); return; } @@ -547,7 +547,7 @@ public Bitmap getFrameAtTime(long ms, boolean precise) { if (precise) { result = getFrameAtTime(nativePtr, ms, backgroundBitmap, metaData, backgroundBitmap.getRowBytes()); } else { - result = getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), true, 0, 0); + result = getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), true, 0, 0, true); } return result != 0 ? backgroundBitmap : null; } @@ -765,6 +765,10 @@ public int getCurrentProgressMs() { return nextRenderingBitmapTime != 0 ? nextRenderingBitmapTime : renderingBitmapTime; } + public int getProgressMs() { + return metaData[3]; + } + public int getDurationMs() { return metaData[4]; } @@ -1083,7 +1087,7 @@ public boolean isRecycled() { return isRecycled || decoderTryCount >= 15; } - public Bitmap getNextFrame() { + public Bitmap getNextFrame(boolean loop) { if (nativePtr == 0) { return backgroundBitmap; } @@ -1094,7 +1098,7 @@ public Bitmap getNextFrame() { backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); } } - getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(nativePtr, backgroundBitmap, metaData, backgroundBitmap.getRowBytes(), false, startTime, endTime, loop); return backgroundBitmap; } @@ -1140,7 +1144,7 @@ public int getNextFrame(Bitmap bitmap) { if (generatingCacheBitmap == null) { generatingCacheBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); } - getVideoFrame(cacheGenerateNativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(cacheGenerateNativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime, true); if (cacheGenerateTimestamp != 0 && (metaData[3] == 0 || cacheGenerateTimestamp > metaData[3])) { return 0; } @@ -1175,7 +1179,7 @@ public Bitmap getFirstFrame(Bitmap bitmap) { if (nativePtr == 0) { return bitmap; } - getVideoFrame(nativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime); + getVideoFrame(nativePtr, generatingCacheBitmap, metaData, generatingCacheBitmap.getRowBytes(), false, startTime, endTime, true); destroyDecoder(nativePtr); bitmap.eraseColor(Color.TRANSPARENT); canvas.save(); @@ -1192,11 +1196,11 @@ public void drawFrame(Canvas canvas, int incFrame) { return; } for (int i = 0; i < incFrame; ++i) { - getNextFrame(); + getNextFrame(true); } Bitmap bitmap = getBackgroundBitmap(); if (bitmap == null) { - bitmap = getNextFrame(); + bitmap = getNextFrame(true); } AndroidUtilities.rectTmp2.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); canvas.drawBitmap(getBackgroundBitmap(), AndroidUtilities.rectTmp2, getBounds(), getPaint()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java index d0b595a9dd..c32374e047 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java @@ -115,6 +115,8 @@ public AnimatedFloat(float initialValue, Runnable invalidate, long transitionDel this.firstSet = false; } + // get() is not recommended to use (unless minimize System.currentTimeMillis() calls) + @Deprecated public float get() { return value; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index 1b58508f47..fee86bb1fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -109,6 +109,9 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, DownloadController.FileDownloadProgressListener { + private TextView forwardButton; + private TextView backwardButton; + private ActionBar actionBar; private View actionBarShadow; private View playerShadow; @@ -747,14 +750,52 @@ public CharSequence getContentDescription() { FrameLayout bottomView = new FrameLayout(context) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int dist = ((right - left) - AndroidUtilities.dp(8 + 48 * 5)) / 4; - for (int a = 0; a < 5; a++) { + int dist = ((right - left) - AndroidUtilities.dp(8 + 48 * 7)) / 4; + int forkButtonsLayouted = 0; + for (int a = 0; a < 7; a++) { int l = AndroidUtilities.dp(4 + 48 * a) + dist * a; int t = AndroidUtilities.dp(9); - buttons[a].layout(l, t, l + buttons[a].getMeasuredWidth(), t + buttons[a].getMeasuredHeight()); + if (a == 1) { + backwardButton.layout(l, t, l + backwardButton.getMeasuredWidth(), t + backwardButton.getMeasuredHeight()); + forkButtonsLayouted++; + } else if (a == 5) { + forwardButton.layout(l, t, l + forwardButton.getMeasuredWidth(), t + forwardButton.getMeasuredHeight()); + forkButtonsLayouted++; + } else { + int i = a - forkButtonsLayouted; + buttons[i].layout(l, t, l + buttons[i].getMeasuredWidth(), t + buttons[i].getMeasuredHeight()); + } } } }; + + { + final int s = 5; + final int color = getThemedColor(Theme.key_listSelector); + final FrameLayout.LayoutParams frame = LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP); + forwardButton = new TextView(context); + forwardButton.setText("+" + s + "s"); + forwardButton.setGravity(Gravity.CENTER); + bottomView.addView(forwardButton, frame); + + backwardButton = new TextView(context); + backwardButton.setText("–" + s + "s"); + backwardButton.setGravity(Gravity.CENTER); + bottomView.addView(backwardButton, frame); + + if (Build.VERSION.SDK_INT >= 21) { + forwardButton.setBackgroundDrawable(Theme.createSelectorDrawable(color, 1, AndroidUtilities.dp(24))); + backwardButton.setBackgroundDrawable(Theme.createSelectorDrawable(color, 1, AndroidUtilities.dp(24))); + } + + forwardButton.setOnClickListener(view -> { + MediaController.getInstance().seekShift(s * 1000); + }); + backwardButton.setOnClickListener(view -> { + MediaController.getInstance().seekShift(-s * 1000); + }); + } + playerLayout.addView(bottomView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 66, Gravity.TOP | Gravity.LEFT, 0, 111, 0, 0)); buttons[0] = repeatButton = new ActionBarMenuItem(context, null, 0, 0, false, resourcesProvider); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java index a5d2028c00..386ec15810 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AutoDeletePopupWrapper.java @@ -26,7 +26,7 @@ public class AutoDeletePopupWrapper { private final ActionBarMenuSubItem disableItem; Callback callback; long lastDismissTime; - TextView textView; + public TextView textView; public AutoDeletePopupWrapper(Context context, PopupSwipeBackLayout swipeBackLayout, Callback callback, boolean createBackground, int type, Theme.ResourcesProvider resourcesProvider) { windowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(context, createBackground ? R.drawable.popup_fixed_alert : 0, resourcesProvider); @@ -115,14 +115,14 @@ public void updateItems(int ttl) { } } - public void allowExtenededHint() { + public void allowExtendedHint(int linkColor) { if (textView == null) { return; } SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(LocaleController.getString("AutoDeletePopupDescription", R.string.AutoDeletePopupDescription)); spannableStringBuilder.append("\n\n"); - spannableStringBuilder.append(AndroidUtilities.replaceSingleTag(LocaleController.getString("AutoDeletePopupDescription2", R.string.AutoDeletePopupDescription2), () -> { + spannableStringBuilder.append(AndroidUtilities.replaceSingleLink(LocaleController.getString(R.string.AutoDeletePopupDescription2), linkColor, () -> { callback.showGlobalAutoDeleteScreen(); })); textView.setText(spannableStringBuilder); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java index 246662a427..01cae9d823 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -24,9 +26,9 @@ import android.text.TextUtils; import androidx.core.graphics.ColorUtils; -import androidx.core.math.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -40,7 +42,7 @@ import java.util.ArrayList; -import xyz.nextalone.nagram.helper.PeerColorHelper; +import xyz.nextalone.nagram.NaConfig; public class AvatarDrawable extends Drawable { @@ -69,12 +71,14 @@ public class AvatarDrawable extends Drawable { private int gradientColor21, gradientColor22; private LinearGradient gradient2; private boolean drawAvatarBackground = true; + private boolean rotate45Background = false; public static final int AVATAR_TYPE_NORMAL = 0; public static final int AVATAR_TYPE_SAVED = 1; public static final int AVATAR_TYPE_ARCHIVED = 2; public static final int AVATAR_TYPE_SHARES = 3; public static final int AVATAR_TYPE_REPLIES = 12; + public static final int AVATAR_TYPE_STORY = 20; public static final int AVATAR_TYPE_FILTER_CONTACTS = 4; public static final int AVATAR_TYPE_FILTER_NON_CONTACTS = 5; @@ -105,7 +109,7 @@ public AvatarDrawable(Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); namePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - namePaint.setTextSize(AndroidUtilities.dp(18)); + namePaint.setTextSize(dp(18)); } public AvatarDrawable(TLRPC.User user) { @@ -193,12 +197,12 @@ public static int getNameColorNameForId(long id) { } public void setInfo(TLRPC.User user) { + setInfo(UserConfig.selectedAccount, user); + } + + public void setInfo(int currentAccount, TLRPC.User user) { if (user != null) { - Integer colorId = (user.flags2 & 128) != 0 ? user.color : null; - if (user.self) { - colorId = PeerColorHelper.replaceColor(colorId); - } - setInfo(user.id, user.first_name, user.last_name, null, colorId); + setInfo(user.id, user.first_name, user.last_name, null, user != null && user.color != null ? UserObject.getColorId(user) : null, UserObject.getPeerColorForAvatar(currentAccount, user)); drawDeleted = UserObject.isDeleted(user); } } @@ -213,12 +217,23 @@ public void setInfo(TLObject object) { } } + public void setInfo(int currentAccount, TLObject object) { + if (object instanceof TLRPC.User) { + setInfo(currentAccount, (TLRPC.User) object); + } else if (object instanceof TLRPC.Chat) { + setInfo(currentAccount, (TLRPC.Chat) object); + } else if (object instanceof TLRPC.ChatInvite) { + setInfo(currentAccount, (TLRPC.ChatInvite) object); + } + } + public void setScaleSize(float value) { scaleSize = value; } public void setAvatarType(int value) { avatarType = value; + rotate45Background = false; if (avatarType == AVATAR_TYPE_REGISTER) { hasGradient = false; color = color2 = Theme.getColor(Theme.key_chats_actionBackground); @@ -229,6 +244,11 @@ public void setAvatarType(int value) { hasGradient = true; color = getThemedColor(Theme.key_avatar_backgroundSaved); color2 = getThemedColor(Theme.key_avatar_background2Saved); + } else if (avatarType == AVATAR_TYPE_STORY) { + rotate45Background = true; + hasGradient = true; + color = getThemedColor(Theme.key_stories_circle1); + color2 = getThemedColor(Theme.key_stories_circle2); } else if (avatarType == AVATAR_TYPE_SHARES) { hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); @@ -270,7 +290,7 @@ public void setAvatarType(int value) { color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(4)]); } - needApplyColorAccent = avatarType != AVATAR_TYPE_ARCHIVED && avatarType != AVATAR_TYPE_SAVED && avatarType != AVATAR_TYPE_REPLIES && avatarType != AVATAR_TYPE_OTHER_CHATS; + needApplyColorAccent = avatarType != AVATAR_TYPE_ARCHIVED && avatarType != AVATAR_TYPE_SAVED && avatarType != AVATAR_TYPE_STORY && avatarType != AVATAR_TYPE_REPLIES && avatarType != AVATAR_TYPE_OTHER_CHATS; } public void setArchivedAvatarHiddenProgress(float progress) { @@ -282,13 +302,20 @@ public int getAvatarType() { } public void setInfo(TLRPC.Chat chat) { + setInfo(UserConfig.selectedAccount, chat); + } + public void setInfo(int currentAccount, TLRPC.Chat chat) { if (chat != null) { - setInfo(chat.id, chat.title, null, null, (chat.flags2 & 64) != 0 ? chat.color : null); + setInfo(chat.id, chat.title, null, null, chat != null && chat.color != null ? ChatObject.getColorId(chat) : null, ChatObject.getPeerColorForAvatar(currentAccount, chat)); } } + public void setInfo(TLRPC.ChatInvite chat) { + setInfo(UserConfig.selectedAccount, chat); + } + public void setInfo(int currentAccount, TLRPC.ChatInvite chat) { if (chat != null) { - setInfo(0, chat.title, null, null, chat.chat != null && (chat.chat.flags2 & 64) != 0 ? chat.chat.color : null); + setInfo(0, chat.title, null, null, chat.chat != null && chat.chat.color != null ? ChatObject.getColorId(chat.chat) : null, ChatObject.getPeerColorForAvatar(currentAccount, chat.chat)); } } @@ -314,7 +341,7 @@ public void setTextSize(int size) { } public void setInfo(long id, String firstName, String lastName) { - setInfo(id, firstName, lastName, null, null); + setInfo(id, firstName, lastName, null, null, null); } public int getColor() { @@ -334,13 +361,16 @@ private static String takeFirstCharacter(String text) { } public void setInfo(long id, String firstName, String lastName, String custom) { - setInfo(id, firstName, lastName, custom, null); + setInfo(id, firstName, lastName, custom, null, null); } - public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor) { + public void setInfo(long id, String firstName, String lastName, String custom, Integer customColor, MessagesController.PeerColor profileColor) { hasGradient = true; invalidateTextLayout = true; - if (customColor != null) { + if (profileColor != null) { + color = profileColor.getAvatarColor1(); + color2 = profileColor.getAvatarColor2(); + } else if (customColor != null) { if (customColor >= 14) { MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); if (messagesController != null && messagesController.peerColors != null && messagesController.peerColors.getColor(customColor) != null) { @@ -430,12 +460,21 @@ public void draw(Canvas canvas) { canvas.translate(bounds.left, bounds.top); if (drawAvatarBackground) { + if (rotate45Background) { + canvas.save(); + canvas.rotate(-45, size / 2.0f, size / 2.0f); + } if (roundRadius > 0) { AndroidUtilities.rectTmp.set(0, 0, size, size); canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, Theme.avatar_backgroundPaint); + } else if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + canvas.drawRect(0f, 0f, size, size, Theme.avatar_backgroundPaint); } else { canvas.drawCircle(size / 2.0f, size / 2.0f, size / 2.0f, Theme.avatar_backgroundPaint); } + if (rotate45Background) { + canvas.restore(); + } } if (avatarType == AVATAR_TYPE_ARCHIVED) { @@ -499,6 +538,8 @@ public void draw(Canvas canvas) { drawable = Theme.avatarDrawables[15]; } else if (avatarType == AVATAR_TYPE_UNCLAIMED) { drawable = Theme.avatarDrawables[16]; + } else if (avatarType == AVATAR_TYPE_STORY) { + drawable = Theme.avatarDrawables[17]; } else { drawable = Theme.avatarDrawables[9]; } @@ -523,8 +564,8 @@ public void draw(Canvas canvas) { } else if (drawDeleted && Theme.avatarDrawables[1] != null) { int w = Theme.avatarDrawables[1].getIntrinsicWidth(); int h = Theme.avatarDrawables[1].getIntrinsicHeight(); - if (w > size - AndroidUtilities.dp(6) || h > size - AndroidUtilities.dp(6)) { - float scale = size / (float) AndroidUtilities.dp(50); + if (w > size - dp(6) || h > size - dp(6)) { + float scale = size / (float) dp(50); w *= scale; h *= scale; } @@ -537,10 +578,10 @@ public void draw(Canvas canvas) { invalidateTextLayout = false; if (stringBuilder.length() > 0) { CharSequence text = stringBuilder.toString().toUpperCase(); - text = Emoji.replaceEmoji(text, namePaint.getFontMetricsInt(), AndroidUtilities.dp(16), true); + text = Emoji.replaceEmoji(text, namePaint.getFontMetricsInt(), dp(16), true); if (textLayout == null || !TextUtils.equals(text, textLayout.getText())) { try { - textLayout = new StaticLayout(text, namePaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + textLayout = new StaticLayout(text, namePaint, dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (textLayout.getLineCount() > 0) { textLeft = textLayout.getLineLeft(0); textWidth = textLayout.getLineWidth(0); @@ -555,7 +596,7 @@ public void draw(Canvas canvas) { } } if (textLayout != null) { - float scale = size / (float) AndroidUtilities.dp(50); + float scale = size / (float) dp(50); canvas.scale(scale, scale, size / 2f, size / 2f) ; canvas.translate((size - textWidth) / 2 - textLeft, (size - textHeight) / 2); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java index 8c21a30ddb..fcef07bf4e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java @@ -305,10 +305,10 @@ public void setObject(int index, int account, TLObject object) { long id = MessageObject.getPeerId(participant.peer); if (DialogObject.isUserDialog(id)) { currentUser = MessagesController.getInstance(account).getUser(id); - animatingStates[index].avatarDrawable.setInfo(currentUser); + animatingStates[index].avatarDrawable.setInfo(account, currentUser); } else { currentChat = MessagesController.getInstance(account).getChat(-id); - animatingStates[index].avatarDrawable.setInfo(currentChat); + animatingStates[index].avatarDrawable.setInfo(account, currentChat); } if (currentStyle == 4) { if (id == AccountInstance.getInstance(account).getUserConfig().getClientUserId()) { @@ -332,14 +332,14 @@ public void setObject(int index, int account, TLObject object) { } else { animatingStates[index].avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NORMAL); animatingStates[index].avatarDrawable.setScaleSize(1f); - animatingStates[index].avatarDrawable.setInfo(currentUser); + animatingStates[index].avatarDrawable.setInfo(account, currentUser); } animatingStates[index].id = currentUser.id; } else { currentChat = (TLRPC.Chat) object; animatingStates[index].avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_NORMAL); animatingStates[index].avatarDrawable.setScaleSize(1f); - animatingStates[index].avatarDrawable.setInfo(currentChat); + animatingStates[index].avatarDrawable.setInfo(account, currentChat); animatingStates[index].id = -currentChat.id; } if (currentUser != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java index 9c3441cf70..e3974d569c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java @@ -109,7 +109,7 @@ public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButt Drawable thumb = avatarDrawable; boolean addDivider = false; if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), chat); if (chat.photo != null && chat.photo.strippedBitmap != null) { thumb = chat.photo.strippedBitmap; } @@ -130,11 +130,11 @@ public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButt imageView.setImageDrawable(avatarDrawable); } else if (UserObject.isDeleted(user)) { name = LocaleController.getString("HiddenName", R.string.HiddenName); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), user); imageView.setImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), "50_50", avatarDrawable, user); } else { name = UserObject.getUserName(user); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(thisFragment.getCurrentAccount(), user); imageView.setImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), "50_50", thumb, user); } titleView.setText(name); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java index 17f5965114..3bdd4a8e81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -43,6 +43,7 @@ public class BackupImageView extends View { public BackupImageView(Context context) { super(context); imageReceiver = createImageReciever(); + imageReceiver.setCrossfadeByScale(0); imageReceiver.setAllowLoadingOnAttachedOnly(true); imageReceiver.setDelegate((imageReceiver1, set, thumb, memCache) -> { if (set && !thumb) { @@ -184,6 +185,11 @@ public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocat onNewImageSet(); } + public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, Drawable thumb, String ext, long size, int cacheType, Object parentObject) { + imageReceiver.setImage(imageLocation, imageFilter, thumbLocation, thumbFilter, thumb, size, ext, parentObject, cacheType); + onNewImageSet(); + } + public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, long size, int cacheType, Object parentObject) { imageReceiver.setImage(imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); onNewImageSet(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BitmapShaderTools.java index 4ee2471caf..b2aec0db8b 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 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 void setBounds(float left, float top, float right, float bottom) { 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 743d114c12..d2519fab2b 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 BlobDrawable(int n, int liteFlag) { 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; @@ -178,6 +178,10 @@ public void generateBlob() { private final static float animationSpeed = 1f - ANIMATION_SPEED_WAVE_HUGE; private final static float animationSpeedTiny = 1f - ANIMATION_SPEED_WAVE_SMALL; + public void setValue(float value) { + amplitude = value; + } + public void setValue(float value, boolean isBig) { animateToAmplitude = value; if (!LiteMode.isEnabled(liteFlag)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BlurringShader.java index 26b57060f7..a086e0d95d 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 @@ private void invalidateFallbackBlur() { 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 void destroy() { 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 Bitmap getBitmap(Bitmap bitmap, String key, int orientation, int invert) } else { resultBitmap.recycle(); } + + if (recycleAfter) { + bitmap.recycle(); + } }); }); return thumbBitmap; @@ -675,14 +682,14 @@ public Bitmap getBitmap(ImageReceiver imageReceiver) { 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); } } @@ -696,6 +703,9 @@ public static class StoryBlurDrawer { public static final int BLUR_TYPE_MENU_BACKGROUND = 5; public static final int BLUR_TYPE_SHADOW = 6; public static final int BLUR_TYPE_EMOJI_VIEW = 7; + public static final int BLUR_TYPE_REPLY_BACKGROUND = 8; + public static final int BLUR_TYPE_REPLY_TEXT_XFER = 9; + public static final int BLUR_TYPE_ACTION_BACKGROUND = 10; private final BlurManager manager; private final View view; @@ -728,10 +738,9 @@ public StoryBlurDrawer(@Nullable BlurManager manager, @NonNull View view, int ty } else if (type == BLUR_TYPE_CAPTION_XFER) { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); oldPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.8f); - AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.45f); - AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 2.5f); - AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.8f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.4f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.3f); +// AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 1.4f); } else if (type == BLUR_TYPE_CAPTION) { AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.35f); AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.7f); @@ -747,7 +756,20 @@ public StoryBlurDrawer(@Nullable BlurManager manager, @NonNull View view, int ty AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.35f); } else if (type == BLUR_TYPE_EMOJI_VIEW) { AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.5f); - AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .85f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .95f); + } else if (type == BLUR_TYPE_REPLY_BACKGROUND) { + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, -.15f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.47f); + } else if (type == BLUR_TYPE_REPLY_TEXT_XFER) { + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + oldPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.4f); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.45f); +// AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 1.4f); + } 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)); @@ -819,6 +841,22 @@ public void setBounds(RectF bounds) { 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); @@ -903,6 +941,7 @@ private boolean setupMatrix(int bitmapWidth, int bitmapHeight) { 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(); @@ -920,6 +959,7 @@ private boolean setupMatrix(int bitmapWidth, int bitmapHeight) { } 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 a087af2e53..7fcd0fafa9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -1175,7 +1175,11 @@ public void dismiss(Runnable callback) { 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/BottomPagerTabs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java index 4b55e6164e..bc8b718e03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomPagerTabs.java @@ -46,6 +46,7 @@ protected class Tab { final AnimatedFloat nonscrollingT = new AnimatedFloat(BottomPagerTabs.this, 0, 200, CubicBezierInterpolator.EASE_OUT_QUINT); public int customEndFrameMid; public int customEndFrameEnd; + public boolean customFrameInvert; public Tab(int i, int resId, CharSequence text) { this.i = i; @@ -68,6 +69,9 @@ public Tab(int i, int resId, CharSequence text) { private boolean active; public void setActive(boolean active, boolean animated) { + if (customFrameInvert) { + active = !active; + } if (this.active == active) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java index eb1e8d095d..9737c16992 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 @@ private void postDrawInternal(Canvas canvas, View parentView) { 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 64fdc41f73..47c5213e46 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -202,6 +202,11 @@ public Bulletin hideAfterBottomSheet(boolean hide) { return this; } + public Bulletin setTag(int tag) { + this.tag = tag; + return this; + } + public Bulletin show() { return show(false); } @@ -669,7 +674,11 @@ public Layout(@NonNull Context context, Theme.ResourcesProvider resourcesProvide } 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") { @@ -1080,9 +1089,17 @@ public ButtonLayout(@NonNull Context context, Theme.ResourcesProvider resourcesP 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()); @@ -1915,9 +1932,4 @@ public void updateLayout() { } } } - - public Bulletin setTag(int tag) { - this.tag = tag; - return this; - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java index d2c1928b31..bf45b98d05 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -43,6 +43,7 @@ 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; @@ -193,6 +194,20 @@ public Bulletin createSimpleBulletinWithIconSize(int iconRawId, CharSequence tex 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); @@ -223,6 +238,26 @@ public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLi return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLines, int duration) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + if (text != null) { + String string = text.toString(); + SpannableStringBuilder ssb = text instanceof SpannableStringBuilder ? (SpannableStringBuilder) text : new SpannableStringBuilder(text); + for (int index = string.indexOf('\n'), l = 0; index >= 0 && index < text.length(); l++, index = string.indexOf('\n', index + 1)) { + if (l >= maxLines) { + ssb.replace(index, index + 1, " "); + } + } + text = ssb; + } + layout.textView.setText(text); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(maxLines); + return create(layout, duration); + } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); @@ -501,6 +536,20 @@ public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text) return create(layout, Bulletin.DURATION_LONG); } + public Bulletin createStaticEmojiBulletin(TLRPC.Document document, CharSequence text) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + if (MessageObject.isTextColorEmoji(document)) { + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); + } + layout.setAnimation(document, 36, 36); + layout.imageView.stopAnimation(); + layout.textView.setText(text); + layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(3); + return create(layout, Bulletin.DURATION_LONG); + } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text, CharSequence button, Runnable onButtonClick) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); if (MessageObject.isTextColorEmoji(document)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java index 7852b1cb23..b0115a5a87 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java @@ -94,7 +94,7 @@ public boolean isPressed() { return isPressed; } - private void invalidate() { + public void invalidate() { if (view != null) { view.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CaptionPhotoViewer.java index 5c5bf8b02d..41276e7ed0 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 @@ protected int additionalKeyboardHeight() { @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 4cd0c458e8..d9ce49137e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -64,7 +64,6 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; -import android.text.style.DynamicDrawableSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.util.Log; @@ -125,7 +124,6 @@ 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; @@ -136,7 +134,6 @@ 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; @@ -147,7 +144,6 @@ 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; @@ -172,11 +168,13 @@ 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.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -232,6 +230,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; @@ -286,7 +287,7 @@ default void onContextMenuClose() { 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); @@ -374,6 +375,10 @@ default ChatActivity.ReplyQuote getReplyQuote() { default void onKeyboardRequested() { } + + default boolean onceVoiceAvailable() { + return false; + } } public final static int RECORD_STATE_ENTER = 0; @@ -578,6 +583,7 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo i private AnimatorSet scheduledButtonAnimation; @Nullable private RecordCircle recordCircle; + private OnceButton onceButton; private CloseProgressDrawable2 progressDrawable; private Paint dotPaint; private MediaActionDrawable playPauseDrawable; @@ -656,6 +662,7 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo i private boolean ignoreTextChange; private int innerTextChange; private MessageObject replyingMessageObject; + private MessageObject replyingTopMessage; private ChatActivity.ReplyQuote replyingQuote; private MessageObject botMessageObject; private TLRPC.WebPage messageWebPage; @@ -781,7 +788,7 @@ public void set(RecordCircle object, Float value) { @Override public void run() { if (delegate != null) { - delegate.needStartRecordVideo(0, true, 0); + delegate.needStartRecordVideo(0, true, 0, 0); } } }; @@ -894,7 +901,7 @@ protected void onDetachedFromWindow() { public RecordDot(Context context) { super(context); - int resId = R.raw.chat_audio_record_delete; + int resId = R.raw.chat_audio_record_delete_2; drawable = new RLottieDrawable(resId, "" + resId, AndroidUtilities.dp(28), AndroidUtilities.dp(28), false, null); drawable.setCurrentParentView(this); drawable.setInvalidateOnProgressSet(true); @@ -1065,9 +1072,147 @@ public void set(View object, Float value) { } }; + 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; @@ -1079,7 +1224,7 @@ public class RecordCircle extends View { private boolean pressed; private float transformToSeekbar; private float exitTransition; - private float progressToSeekbarStep3; + public float progressToSeekbarStep3; private float progressToSendButton; public float iconScale; @@ -1113,8 +1258,9 @@ public class RecordCircle extends View { 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; @@ -1281,9 +1427,9 @@ public boolean onTouchEvent(MotionEvent event) { 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) { @@ -1326,6 +1472,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { slideDelta = (int) (-distance * (1f - slideToCancelProgress)); } + public float moveProgress; + public float lockY, lockSize; + public float translationDy; + @Override protected void onDraw(Canvas canvas) { if (skipDraw) { @@ -1420,6 +1570,8 @@ protected void onDraw(Canvas canvas) { 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); @@ -1452,7 +1604,7 @@ protected void onDraw(Canvas canvas) { 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; @@ -1567,8 +1719,8 @@ protected void onDraw(Canvas canvas) { } 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); @@ -1578,15 +1730,14 @@ protected void onDraw(Canvas canvas) { 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; @@ -1679,10 +1830,15 @@ protected void onDraw(Canvas canvas) { } 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); @@ -1745,6 +1901,14 @@ protected void onDraw(Canvas canvas) { 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; @@ -2288,12 +2452,12 @@ public boolean onTouchEvent(MotionEvent motionEvent) { 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; @@ -2327,10 +2491,10 @@ public boolean onTouchEvent(MotionEvent motionEvent) { 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); @@ -2353,10 +2517,10 @@ public boolean onTouchEvent(MotionEvent motionEvent) { 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); @@ -2375,19 +2539,19 @@ public boolean onTouchEvent(MotionEvent motionEvent) { startedDraggingX = -1; if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); - delegate.needStartRecordVideo(NekoConfig.confirmAVMessage.Bool() ? 3 : 1, true, 0);} else if (!sendVoiceEnabled) { + delegate.needStartRecordVideo(NekoConfig.confirmAVMessage.Bool() ? 3 : 1, true, 0, voiceOnce ? 0x7FFFFFFF : 0);} else if (!sendVoiceEnabled) { delegate.needShowMediaBanHint(); } else { if (!NekoConfig.confirmAVMessage.Bool()) { 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, voiceOnce), () -> MediaController.getInstance().stopRecording(0, false, 0, voiceOnce), resourcesProvider); } } delegate.needStartRecordAudio(0); if (!NekoConfig.confirmAVMessage.Bool()) { - MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0); + MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0, voiceOnce); } else { - MediaController.getInstance().stopRecording(2, true, 0); + MediaController.getInstance().stopRecording(2, true, 0, voiceOnce); } } if (!NekoConfig.confirmAVMessage.Bool()) { @@ -2447,10 +2611,10 @@ public boolean onTouchEvent(MotionEvent motionEvent) { 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); @@ -2468,12 +2632,12 @@ public boolean onTouchEvent(MotionEvent motionEvent) { 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), null); + AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate, voiceOnce), () -> MediaController.getInstance().stopRecording(0, false, 0, voiceOnce), null); } - MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0); + MediaController.getInstance().stopRecording(isInScheduleMode() ? 3 : 1, true, 0, voiceOnce); delegate.needStartRecordAudio(0); } recordingAudioVideo = false; @@ -3197,7 +3361,7 @@ protected void dispatchDraw(Canvas canvas) { 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) { @@ -3572,6 +3736,7 @@ private void createBotWebViewButton() { } private void createRecordCircle() { + createOnceButton(); if (recordCircle != null) { return; } @@ -3580,6 +3745,18 @@ private void createRecordCircle() { 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); @@ -3595,7 +3772,7 @@ private void openWebViewMenu() { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), parentFragment.getResourceProvider()); webViewSheet.setParentActivity(parentActivity); webViewSheet.requestWebView(currentAccount, dialog_id, dialog_id, botMenuWebViewTitle, botMenuWebViewUrl, BotWebViewSheet.TYPE_BOT_MENU_BUTTON, 0, false); - webViewSheet.show(); + parentFragment.showDialog(webViewSheet); if (botCommandsMenuButton != null) { botCommandsMenuButton.setOpened(false); @@ -4705,6 +4882,7 @@ public boolean onTouchEvent(MotionEvent event) { } else { if (clickMaybe) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } if (messageEditText != null && !AndroidUtilities.showKeyboard(messageEditText)) { @@ -4717,6 +4895,7 @@ public boolean onTouchEvent(MotionEvent event) { } else { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (delegate != null) { + fixHandlesColor(); delegate.onKeyboardRequested(); } } @@ -4724,6 +4903,13 @@ public boolean onTouchEvent(MotionEvent event) { } } + /* + * The color of the handles changes when opened PhotoView and write a comment. + */ + private void fixHandlesColor() { + setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); + } + @Override public void setOffsetY(float offset) { super.setOffsetY(offset); @@ -5025,7 +5211,7 @@ public void onAnimationEnd(Animator animation) { } 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); @@ -5313,10 +5499,10 @@ public boolean isRecordLocked() { 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); @@ -6063,6 +6249,17 @@ public void updateFieldHint(boolean animated) { messageEditText.setHintText(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage)); } else if (botKeyboardViewVisible && botButtonsMessageObject != null && botButtonsMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(botButtonsMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(botButtonsMessageObject.messageOwner.reply_markup.placeholder, animated); + } else if (parentFragment != null && parentFragment.isForumInViewAsMessagesMode()) { + if (replyingTopMessage != null && replyingTopMessage.replyToForumTopic != null && replyingTopMessage.replyToForumTopic.title != null) { + messageEditText.setHintText(LocaleController.formatString("TypeMessageIn", R.string.TypeMessageIn, replyingTopMessage.replyToForumTopic.title), animated); + } else { + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(parentFragment.getCurrentChat().id, 1); + if (topic != null && topic.title != null) { + messageEditText.setHintText(LocaleController.formatString("TypeMessageIn", R.string.TypeMessageIn, topic.title), animated); + } else { + messageEditText.setHintText(LocaleController.getString("TypeMessage", R.string.TypeMessage), animated); + } + } } else { boolean isChannel = false; boolean anonymously = false; @@ -6131,27 +6328,35 @@ public void updateFieldHint(boolean animated) { } public void setReplyingMessageObject(MessageObject messageObject, ChatActivity.ReplyQuote quote) { + setReplyingMessageObject(messageObject, quote, null); + } + + public void setReplyingMessageObject(MessageObject messageObject, ChatActivity.ReplyQuote quote, MessageObject replyingTopMessage) { + boolean animated = parentFragment != null && parentFragment.isForumInViewAsMessagesMode() && this.replyingTopMessage != replyingTopMessage; if (messageObject != null) { if (botMessageObject == null && botButtonsMessageObject != replyingMessageObject) { botMessageObject = botButtonsMessageObject; } replyingMessageObject = messageObject; replyingQuote = quote; + this.replyingTopMessage = replyingTopMessage; if (!(parentFragment != null && parentFragment.isTopic && parentFragment.getThreadMessage() == replyingMessageObject)) { setButtons(replyingMessageObject, true); } } else if (replyingMessageObject == botButtonsMessageObject) { replyingMessageObject = null; + this.replyingTopMessage = null; replyingQuote = null; setButtons(botMessageObject, false); botMessageObject = null; } else { replyingMessageObject = null; replyingQuote = null; + this.replyingTopMessage = null; } TL_stories.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; MediaController.getInstance().setReplyingMessage(messageObject, getThreadMessage(), storyItem); - updateFieldHint(false); + updateFieldHint(animated); } public void setWebPage(TLRPC.WebPage webPage, boolean searchWebPages) { @@ -6261,20 +6466,24 @@ private void hideRecordedAudioPanel(boolean wasSent) { 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), - - 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) - ); + 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)); + + 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); @@ -6307,12 +6516,16 @@ public void onAnimationEnd(Animator animation) { } 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 { @@ -6334,16 +6547,19 @@ public void onAnimationEnd(Animator animation) { 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); @@ -6442,6 +6658,9 @@ public void onAnimationEnd(Animator animation) { if (recordPannelAnimation != null) { recordPannelAnimation.start(); } + if (onceButton != null) { + onceButton.invalidate(); + } } private void hideRecordedAudioPanelInternal() { @@ -6530,7 +6749,7 @@ private void sendMessageInternal(boolean notify, int scheduleDate, boolean allow return; } if (videoToSendMessageObject != null) { - delegate.needStartRecordVideo(4, notify, scheduleDate); + delegate.needStartRecordVideo(4, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0); hideRecordedAudioPanel(true); checkSendButton(true); return; @@ -6542,7 +6761,7 @@ private void sendMessageInternal(boolean notify, int scheduleDate, boolean allow if (playing != null && playing == audioToSendMessageObject) { MediaController.getInstance().cleanupPlayer(true, true); } - SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), voiceCaption, null, null, null, notify, scheduleDate, 0, null, null, false); + SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, getThreadMessage(), voiceCaption, null, null, null, notify, scheduleDate, voiceOnce ? 0x7FFFFFFF : 0, null, null, false); voiceCaption = null; applyStoryToSendMessageParams(params); SendMessagesHelper.getInstance(currentAccount).sendMessage(params); @@ -6727,7 +6946,7 @@ public void doneEditingMessage(boolean withMarkdown) { } 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; @@ -6884,9 +7103,9 @@ public boolean processSendingText(CharSequence text, boolean notify, int schedul updateStickersOrder = SendMessagesHelper.checkUpdateStickersOrder(text); MessageObject replyToTopMsg = getThreadMessage(); -// if (parentFragment != null && parentFragment.replyingTopMessage != null) { -// replyToTopMsg = parentFragment.replyingTopMessage; -// } + if (replyToTopMsg == null && replyingTopMessage != null) { + replyToTopMsg = replyingTopMessage; + } SendMessagesHelper.SendMessageParams params = SendMessagesHelper.SendMessageParams.of(message[0].toString(), dialog_id, replyingMessageObject, replyToTopMsg, messageWebPage, messageWebPageSearch, entities, null, null, notify, scheduleDate, sendAnimationData, updateStickersOrder); params.canSendGames = withGame; applyStoryToSendMessageParams(params); @@ -7774,6 +7993,10 @@ protected void updateRecordInterface(int recordState) { if (recordInterfaceState == 1) { return; } + voiceOnce = false; + if (onceButton != null) { + onceButton.periodDrawable.setValue(1, false, false); + } createRecordAudioPanel(); recordInterfaceState = 1; if (emojiView != null) { @@ -7812,6 +8035,9 @@ protected void updateRecordInterface(int recordState) { recordCircle.setVisibility(VISIBLE); recordCircle.setAmplitude(0); } + if (onceButton != null) { + onceButton.setVisibility(delegate != null && delegate.onceVoiceAvailable() ? VISIBLE : GONE); + } if (recordDot != null) { recordDot.resetAlpha(); @@ -7845,6 +8071,9 @@ protected void updateRecordInterface(int recordState) { 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)); } @@ -7962,6 +8191,10 @@ public void onAnimationEnd(Animator animator) { 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), @@ -8180,6 +8413,10 @@ public void onAnimationEnd(Animator animation) { botCommandsMenuButton.setScaleX(0f); botCommandsMenuButton.setScaleY(0f); } + + if (onceButton != null && onceVisible && MessagesController.getGlobalMainSettings().getInt("voiceoncehint", 0) < 3) { + onceButton.showHintView(); + } } }); @@ -8195,6 +8432,10 @@ public void onAnimationEnd(Animator animation) { 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( @@ -8349,6 +8590,10 @@ public void onAnimationEnd(Animator animation) { 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), @@ -8889,10 +9134,6 @@ private void updateRecordedDeleteIconColors() { recordDeleteImageView.setLayerColor("Box Red.**", dotColor); recordDeleteImageView.setLayerColor("Cup Grey.**", greyColor); recordDeleteImageView.setLayerColor("Box Grey.**", greyColor); - - recordDeleteImageView.setLayerColor("Line 1.**", background); - recordDeleteImageView.setLayerColor("Line 2.**", background); - recordDeleteImageView.setLayerColor("Line 3.**", background); } } @@ -9042,7 +9283,7 @@ public CharSequence getFieldText() { } 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() && @@ -9551,7 +9792,11 @@ public void run() { BotWebViewSheet webViewSheet = new BotWebViewSheet(getContext(), resourcesProvider); webViewSheet.setParentActivity(parentActivity); webViewSheet.requestWebView(currentAccount, messageObject.messageOwner.dialog_id, botId, button.text, button.url, button instanceof TLRPC.TL_keyboardButtonSimpleWebView ? BotWebViewSheet.TYPE_SIMPLE_WEB_VIEW_BUTTON : BotWebViewSheet.TYPE_WEB_VIEW_BUTTON, replyMessageObject != null ? replyMessageObject.messageOwner.id : 0, false); - webViewSheet.show(); + if (parentFragment != null) { + parentFragment.showDialog(webViewSheet); + } else { + webViewSheet.show(); + } } }; if (SharedPrefsHelper.isWebViewConfirmShown(currentAccount, botId)) { @@ -9672,6 +9917,21 @@ public void run() { } 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); @@ -9687,20 +9947,17 @@ public void run() { 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; @@ -11483,10 +11740,10 @@ public boolean onTouchEvent(MotionEvent event) { 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); @@ -11512,8 +11769,7 @@ public SlideTextView(@NonNull Context context) { arrowPaint.setStrokeCap(Paint.Cap.ROUND); arrowPaint.setStrokeJoin(Paint.Join.ROUND); - slideToCancelString = LocaleController.getString("SlideToCancel", R.string.SlideToCancel); - slideToCancelString = slideToCancelString.charAt(0) + slideToCancelString.substring(1).toLowerCase(); + slideToCancelString = LocaleController.getString(R.string.SlideToCancel2); cancelString = LocaleController.getString("Cancel", R.string.Cancel).toUpperCase(); @@ -11745,7 +12001,7 @@ protected void onDraw(Canvas canvas) { 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 95ff58109a..897b911e23 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -113,8 +113,6 @@ import org.telegram.ui.PhotoPickerActivity; import org.telegram.ui.PhotoPickerSearchActivity; import org.telegram.ui.PremiumPreviewFragment; -import org.telegram.ui.Stories.DarkThemeResourceProvider; -import org.telegram.ui.Stories.recorder.CaptionContainerView; import org.telegram.ui.WebAppDisclaimerAlert; import java.io.File; @@ -465,6 +463,10 @@ public void setDialogId(long dialogId) { } public interface ChatAttachViewDelegate { + default boolean selectItemOnClicking() { + return false; + } + void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); default void onCameraOpened() { @@ -1141,7 +1143,7 @@ public void setUser(TLRPC.User user) { nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); currentUser = user; nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageView.setForUserOrChat(user, avatarDrawable); imageView.setSize(-1, -1); imageView.setColorFilter(null); @@ -1159,7 +1161,7 @@ public void setAttachBot(TLRPC.User user, TLRPC.TL_attachMenuBot bot) { nameTextView.setTextColor(getThemedColor(Theme.key_dialogTextGray2)); currentUser = user; nameTextView.setText(bot.short_name); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); boolean animated = true; TLRPC.TL_attachMenuBotIcon icon = MediaDataController.getAnimatedAttachMenuBotIcon(bot); @@ -2542,7 +2544,7 @@ public void onAnimationEnd(Animator animation) { 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); // } @@ -2608,7 +2610,7 @@ public void getOutline(View view, Outline outline) { } 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/ChatAttachAlertContactsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java index ae36a6060c..1a738067ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertContactsLayout.java @@ -225,7 +225,7 @@ public void update(int mask) { } if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java index 9dd6216147..7457cf8214 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -805,6 +805,20 @@ public int getSpanSize(int position) { if (position < 0 || position >= arrayList.size()) { return; } + if (parentAlert.delegate != null && parentAlert.delegate.selectItemOnClicking() && arrayList.get(position) instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) arrayList.get(position); + selectedPhotos.clear(); + if (photoEntry != null) { + addToSelectedPhotos(photoEntry, -1); + } + parentAlert.applyCaption(); + parentAlert.delegate.didPressedButton(7, true, true, 0, false); + selectedPhotos.clear(); + cameraPhotos.clear(); + selectedPhotosOrder.clear(); + selectedPhotos.clear(); + return; + } PhotoViewer.getInstance().setParentActivity(fragment, resourcesProvider); PhotoViewer.getInstance().setParentAlert(parentAlert); PhotoViewer.getInstance().setMaxSelectedPhotos(parentAlert.maxSelectedPhotos, parentAlert.allowOrder); @@ -859,7 +873,7 @@ public int getSpanSize(int position) { } int finalPosition = position; BaseFragment finalFragment = fragment; - AndroidUtilities.runOnUIThread(()-> { + AndroidUtilities.runOnUIThread(() -> { int avatarType = type; if (parentAlert.isPhotoPicker) { PhotoViewer.getInstance().setParentActivity(finalFragment); @@ -1485,6 +1499,12 @@ public void showAvatarConstructorFragment(AvatarConstructorPreviewCell view, TLR selectedPhotos.put(-1, photoEntry); selectedPhotosOrder.add(-1); parentAlert.delegate.didPressedButton(7, true, false, 0, false); + if (!avatarConstructorFragment.finishOnDone) { + if (parentAlert.baseFragment != null) { + parentAlert.baseFragment.removeSelfFromStack(); + } + avatarConstructorFragment.finishFragment(); + } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index df8300d619..ed907c2af9 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 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; @@ -53,9 +54,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; import org.telegram.ui.ProfileActivity; -import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.StoriesUtilities; -import org.telegram.ui.Stories.StoryViewer; import org.telegram.ui.TopicsFragment; import java.util.concurrent.atomic.AtomicReference; @@ -65,6 +64,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { public boolean allowDrawStories; + private Integer storiesForceState; public BackupImageView avatarImageView; private SimpleTextView titleTextView; private AtomicReference titleTextLargerCopyView = new AtomicReference<>(); @@ -78,6 +78,7 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent private int currentAccount = UserConfig.selectedAccount; private boolean occupyStatusBar = true; private int leftPadding = AndroidUtilities.dp(8); + private int rightAvatarPadding = 0; StatusDrawable currentTypingDrawable; private int lastWidth = -1; @@ -109,6 +110,10 @@ public void hideSubtitle() { subtitleTextView.setVisibility(View.GONE); } + public void setStoriesForceState(Integer storiesForceState) { + this.storiesForceState = storiesForceState; + } + private class SimpleTextConnectedView extends SimpleTextView { private AtomicReference reference; @@ -143,7 +148,7 @@ public boolean setText(CharSequence value) { public ChatAvatarContainer(Context context, BaseFragment baseFragment, boolean needTime) { this(context, baseFragment, needTime, null); } - + public ChatAvatarContainer(Context context, BaseFragment baseFragment, boolean needTime, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -190,7 +195,10 @@ protected void onDraw(Canvas canvas) { params.drawSegments = true; params.drawInside = true; params.resourcesProvider = resourcesProvider; - StoriesUtilities.drawAvatarWithStory(parentFragment.getDialogId(), canvas, imageReceiver, params); + if (storiesForceState != null) { + params.forceState = storiesForceState; + } + StoriesUtilities.drawAvatarWithStory(parentFragment != null ? parentFragment.getDialogId() : 0, canvas, imageReceiver, params); } else { super.onDraw(canvas); } @@ -486,6 +494,7 @@ private void fadeOutToLessWidth(int largerWidth) { 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()); @@ -529,7 +538,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto int actionBarHeight = ActionBar.getCurrentActionBarHeight(); int viewTop = (actionBarHeight - AndroidUtilities.dp(42)) / 2 + (Build.VERSION.SDK_INT >= 21 && occupyStatusBar ? AndroidUtilities.statusBarHeight : 0); avatarImageView.layout(leftPadding, viewTop + 1, leftPadding + AndroidUtilities.dp(42), viewTop + 1 + AndroidUtilities.dp(42)); - int l = leftPadding + (avatarImageView.getVisibility() == VISIBLE ? AndroidUtilities.dp(54) : 0); + int l = leftPadding + (avatarImageView.getVisibility() == VISIBLE ? AndroidUtilities.dp( 54) : 0) + rightAvatarPadding; SimpleTextView titleTextLargerCopyView = this.titleTextLargerCopyView.get(); if (subtitleTextView.getVisibility() != GONE) { titleTextView.layout(l, viewTop + AndroidUtilities.dp(1.3f) - titleTextView.getPaddingTop(), l + titleTextView.getMeasuredWidth(), viewTop + titleTextView.getTextHeight() + AndroidUtilities.dp(1.3f) - titleTextView.getPaddingTop() + titleTextView.getPaddingBottom()); @@ -556,6 +565,10 @@ public void setLeftPadding(int value) { leftPadding = value; } + public void setRightAvatarPadding(int value) { + rightAvatarPadding = value; + } + public void showTimeItem(boolean animated) { if (timeItem == null || timeItem.getTag() != null || avatarImageView.getVisibility() != View.VISIBLE) { return; @@ -613,16 +626,17 @@ public void setTime(int value, boolean animated) { 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); } } @@ -640,9 +654,9 @@ public void setTitle(CharSequence value, boolean scam, boolean fake, boolean ver 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) { @@ -651,37 +665,34 @@ public void setTitle(CharSequence value, boolean scam, boolean fake, boolean ver 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; + rightDrawableIsScamOrVerified = false; rightDrawableContentDescription = LocaleController.getString("AccDescrPremium", R.string.AccDescrPremium); - } else if (titleTextView.getRightDrawable() instanceof ScamDrawable) { + } else { titleTextView.setRightDrawable(null); -// titleTextView.setRightPadding(0); - rightDrawableIsScamOrVerified = false; rightDrawableContentDescription = null; } } @@ -961,7 +972,7 @@ public int getLastSubtitleColorKey() { } public void setChatAvatar(TLRPC.Chat chat) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); avatarImageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(16) : AndroidUtilities.dp(21)); @@ -973,7 +984,7 @@ public void setUserAvatar(TLRPC.User user) { } public void setUserAvatar(TLRPC.User user, boolean showSelf) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); avatarDrawable.setScaleSize(.8f); @@ -1001,7 +1012,7 @@ public void checkAndUpdateAvatar() { TLRPC.User user = parentFragment.getCurrentUser(); TLRPC.Chat chat = parentFragment.getCurrentChat(); if (user != null) { - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); if (UserObject.isReplyUser(user)) { avatarDrawable.setScaleSize(.8f); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REPLIES); @@ -1021,7 +1032,7 @@ public void checkAndUpdateAvatar() { } } } else if (chat != null) { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); if (avatarImageView != null) { avatarImageView.setForUserOrChat(chat, avatarDrawable); } @@ -1142,6 +1153,10 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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 6dad3210c8..4f2ad0a0bb 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,7 +22,10 @@ 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; import android.view.Gravity; import android.view.MotionEvent; @@ -50,10 +55,12 @@ 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; @@ -65,7 +72,9 @@ 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; @@ -100,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; @@ -112,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; @@ -149,10 +159,10 @@ public ChatThemeBottomSheet(final ChatActivity chatActivity, ChatActivity.ThemeD 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); @@ -168,7 +178,7 @@ public ChatThemeBottomSheet(final ChatActivity chatActivity, ChatActivity.ThemeD 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); @@ -212,7 +222,7 @@ protected int calculateTimeForScrolling(int dx) { 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; @@ -254,7 +264,7 @@ public void run() { 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)); @@ -283,10 +293,19 @@ public void onClick(View v) { 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()); @@ -314,7 +333,13 @@ public void onClick(View v) { 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)); } @@ -325,11 +350,11 @@ public void onClick(View v) { 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)); @@ -338,7 +363,7 @@ private void updateButtonColors() { 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)))); } @@ -356,7 +381,12 @@ private void previewSelectedTheme() { } } + 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); @@ -364,6 +394,7 @@ private void updateState(boolean animated) { 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 { @@ -371,16 +402,30 @@ private void updateState(boolean animated) { 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); @@ -388,11 +433,54 @@ private void updateState(boolean animated) { 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); @@ -432,7 +520,7 @@ public void onError(TLRPC.TL_error error) { 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 { @@ -537,7 +625,7 @@ public void onAnimationProgress(float progress) { } 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)); @@ -549,8 +637,8 @@ public void didSetColor() { } }; 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) { @@ -832,6 +920,35 @@ private void setItemsAnimationProgress(float progress) { } 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) { @@ -1123,11 +1240,159 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { } } + 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; chatAttachAlert.setupPhotoPicker(LocaleController.getString("ChooseBackground", R.string.ChooseBackground)); chatAttachAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + long start; + @Override + public boolean selectItemOnClicking() { + start = System.currentTimeMillis(); + return true; + } + @Override public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { try { @@ -1147,9 +1412,16 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu FileOutputStream stream = new FileOutputStream(currentWallpaperPath); bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.FileWallpaper("", currentWallpaperPath, currentWallpaperPath), bitmap); + ThemePreviewActivity themePreviewActivity = new ThemePreviewActivity(new WallpapersListActivity.FileWallpaper("", currentWallpaperPath, currentWallpaperPath), bitmap) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + themePreviewActivity.boostsStatus = boostsStatus; + themePreviewActivity.setInitialModes(false, false, .20f); themePreviewActivity.setDialogId(chatActivity.getDialogId()); - themePreviewActivity.setDelegate(() -> { + themePreviewActivity.setDelegate(wallPaper -> { chatAttachAlert.dismissInternal(); dismiss(); }); @@ -1163,9 +1435,15 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu @Override public void onWallpaperSelected(Object object) { - ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false); + ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; + wallpaperActivity.boostsStatus = boostsStatus; wallpaperActivity.setDialogId(chatActivity.getDialogId()); - wallpaperActivity.setDelegate(() -> { + wallpaperActivity.setDelegate(wallPaper -> { chatAttachAlert.dismissInternal(); dismiss(); }); @@ -1183,7 +1461,7 @@ public void onWallpaperSelected(Object object) { @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 @@ -1194,12 +1472,12 @@ protected void dispatchDraw(Canvas canvas) { } }; 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)); @@ -1242,6 +1520,27 @@ private void fixColorsAfterAnotherWindow() { } } + 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; @@ -1256,16 +1555,21 @@ public boolean isDark() { } @Override - public void switchDayNight() { + public boolean supportsAnimation() { + return true; + } + + @Override + public void switchDayNight(boolean animated) { forceDark = !forceDark; if (selectedItem != null) { isLightDarkChangeAnimation = true; chatActivity.forceDisallowRedrawThemeDescriptions = true; TLRPC.WallPaper wallpaper = hasChanges() ? null : themeDelegate.getCurrentWallpaper(); if (selectedItem.chatTheme.showAsDefaultStub) { - themeDelegate.setCurrentTheme(null, wallpaper, true, forceDark); + themeDelegate.setCurrentTheme(null, wallpaper, animated, forceDark); } else { - themeDelegate.setCurrentTheme(selectedItem.chatTheme, wallpaper, true, forceDark); + themeDelegate.setCurrentTheme(selectedItem.chatTheme, wallpaper, animated, forceDark); } chatActivity.forceDisallowRedrawThemeDescriptions = false; } @@ -1280,6 +1584,7 @@ public void switchDayNight() { params.onDismiss = () -> { overlayFragment = null; }; + params.occupyNavigationBar = true; overlayFragment = themePreviewActivity; chatActivity.showAsSheet(themePreviewActivity, params); } @@ -1296,5 +1601,12 @@ public static class ChatThemeItem { 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 b886854f12..b8e820c777 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 void setTopPadding(int topPadding) { 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/EditTextEffects.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java index a30c32580a..2407f9fbd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java @@ -151,7 +151,7 @@ public void recycleEmojis() { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - updateAnimatedEmoji(false); + updateAnimatedEmoji(true); invalidateQuotes(false); } @@ -282,7 +282,8 @@ public static boolean allowHackingTextCanvas() { Build.MANUFACTURER == null || !Build.MANUFACTURER.toLowerCase().contains("honor") && !Build.MANUFACTURER.toLowerCase().contains("huawei") && - !Build.MANUFACTURER.toLowerCase().contains("alps") + !Build.MANUFACTURER.toLowerCase().contains("alps") && + !Build.MANUFACTURER.toLowerCase().contains("vivo") ) && ( Build.MODEL == null || !Build.MODEL.toLowerCase().contains("mediapad") diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java index 4381bb967a..16a355fcc5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEmoji.java @@ -242,7 +242,7 @@ public long getCurrentChat() { 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); @@ -287,7 +287,7 @@ protected void dispatchDraw(Canvas canvas) { 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); @@ -378,10 +378,11 @@ public void didReceivedNotification(int id, int account, Object... args) { 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); } } @@ -766,6 +767,7 @@ public void onCustomEmojiSelected(long documentId, TLRPC.Document document, Str if (i < 0) { i = 0; } + try { innerTextChange = 2; SpannableString spannable = new SpannableString(emoticon); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java index 5fd6d0fb4a..a8b574dcda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -96,7 +96,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { public boolean animateAppear = true; - private int accentColor; + private final int accentColor; private Runnable onSettingsOpenRunnable; private boolean wasDrawn; private int animatedEmojiCacheType = AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP; @@ -300,6 +300,9 @@ private void getChildBounds(int i, RectF out) { if (type == SelectAnimatedEmojiDialog.TYPE_TOPIC_ICON) { recentDrawableId = R.drawable.msg_emoji_smiles; } + if(type == SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS) { + recentDrawableId = R.drawable.emoji_love; + } if (includeRecent) { contentView.addView(recentTab = new EmojiTabButton(context, recentDrawableId, false, false)); recentTab.id = (long) "recent".hashCode(); @@ -503,7 +506,7 @@ public void updateEmojiPacks(ArrayList emojiPacks) { currentPackButton.setAnimatedEmojiDocument(thumbDocument); } currentPackButton.updateSelect(selected == i, false); - if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR || currentType == SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { currentPackButton.setLock(null, false); } else if (!isPremium && !free) { currentPackButton.setLock(true, false); @@ -659,7 +662,7 @@ protected ColorFilter getEmojiColorFilter() { } private int selectorColor() { - if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { return Theme.multAlpha(accentColor, .09f); } return Theme.multAlpha(Theme.getColor(Theme.key_chat_emojiPanelIcon, resourcesProvider), .18f); @@ -1000,10 +1003,15 @@ public void onAnimationEnd(Animator animation) { public void updateLockImageReceiver() { if (lockView != null && !lockView.ready() && getDrawable() instanceof AnimatedEmojiDrawable) { - ImageReceiver imageReceiver = ((AnimatedEmojiDrawable) getDrawable()).getImageReceiver(); - if (imageReceiver != null) { - lockView.setImageReceiver(imageReceiver); - lockView.invalidate(); + if (((AnimatedEmojiDrawable) getDrawable()).canOverrideColor()) { + lockView.setImageReceiver(null); + lockView.setColor(accentColor); + } else { + ImageReceiver imageReceiver = ((AnimatedEmojiDrawable) getDrawable()).getImageReceiver(); + if (imageReceiver != null) { + lockView.setImageReceiver(imageReceiver); + lockView.invalidate(); + } } } } @@ -1140,7 +1148,7 @@ public void updateColor() { } private void setColor(int color) { - if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON || currentType == SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM) { color = accentColor; } PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index a7a20edf30..dc94223d17 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -5781,7 +5781,7 @@ private void checkDocuments(boolean isGif) { } } recentStickers = new ArrayList<>(recentStickers.subList(0, Math.min(recentStickers.size(), NekoConfig.maxRecentStickerCount.Int()))); - 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); @@ -7561,7 +7561,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { public int getItemViewType(int position) { if (position == 0) { return VIEW_TYPE_SEARCHFIELD; - } else if (position == 1 && searchWas && result.isEmpty()) { + } else if (position == 1 && searchWas && result.isEmpty() && packs.isEmpty()) { return VIEW_TYPE_HELP; } if (!packs.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java new file mode 100644 index 0000000000..b30784b3fc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilledTabsView.java @@ -0,0 +1,138 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.view.MotionEvent; +import android.view.View; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; + +public class FilledTabsView extends View { + + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private Text[] tabs; + private RectF[] bounds; + + public FilledTabsView(Context context) { + super(context); + + selectedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); + selectedPaint.setColor(0xFFFFFFFF); + } + + public void setTabs(CharSequence ...texts) { + tabs = new Text[texts.length]; + bounds = new RectF[texts.length]; + + for (int i = 0; i < texts.length; ++i) { + tabs[i] = new Text(texts[i], 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + bounds[i] = new RectF(); + } + + invalidate(); + } + + private float selectedTabIndex; + + public void setSelected(float tabIndex) { + if (Math.abs(tabIndex - selectedTabIndex) > 0.001f) { + invalidate(); + } + selectedTabIndex = tabIndex; + } + + private Utilities.Callback onTabClick; + public FilledTabsView onTabSelected(Utilities.Callback onTabClick) { + this.onTabClick = onTabClick; + return this; + } + + @Override + public void setBackgroundColor(int color) { + backgroundPaint.setColor(color); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (tabs == null) { + return; + } + + final int W = getWidth(); + final int H = getHeight(); + + int w = dp(2) + tabs.length * dp(24) + dp(2); + for (int i = 0; i < tabs.length; ++i) + w += tabs[i].getWidth(); + + float top = (H - dp(30)) / 2f, bottom = (H + dp(30)) / 2f; + float x = (W - w) / 2f; + + AndroidUtilities.rectTmp.set(x, top, x + w, bottom); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(15), dp(15), backgroundPaint); + + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + x += dp(2 + 12); + for (int i = 0; i < tabs.length; ++i) { + tabs[i].draw(canvas, x, H / 2f, 0xFFFFFFFF, 1f); + bounds[i].set(x - dp(2 + 12), top, x + tabs[i].getWidth() + dp(12 + 2), bottom); + x += tabs[i].getWidth() + dp(12 + 12); + } + + x = (W - w) / 2f + dp(2); + top = (H - dp(30 - 4)) / 2f; + bottom = (H + dp(30 - 4)) / 2f; + + final int l = Utilities.clamp((int) Math.floor(selectedTabIndex), tabs.length - 1, 0); + final int r = Utilities.clamp((int) Math.ceil(selectedTabIndex), tabs.length - 1, 0); + float left = AndroidUtilities.lerp(bounds[l].left + dp(2), bounds[r].left + dp(2), (float) (selectedTabIndex - Math.floor(selectedTabIndex))); + float right = AndroidUtilities.lerp(bounds[l].right - dp(2), bounds[r].right - dp(2), (float) (selectedTabIndex - Math.floor(selectedTabIndex))); + + AndroidUtilities.rectTmp.set(left, top, right, bottom); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(15), dp(15), selectedPaint); + canvas.restore(); + } + + private int lastPressedIndex = -1; + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (tabs == null || bounds == null) return false; + int index = -1; + for (int i = 0; i < bounds.length; ++i) { + if (bounds[i].contains(event.getX(), event.getY())) { + index = i; + break; + } + } + + if (index >= 0 && index != lastPressedIndex) { + lastPressedIndex = index; + if (onTabClick != null) { + onTabClick.run(index); + } + } + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + lastPressedIndex = -1; + } + if (event.getAction() == MotionEvent.ACTION_DOWN && index >= 0) { + return true; + } + return super.onTouchEvent(event); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java index bc21bd4de5..2b49ba89aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FilterTabsView.java @@ -1845,7 +1845,7 @@ public boolean isLongPressDragEnabled() { @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { - if (!NekoConfig.hideAllTab.Bool() && (!isEditing || (viewHolder.getAdapterPosition() == 0 && tabs.get(0).isDefault && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium()))) { + if (!NekoConfig.hideAllTab.Bool() && (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); @@ -1853,7 +1853,7 @@ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder v @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { - if (!NekoConfig.hideAllTab.Bool() && ((source.getAdapterPosition() == 0 || target.getAdapterPosition() == 0) && !UserConfig.getInstance(UserConfig.selectedAccount).isPremium())) { + if (!NekoConfig.hideAllTab.Bool() && (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 313b3b33a3..3346823e19 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 @@ private void draw(Canvas canvas) { 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 @@ private void loadHeartDrawables() { } } + 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 @@ private Particle createParticle(boolean fall) { 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 boolean isStarted() { 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 void start() { 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 void start() { invalidate(); } + public void start() { + start(false); + } + private void startFall() { if (startedFall) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java index 7e96afaf58..32063ad628 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlatCheckBox.java @@ -30,11 +30,11 @@ public class FlatCheckBox extends View { int colorTextActive; - int HEIGHT = AndroidUtilities.dp(36); + int HEIGHT = AndroidUtilities.dp(37); int INNER_PADDING = AndroidUtilities.dp(22); int TRANSLETE_TEXT = AndroidUtilities.dp(8); - int P = AndroidUtilities.dp(2); + int P = AndroidUtilities.dp(2.5f); RectF rectF = new RectF(); @@ -113,7 +113,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (getMeasuredWidth() != lastW) { rectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - rectF.inset(P + outLinePaint.getStrokeWidth() / 2, P + outLinePaint.getStrokeWidth() / 2 + AndroidUtilities.dp(2)); + rectF.inset(P + outLinePaint.getStrokeWidth() / 2, P + outLinePaint.getStrokeWidth() / 2); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FolderBottomSheet.java index 742895ed1b..a4a4bce6fa 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 static void showForDeletion(final BaseFragment fragment, final int filter 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/Forum/MessageTopicButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java index 466dec1cc3..564fcd2325 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java @@ -94,7 +94,7 @@ public int set(ChatMessageCell cell, MessageObject messageObject, @NonNull TLRPC if (topicClosed) { maxWidth -= AndroidUtilities.dp(18); } - topicNameLayout = StaticLayoutEx.createStaticLayout(title, 0, title.length(), Theme.chat_topicTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false, TextUtils.TruncateAt.END, maxWidth, 2, false); + topicNameLayout = StaticLayoutEx.createStaticLayout(title, Theme.chat_topicTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false, TextUtils.TruncateAt.END, maxWidth, 2, false); topicHeight = AndroidUtilities.dp(4 + 4.5f) + Math.min(AndroidUtilities.dp(24), topicNameLayout == null ? 0 : topicNameLayout.getHeight()); float textWidth = 0; int lineCount = topicNameLayout == null ? 0 : topicNameLayout.getLineCount(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java index 52bba9adb7..c020b6c666 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java @@ -20,6 +20,7 @@ import android.os.Build; import android.os.Handler; import android.os.Message; +import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java index c253edbec5..55a9a6093b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallFullscreenAdapter.java @@ -226,7 +226,7 @@ public void setParticipant(ChatObject.VideoParticipant videoParticipant, TLRPC.T if (peerId > 0) { currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId); currentChat = null; - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); name = UserObject.getFirstName(currentUser); avatarImageView.getImageReceiver().setCurrentAccount(currentAccount); @@ -237,7 +237,7 @@ public void setParticipant(ChatObject.VideoParticipant videoParticipant, TLRPC.T } else { currentChat = AccountInstance.getInstance(currentAccount).getMessagesController().getChat(-peerId); currentUser = null; - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); if (currentChat != null) { name = currentChat.title; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java index 90c56efe65..17779ef95f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java @@ -284,7 +284,7 @@ protected void onAttachedToWindow() { Theme.getColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(service.getChat().id)]), Theme.getColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(service.getChat().id)]) ); - avatarDrawable.setInfo(service.getChat()); + avatarDrawable.setInfo(currentAccount, service.getChat()); avatarImageView.setImage(ImageLocation.getForLocal(service.getChat().photo.photo_small), "50_50", avatarDrawable, null); String titleStr; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java index 410a4774b2..24d9552127 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCreateSpan.java @@ -18,16 +18,12 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.text.Layout; -import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.ReplacementSpan; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java index 0130fa9d8e..e8a323d91a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -652,7 +652,7 @@ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, final int width, @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (cameraThread != null) { - cameraThread.shutdown(0); + cameraThread.shutdown(0, 0); cameraThread = null; } if (cameraSession != null) { @@ -767,7 +767,7 @@ public void changeVideoPreviewState(int state, float progress) { } } - public void send(int state, boolean notify, int scheduleDate) { + public void send(int state, boolean notify, int scheduleDate, int ttl) { if (textureView == null) { return; } @@ -805,7 +805,9 @@ public void send(int state, boolean notify, int scheduleDate) { 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); } @@ -830,7 +832,7 @@ public void send(int state, boolean notify, int scheduleDate) { send = 1; } saveLastCameraBitmap(); - cameraThread.shutdown(send); + cameraThread.shutdown(send, ttl); cameraThread = null; } if (cancelled) { @@ -873,7 +875,7 @@ public void cancel(boolean byGesture) { 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) { @@ -1564,7 +1566,7 @@ public void handleMessage(Message inputMessage) { case DO_SHUTDOWN_MESSAGE: finish(); if (recording) { - videoEncoder.stopRecording(inputMessage.arg1); + videoEncoder.stopRecording(inputMessage.arg1, inputMessage.arg2); } Looper looper = Looper.myLooper(); if (looper != null) { @@ -1638,10 +1640,10 @@ public void handleMessage(Message inputMessage) { } } - 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); } } @@ -1684,7 +1686,7 @@ public void handleMessage(Message inputMessage) { encoder.prepareEncoder(); } catch (Exception e) { FileLog.e(e); - encoder.handleStopRecording(0); + encoder.handleStopRecording(0, 0); Looper.myLooper().quit(); } break; @@ -1693,7 +1695,7 @@ public void handleMessage(Message inputMessage) { if (BuildVars.LOGS_ENABLED) { FileLog.e("InstantCamera stop encoder"); } - encoder.handleStopRecording(inputMessage.arg1); + encoder.handleStopRecording(inputMessage.arg1, inputMessage.arg2); break; } case MSG_VIDEOFRAME_AVAILABLE: { @@ -1779,6 +1781,7 @@ private class VideoRecorder implements Runnable { private boolean ready; private volatile boolean running; private volatile int sendWhenDone; + private volatile int sendWhenDoneTTL; private long skippedTime; private boolean skippedFirst; @@ -1903,7 +1906,7 @@ public void run() { } catch (Exception e) { FileLog.e(e); } - handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, 0)); + handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, sendWhenDone, sendWhenDoneTTL)); } }; @@ -1952,8 +1955,8 @@ public void startRecording(File outputFile, android.opengl.EGLContext sharedCont 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); }); @@ -2281,10 +2284,11 @@ public void run() { } } - 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; } @@ -2376,13 +2380,17 @@ private void handleStopRecording(final int send) { 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 f3e93b2ed3..305ddf82d8 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 void invalidateSelf() { } } - 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/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java index 41a344bc75..954dba51da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -538,7 +538,7 @@ public int getBottomOffset(int tag) { hideFloatingButton(true, false); } - sharedMediaLayout = new SharedMediaLayout(context, dialogId, sharedMediaPreloader, 0, null, currentChatInfo, currentUserInfo, false, this, new SharedMediaLayout.Delegate() { + sharedMediaLayout = new SharedMediaLayout(context, dialogId, sharedMediaPreloader, 0, null, currentChatInfo, currentUserInfo, initialTab, this, new SharedMediaLayout.Delegate() { @Override public void scrollToSharedMedia() { @@ -784,7 +784,7 @@ protected void onTabScroll(boolean scrolling) { TLRPC.User user = getMessagesController().getUser(encryptedChat.user_id); if (user != null) { nameTextView[0].setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarObject = user; } } @@ -797,7 +797,7 @@ protected void onTabScroll(boolean scrolling) { avatarDrawable.setScaleSize(.8f); } else { nameTextView[0].setText(ContactsController.formatName(user.first_name, user.last_name)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarObject = user; } } @@ -805,7 +805,7 @@ protected void onTabScroll(boolean scrolling) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null) { nameTextView[0].setText(chat.title); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarObject = chat; } } @@ -938,7 +938,7 @@ private void updateMediaCount() { return; } - if (id < 0 || mediaCount[id] < 0) { + if (id < 0 || id < mediaCount.length && mediaCount[id] < 0) { return; } if (id == SharedMediaLayout.TAB_PHOTOVIDEO) { @@ -965,6 +965,10 @@ private void updateMediaCount() { } else if (id == SharedMediaLayout.TAB_GIF) { showSubtitle(i, true, true); subtitleTextView[i].setText(LocaleController.formatPluralString("GIFs", mediaCount[MediaDataController.MEDIA_GIF]), animated); + } else if (id == SharedMediaLayout.TAB_RECOMMENDED_CHANNELS) { + showSubtitle(i, true, true); + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(-dialogId); + subtitleTextView[i].setText(LocaleController.formatPluralString("Channels", rec == null ? 0 : rec.more + rec.chats.size()), animated); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MenuToItemOptions.java index fa892ea4ef..c388ecd0e5 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 MenuToItemOptions(@NonNull ItemOptions itemOptions, @NonNull Utilities.Ca @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/MessageContainsEmojiButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java index ac1f16f655..810bc0b267 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java @@ -4,6 +4,8 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.text.Layout; import android.text.Spannable; @@ -136,7 +138,7 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i } }, 0, emoji.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); emojiDrawable = AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, document); - emojiDrawable.setColorFilter(Theme.getAnimatedEmojiColorFilter(resourcesProvider)); + emojiDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider), PorterDuff.Mode.SRC_IN)); emojiDrawable.addView(this); SpannableString stickerPack = new SpannableString(stickerPackName); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessagePreviewView.java index 6fad4fcf07..a4c57f5405 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 void updateBackground() { 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 void updateBackground() { 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 4cade21772..de8d17479b 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 MotionBackgroundDrawable() { } 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 MotionBackgroundDrawable(int c1, int c2, int c3, int c4, int rotation, bo @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 89739fc33d..315825bf14 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 @@ -66,6 +66,9 @@ default void onEntityDragMultitouchEnd() {} default void onEntityDragEnd(boolean delete) {} default void onEntityDragTrash(boolean enter) {} default void onEntityHandleTouched() {} + default boolean isEntityDeletable() { + return true; + } } private float previousLocationX, previousLocationY; @@ -226,7 +229,11 @@ private boolean onTouchMove(float x1, float y1, boolean multitouch, float x2, fl 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); @@ -712,7 +719,7 @@ private void rotateInternal(float angle) { updateSelectionView(); } - protected Rect getSelectionBounds() { + public Rect getSelectionBounds() { return new Rect(0, 0, 0, 0); } @@ -1005,16 +1012,28 @@ private void updateTrash(boolean enter) { } } + public boolean trashCenter() { + 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) { View p = (View) getParent(); - float px = p.getWidth() / 2f - getX(); - float py = p.getHeight() - dp(76) - getY(); - canvas.scale(trashScale, trashScale, px, py); + if (trashCenter()) { + canvas.scale(trashScale, trashScale, getWidth() / 2f, getHeight() / 2f); + } else { + float px = p.getWidth() / 2f - getX(); + float py = p.getHeight() - dp(76) - getY(); + canvas.scale(trashScale, trashScale, px, py); + } } super.dispatchDraw(canvas); canvas.restore(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index 395a64c799..c3f5fb9275 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.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.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.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; @@ -44,12 +49,14 @@ import androidx.dynamicanimation.animation.SpringForce; 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; @@ -61,15 +68,18 @@ 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; @@ -88,12 +98,19 @@ 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 { @@ -124,6 +141,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; @@ -436,7 +454,7 @@ protected void onDraw(Canvas canvas) { 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(); @@ -445,7 +463,7 @@ protected void onDraw(Canvas canvas) { 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); @@ -470,6 +488,19 @@ protected void onDraw(Canvas canvas) { 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; } @@ -1367,7 +1398,7 @@ private void openStickersView() { EmojiBottomSheet emojiBottomSheet = new EmojiBottomSheet(getContext(), false, resourcesProvider) { @Override public boolean canShowWidget(Integer id) { - return false; + return id == WIDGET_PHOTO; } }; emojiBottomSheet.whenDocumentSelected((parentObject, document, isGif) -> { @@ -1376,6 +1407,11 @@ public boolean canShowWidget(Integer id) { stickerView.setScale(1.5f); } }); + emojiBottomSheet.whenWidgetSelected(widget -> { + if (widget == EmojiBottomSheet.WIDGET_PHOTO) { + showPhotoAlert(); + } + }); emojiBottomSheet.setOnDismissListener(di -> { onOpenCloseStickersAlert(false); switchTab(wasSelectedIndex); @@ -1384,6 +1420,132 @@ public boolean canShowWidget(Integer id) { 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() {} @@ -1430,6 +1592,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); @@ -1493,6 +1660,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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()); } @@ -1708,6 +1878,23 @@ public Bitmap getBitmap(ArrayList entities, Bitmap[ 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; } @@ -2528,6 +2715,30 @@ private void showMenuForEntity(final EntityView entityView) { }); 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(); @@ -2811,6 +3022,9 @@ private void removeEntity(EntityView entityView) { } private void registerRemovalUndo(final EntityView entityView) { + if (entityView == null) { + return; + } undoStore.registerUndo(entityView.getUUID(), () -> removeEntity(entityView)); } @@ -3375,4 +3589,64 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + + 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 e58a66dfd7..347aa67bda 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 @@ protected float getMaxScale() { } @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 0000000000..e357f7460e --- /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 f096b18d40..220a685345 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.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 @@ protected void onDraw(Canvas canvas) { private boolean mirrored = false; private final AnimatedFloat mirrorT; private Size baseSize; + private boolean overridenSegmented = false; + + private int orientation, invert; + + private boolean segmented = false; + private AnimatedFloat segmentedT; - private FrameLayoutDrawer containerView; - public final ImageReceiver centerImage = new ImageReceiver(); + 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 PhotoView(Context context, Point position, float angle, float scale, Size 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 PhotoView(Context context, Point position, float angle, float scale, Size 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 void mirror(boolean animated) { 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 @@ protected void updatePosition() { 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 @@ protected void stickerDraw(Canvas canvas) { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } @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 PhotoViewSelectionView(Context context) { @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 @@ protected void onDraw(Canvas canvas) { 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 @@ protected void onDraw(Canvas canvas) { 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 6982f1ddc0..1c50712edf 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 int getPadding() { } @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 new file mode 100644 index 0000000000..41ec51869f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/RoundView.java @@ -0,0 +1,285 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Size; + +public class RoundView extends EntityView { + + private int anchor = -1; + private boolean mirrored = false; + private final AnimatedFloat mirrorT; + private Size baseSize; + + public TextureView textureView; + private FrameLayout.LayoutParams textureViewParams; + + public Bitmap thumbBitmap; + public final Rect src = new Rect(), dst = new Rect(); + + public RoundView(Context context, Point position, float angle, float scale, Size baseSize, String thumbPath) { + super(context, position); + setRotation(angle); + setScale(scale); + + this.baseSize = baseSize; + + thumbBitmap = BitmapFactory.decodeFile(thumbPath); + if (thumbBitmap != null) { + a = (float) thumbBitmap.getWidth() / thumbBitmap.getHeight(); + src.set(0, 0, thumbBitmap.getWidth(), thumbBitmap.getHeight()); + } + + textureView = new TextureView(context); + addView(textureView, textureViewParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + mirrorT = new AnimatedFloat(this, 0, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + + updatePosition(); + setWillNotDraw(false); + } + + private float a = 1.0f; + public void resizeTextureView(int w, int h) { + final float na = (float) w / h; + if (Math.abs(a - na) >= 0.0001f) { + a = na; + requestLayout(); + } + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int w = (int) baseSize.width; + final int h = (int) baseSize.height; + if (textureView != null) { + textureView.measure( + MeasureSpec.makeMeasureSpec(a >= 1.0f ? (int) (a * h) : w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(a >= 1.0f ? h : (int) (w / a), MeasureSpec.EXACTLY) + ); + } + setMeasuredDimension(w, h); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (textureView != null) { + final int t = ((bottom - top) - textureView.getMeasuredHeight()) / 2; + final int l = ((right - left) - textureView.getMeasuredWidth()) / 2; + textureView.layout(l, t, l + textureView.getMeasuredWidth(), t + textureView.getMeasuredHeight()); + } + } + + private final Path clipPath = new Path(); + + private boolean draw = true; + public void setDraw(boolean draw) { + if (this.draw != draw) { + this.draw = draw; + invalidate(); + } + } + + private boolean shown = true; + private AnimatedFloat shownT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + public void setShown(boolean shown, boolean animated) { + if (this.shown != shown) { + this.shown = shown; + if (!animated) { + shownT.set(shown, true); + } + invalidate(); + } + } + + private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (!draw) { + return false; + } + if (child == textureView) { + canvas.save(); + float mirrorT = this.mirrorT.set(mirrored); + canvas.scale(1 - mirrorT * 2, 1f, getMeasuredWidth() / 2f, 0); + canvas.skew(0, 4 * mirrorT * (1f - mirrorT) * .25f); + + final float show = shownT.set(shown); + + final float cx = child.getX() + child.getWidth() / 2f, cy = child.getY() + child.getHeight() / 2f, r = Math.min(child.getWidth() / 2f, child.getHeight() / 2f); + + if (show < 1) { + canvas.saveLayerAlpha(child.getX(), child.getY(), child.getX() + child.getWidth(), child.getY() + child.getHeight(), 0x80, Canvas.ALL_SAVE_FLAG); + clipPath.rewind(); + clipPath.addCircle(cx, cy, r, Path.Direction.CW); + canvas.clipPath(clipPath); + if (thumbBitmap != null) { + dst.set(0, 0, child.getWidth(), child.getHeight()); + canvas.drawBitmap(thumbBitmap, src, dst, null); + } + super.drawChild(canvas, child, drawingTime); + canvas.restore(); + } + + canvas.save(); + clipPath.rewind(); + clipPath.addCircle(cx, cy, r * show, Path.Direction.CW); + canvas.clipPath(clipPath); + if (thumbBitmap != null) { + dst.set(0, 0, child.getWidth(), child.getHeight()); + canvas.drawBitmap(thumbBitmap, src, dst, null); + } + final boolean res; + if (getParent() instanceof EntitiesContainerView && ((EntitiesContainerView) getParent()).drawForThumb) { + res = true; + } else { + res = super.drawChild(canvas, child, drawingTime); + } + + canvas.restore(); + + canvas.restore(); + return res; + } + return super.drawChild(canvas, child, drawingTime); + } + + public int getAnchor() { + return anchor; + } + + public void mirror() { + mirror(false); + } + + public void mirror(boolean animated) { + mirrored = !mirrored; + if (!animated) { + mirrorT.set(mirrored, true); + } + invalidate(); + } + + public boolean isMirrored() { + return mirrored; + } + + protected void updatePosition() { + float halfWidth = baseSize.width / 2.0f; + float halfHeight = baseSize.height / 2.0f; + setX(getPositionX() - halfWidth); + setY(getPositionY() - halfHeight); + updateSelectionView(); + } + + @Override + public org.telegram.ui.Components.Rect getSelectionBounds() { + ViewGroup parentView = (ViewGroup) getParent(); + if (parentView == null) { + return new org.telegram.ui.Components.Rect(); + } + float scale = parentView.getScaleX(); + float width = getMeasuredWidth() * getScale() + AndroidUtilities.dp(64) / scale; + float height = getMeasuredHeight() * getScale() + AndroidUtilities.dp(64) / scale; + float left = (getPositionX() - width / 2.0f) * scale; + float right = left + width * scale; + return new org.telegram.ui.Components.Rect(left, (getPositionY() - height / 2.0f) * scale, right - left, height * scale); + } + + @Override + protected SelectionView createSelectionView() { + return new RoundViewSelectionView(getContext()); + } + + public Size getBaseSize() { + return baseSize; + } + + public class RoundViewSelectionView extends SelectionView { + + public RoundViewSelectionView(Context context) { + super(context); + } + + @Override + protected int pointInsideHandle(float x, float y) { + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dp(19.5f); + + float inset = radius + thickness; + float middle = inset + (getMeasuredHeight() - inset * 2) / 2.0f; + + if (x > inset - radius && y > middle - radius && x < inset + radius && y < middle + radius) { + return SELECTION_LEFT_HANDLE; + } else if (x > inset + (getMeasuredWidth() - inset * 2) - radius && y > middle - radius && x < inset + (getMeasuredWidth() - inset * 2) + radius && y < middle + radius) { + return SELECTION_RIGHT_HANDLE; + } + + float selectionRadius = getMeasuredWidth() / 2.0f; + + if (Math.pow(x - selectionRadius, 2) + Math.pow(y - selectionRadius, 2) < Math.pow(selectionRadius, 2)) { + return SELECTION_WHOLE_HANDLE; + } + + return 0; + } + + private final RectF arcRect = new RectF(); + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dpf2(5.66f); + + float inset = radius + thickness + AndroidUtilities.dp(15); + float mainRadius = getMeasuredWidth() / 2f - inset; + + arcRect.set(inset, inset, inset + mainRadius * 2, inset + mainRadius * 2); + canvas.drawArc(arcRect, 0, 180, false, paint); + canvas.drawArc(arcRect, 180, 180, false, paint); + + canvas.drawCircle(inset, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius, dotStrokePaint); + canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.restoreToCount(count); + } + } + + @Override + public boolean trashCenter() { + return true; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java index 97119d0495..ce80842776 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } @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 25a7decd0b..41386272b3 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 void updateColor() { } @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/PhonebookShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java index 5f984365f4..e1e60b6446 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhonebookShareAlert.java @@ -112,7 +112,7 @@ public UserCell(Context context) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(30)); - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); BackupImageView avatarImageView = new BackupImageView(context); avatarImageView.setRoundRadius(AndroidUtilities.dp(40)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index fbb2324978..fe243f93ea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -373,7 +373,7 @@ public void onAnimationEnd(Animator animation) { 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); @@ -400,7 +400,7 @@ public void onAnimationEnd(Animator animation) { 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/PollVotesAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java index 9295aab8d3..fc539d416a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PollVotesAlert.java @@ -400,14 +400,14 @@ public void update(int mask) { } if (currentUser != null) { - avatarDrawable.setInfo(currentUser); + avatarDrawable.setInfo(currentAccount, currentUser); if (currentUser.status != null) { lastStatus = currentUser.status.expires; } else { lastStatus = 0; } } else if (currentChat != null) { - avatarDrawable.setInfo(currentChat); + avatarDrawable.setInfo(currentAccount, currentChat); } if (currentUser != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java index 51a304f288..1ee2bb14d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java @@ -324,6 +324,11 @@ public Adapter(int currentAccount, boolean drawHeader, Theme.ResourcesProvider r LocaleController.formatString("ConnectedAccountsLimitSubtitle", R.string.ConnectedAccountsLimitSubtitle, 4), 16, 4 )); + limits.add(new Limit( + LocaleController.getString(R.string.SimilarChannelsLimitTitle), + LocaleController.formatString(R.string.SimilarChannelsLimitSubtitle, messagesController.recommendedChannelsLimitPremium), + messagesController.recommendedChannelsLimitDefault, messagesController.recommendedChannelsLimitPremium + )); rowCount = 0; headerRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java index 236cdfe089..f150719434 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java @@ -18,7 +18,7 @@ public class HelloParticles { - private static String[] hellos = new String[] { + private static final String[] hellos = new String[] { "Hello", "Привіт", "Привет", "Bonjour", "Hola", "Ciao", "Olá", "여보세요", "你好", "Salve", "Sveiki", "Halo", "გამარჯობა", "Hallå", "Salam", "Tere", "Dia dhuit", "こんにちは", "Сайн уу", "Bongu", "Ahoj", "γεια", "Zdravo", "नमस्ते", "Habari", "Hallo", "ជំរាបសួរ", "مرحبًا", "ನಮಸ್ಕಾರ", @@ -120,12 +120,7 @@ private class Particle { float inProgress; public void draw(Canvas canvas, int index, long time) { - if (!paused) { - float speed = AndroidUtilities.dp(4) * (dt / 660f) * speedScale; -// x += vecX * speed; -// y += vecY * speed; - if (inProgress != 1f) { inProgress += dt / duration; if (inProgress > 1f) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 3be324633c..a06c831e85 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -17,6 +17,7 @@ import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.style.RelativeSizeSpan; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; @@ -100,7 +101,7 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in setIconValue(currentValue, false); - limitIcon.setPadding(dp(24), dp(6), dp(24), dp(14)); + limitIcon.setPadding(dp(19), dp(6), dp(19), dp(14)); addView(limitIcon, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.LEFT)); } @@ -269,7 +270,8 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { public void setIconValue(int currentValue, boolean animated) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); - spannableStringBuilder.append("d ").setSpan(new ColoredImageSpan(icon), 0, 1, 0); + spannableStringBuilder.append("d").setSpan(new ColoredImageSpan(icon), 0, 1, 0); + spannableStringBuilder.append(" ").setSpan(new RelativeSizeSpan(0.8f), 1, 2, 0); spannableStringBuilder.append(Integer.toString(currentValue)); limitIcon.setText(spannableStringBuilder, animated); limitIcon.requestLayout(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java index b1c1aa414e..573dbce89b 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.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,16 +58,17 @@ 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; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.ChatActivity; +import org.telegram.ui.ChatEditActivity; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BottomSheetWithRecyclerListView; -import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -80,12 +82,16 @@ import org.telegram.ui.Components.Premium.boosts.BoostPagerBottomSheet; import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.Components.Premium.boosts.ReassignBoostBottomSheet; +import org.telegram.ui.Components.Reactions.ChatCustomReactionsEditActivity; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; +import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.ChannelBoostUtilities; +import org.telegram.ui.Stories.DarkThemeResourceProvider; import org.telegram.ui.Stories.recorder.StoryRecorder; import java.util.ArrayList; @@ -116,6 +122,13 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView imp public static final int TYPE_BOOSTS_FOR_POSTING = 18; public static final int TYPE_BOOSTS_FOR_USERS = 19; public static final int TYPE_BOOSTS_FOR_COLOR = 20; + public static final int TYPE_BOOSTS_FOR_REACTIONS = 21; + 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; @@ -166,6 +179,81 @@ public static String limitTypeToServerString(int type) { 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; @@ -189,6 +277,7 @@ public static String limitTypeToServerString(int type) { private TLRPC.Chat fromChat; FireworksOverlay fireworksOverlay; Runnable statisticClickRunnable; + private int requiredLvl = 0; public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(fragment, false, hasFixedSize(type), false, resourcesProvider); @@ -208,8 +297,21 @@ public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, fireworksOverlay = new FireworksOverlay(getContext()); container.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_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); @@ -242,7 +344,17 @@ public void invalidate() { } }; - 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) { @@ -297,7 +409,7 @@ protected void onDraw(Canvas canvas) { 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)); @@ -374,12 +486,12 @@ protected void onDraw(Canvas canvas) { AvatarDrawable fromAvatarDrawable = new AvatarDrawable(); TLRPC.Chat fromChat = MessagesController.getInstance(currentAccount).getChat(-canApplyBoost.replaceDialogId); - fromAvatarDrawable.setInfo(fromChat); + fromAvatarDrawable.setInfo(currentAccount, fromChat); fromAvatar.setForUserOrChat(fromChat, fromAvatarDrawable); AvatarDrawable toAvatarDrawable = new AvatarDrawable(); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); - toAvatarDrawable.setInfo(chat); + toAvatarDrawable.setInfo(currentAccount, chat); toAvatar.setForUserOrChat(chat, toAvatarDrawable); AlertDialog.Builder builder = new AlertDialog.Builder(context); @@ -396,12 +508,22 @@ protected void onDraw(Canvas canvas) { } return; } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_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; } @@ -429,7 +551,7 @@ protected void onDraw(Canvas canvas) { } } else { if (canApplyBoost.alreadyActive && BoostRepository.isMultiBoostsAvailable() && !canApplyBoost.isMaxLvl) { - BoostDialogs.showMoreBoostsNeeded(dialogId); + BoostDialogs.showMoreBoostsNeeded(dialogId, this); } else { dismiss(); } @@ -563,6 +685,10 @@ private void sendInviteMessages() { dismiss(); } + public void setRequiredLvl(int requiredLvl) { + this.requiredLvl = requiredLvl; + } + public void updatePremiumButtonText() { if (type == TYPE_BOOSTS_FOR_USERS) { if (BoostRepository.isMultiBoostsAvailable()) { @@ -575,12 +701,22 @@ public void updatePremiumButtonText() { } else { premiumButtonView.buttonTextView.setText(LocaleController.getString("BoostChannel", R.string.BoostChannel)); } - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { + } else if ( + type == TYPE_BOOSTS_FOR_POSTING || + type == TYPE_BOOSTS_FOR_COLOR || + type == TYPE_BOOSTS_FOR_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 { @@ -688,21 +824,40 @@ private void updateButton() { } 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) { - 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 @@ -710,6 +865,7 @@ public void onAttachedToWindow() { super.onAttachedToWindow(); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.boostByChannelCreated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.boostedChannelByUser); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didStartedMultiGiftsSelector); } @Override @@ -717,6 +873,7 @@ public void onDetachedFromWindow() { super.onDetachedFromWindow(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.boostByChannelCreated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.boostedChannelByUser); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didStartedMultiGiftsSelector); } @Override @@ -724,6 +881,28 @@ public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.boostByChannelCreated) { TLRPC.Chat chat = (TLRPC.Chat) args[0]; boolean isGiveaway = (boolean) args[1]; + BaseFragment lastFragment = getBaseFragment().getParentLayout().getLastFragment(); + if (lastFragment instanceof ChatCustomReactionsEditActivity) { + List fragmentStack = getBaseFragment().getParentLayout().getFragmentStack(); + BaseFragment chatEditFragment = fragmentStack.size() >= 2 ? fragmentStack.get(fragmentStack.size() - 2) : null; + BaseFragment profileFragment = fragmentStack.size() >= 3 ? fragmentStack.get(fragmentStack.size() - 3) : null; + BaseFragment chatFragment = fragmentStack.size() >= 4 ? fragmentStack.get(fragmentStack.size() - 4) : null; + if (chatEditFragment instanceof ChatEditActivity) { + getBaseFragment().getParentLayout().removeFragmentFromStack(chatEditFragment); + } + dismiss(); + if (isGiveaway) { + if (profileFragment instanceof ProfileActivity) { + getBaseFragment().getParentLayout().removeFragmentFromStack(profileFragment); + } + lastFragment.finishFragment(); + BoostDialogs.showBulletin(chatFragment, chat, true); + } else { + lastFragment.finishFragment(); + BoostDialogs.showBulletin(profileFragment, chat, false); + } + return; + } if (isGiveaway) { if (StoryRecorder.isVisible()) { ChatActivity chatFragment = ChatActivity.of(-chat.id); @@ -773,10 +952,23 @@ public void didReceivedNotification(int id, int account, Object... args) { 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() { @@ -785,7 +977,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { 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 @@ -794,8 +986,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int 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); @@ -826,7 +1019,11 @@ public void onClick(@NonNull View view) { arrow.setSpan(span, 0, arrow.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(TextUtils.concat(text, " ", AndroidUtilities.replaceCharSequence(">", link, arrow))); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + if (resourcesProvider instanceof DarkThemeResourceProvider) { + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + } else { + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + } textView.setGravity(Gravity.CENTER_HORIZONTAL); textView.setOnClickListener(v -> BoostPagerBottomSheet.show(getBaseFragment(), dialogId, resourcesProvider)); orDividerView.setOnClickListener(v -> textView.performClick()); @@ -836,10 +1033,14 @@ public void onClick(@NonNull View view) { 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); @@ -866,10 +1067,10 @@ public void onClick(@NonNull View view) { 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) { @@ -880,17 +1081,17 @@ public void onClick(View v) { } }, 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); @@ -898,7 +1099,7 @@ public void onClick(View v) { flickerLoadingView.setItemsCount(10); view = flickerLoadingView; break; - case 6: + case VIEW_TYPE_SPACE16DP: view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -913,68 +1114,79 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @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)); + 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); + } + 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 { - headerCell.setText(LocaleController.getString("ChannelInviteViaLinkRestricted3", R.string.ChannelInviteViaLinkRestricted3)); + 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)); } - } 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_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; } } @@ -1017,6 +1229,7 @@ public void setDialogId(long dialogId) { public void setBoostsStats(TL_stories.TL_premium_boostsStatus boostsStatus, boolean isCurrentChat) { this.boostsStatus = boostsStatus; this.isCurrentChat = isCurrentChat; + updateRows(); } public void setCanApplyBoost(ChannelBoostsController.CanApplyBoost canApplyBoost) { @@ -1040,12 +1253,12 @@ private class HeaderView extends LinearLayout { 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) { @@ -1063,9 +1276,41 @@ public HeaderView(Context context) { } } 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); } else if (type == TYPE_ADD_MEMBERS_RESTRICTED) { premiumLocked = true; if (!canSendLink) { @@ -1147,7 +1392,19 @@ public HeaderView(Context context) { percent = defaultLimit / (float) premiumLimit; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + 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; } @@ -1160,7 +1417,7 @@ public void invalidate() { super.invalidate(); } }; - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + if (boostsType) { if (boostsStatus != null) { limitPreviewView.setBoosts(boostsStatus, canApplyBoost != null && canApplyBoost.boostedNow); } @@ -1187,7 +1444,7 @@ public void invalidate() { limitPreviewView.setDelayedAnimation(); } - addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0, 0)); + addView(limitPreviewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, -4, 0, -4, 0)); title = new TextView(context); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -1199,8 +1456,20 @@ public void invalidate() { } else { title.setText(LocaleController.getString("BoostingIncreaseLevel", R.string.BoostingIncreaseLevel)); } + } else if (type == TYPE_BOOSTS_FOR_REACTIONS) { + title.setText(LocaleController.getString(R.string.ReactionCustomReactions)); } else if (type == TYPE_BOOSTS_FOR_COLOR) { title.setText(LocaleController.getString(R.string.BoostingEnableColor)); + } else if (type == TYPE_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)); @@ -1224,8 +1493,8 @@ public void invalidate() { titleLinearLayout.setOrientation(HORIZONTAL); titleLinearLayout.setWeightSum(1f); titleLinearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 1, 0)); - titleLinearLayout.addView(boostCounterView); - addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, premiumLocked ? 8 : 22, 12, 10)); + titleLinearLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 2, 0, 0)); + addView(titleLinearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, premiumLocked ? 8 : 22, 12, 9)); } else { addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, premiumLocked ? 8 : 22, 0, 0)); @@ -1239,7 +1508,7 @@ public void invalidate() { backupImageView.setRoundRadius(AndroidUtilities.dp(14)); TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); backupImageView.setForUserOrChat(chat, avatarDrawable); frameLayout.addView(backupImageView, LayoutHelper.createFrame(28, 28)); TextView textView = new TextView(getContext()); @@ -1254,9 +1523,14 @@ public void invalidate() { frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 36, 0, 12, 0)); rootLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, Gravity.BOTTOM, 18, 0, 18, 0)); + + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(100); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + rootLayout.setLayoutTransition(layoutTransition); rootLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, -30, 2, 18, 0)); - addView(rootLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 38, Gravity.CENTER, 0, 0, 0, 12)); + addView(rootLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 38, Gravity.CENTER, 0, -4, 0, 12)); ScaleStateListAnimator.apply(rootLayout); rootLayout.setOnClickListener(v -> { getBaseFragment().presentFragment(ChatActivity.of(dialogId)); @@ -1270,13 +1544,17 @@ public void invalidate() { description.setText(AndroidUtilities.replaceTags(descriptionStr)); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); description.setGravity(Gravity.CENTER_HORIZONTAL); + description.setLineSpacing(description.getLineSpacingExtra(), description.getLineSpacingMultiplier() * 1.1f); if (type == TYPE_BOOSTS_FOR_POSTING) { description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); } else { description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); } - addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); - + if (type == TYPE_BOOSTS_FOR_USERS) { + addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, -2, 24, 17)); + } else { + addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); + } updatePremiumButtonText(); } @@ -1293,8 +1571,8 @@ public void recreateTitleAndDescription() { titleLinearLayout.setOrientation(HORIZONTAL); titleLinearLayout.setWeightSum(1f); titleLinearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 1, 0)); - titleLinearLayout.addView(boostCounterView); - addView(titleLinearLayout, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, 22, 12, 10)); + titleLinearLayout.addView(boostCounterView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 0, 2, 0, 0)); + addView(titleLinearLayout, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12 + 13, 22, 12, 9)); } else { int titleIndex = indexOfChild(title); removeView(title); @@ -1303,29 +1581,34 @@ public void recreateTitleAndDescription() { title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); title.setGravity(Gravity.CENTER); - addView(title, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 22, 0, 10)); + addView(title, titleIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 22, 0, 0)); } removeView(description); description = new TextView(getContext()); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + description.setLineSpacing(description.getLineSpacingExtra(), description.getLineSpacingMultiplier() * 1.1f); description.setGravity(Gravity.CENTER_HORIZONTAL); description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); - addView(description, descriptionIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, 0, 24, 24)); + addView(description, descriptionIndex, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 24, -2, 24, 17)); } } + 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) { @@ -1337,6 +1620,8 @@ private String getBoostsTitleString() { } 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) { @@ -1350,7 +1635,8 @@ private String getBoostsDescriptionString() { 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 { @@ -1359,17 +1645,19 @@ private String getBoostsDescriptionString() { 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) { @@ -1377,9 +1665,10 @@ private String getBoostsDescriptionString() { 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) ); } } @@ -1480,7 +1769,7 @@ private static LimitParams getLimitParams(int type, int currentAccount) { limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); - } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_USERS) { + } else if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR || type == TYPE_BOOSTS_FOR_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; @@ -1534,8 +1823,32 @@ private void updateRows() { 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) { @@ -1555,12 +1868,6 @@ private void updateRows() { } } } - if (type == TYPE_BOOSTS_FOR_POSTING || type == TYPE_BOOSTS_FOR_COLOR) { - linkRow = rowCount++; - if (MessagesController.getInstance(currentAccount).giveawayGiftsPurchaseAvailable) { - bottomRow = rowCount++; - } - } notifyDataSetChanged(); } @@ -1690,4 +1997,201 @@ public static class LimitParams { 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/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index cc40b1f0c9..cb738343ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -38,6 +38,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.BottomPagesView; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -45,6 +46,7 @@ import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.ThemePreviewActivity; import java.util.ArrayList; @@ -57,6 +59,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati float containerViewsProgress; float progressToFullscreenView; float progressToGradient; + boolean fullscreenNext; boolean containerViewsForward; ViewPager viewPager; FrameLayout content; @@ -290,12 +293,16 @@ private void checkPage() { if (selectedFullscreen && nextFullscreen) { progressToGradient = 1f; progressToFullscreenView = progress == 0 ? 1f : progress; + fullscreenNext = true; } else if (selectedFullscreen) { progressToGradient = progressToFullscreenView = 1f - progress; + fullscreenNext = true; } else if (nextFullscreen) { progressToGradient = progressToFullscreenView = progress; + fullscreenNext = false; } else { progressToGradient = progressToFullscreenView = 0; + fullscreenNext = true; } int localGradientAlpha = (int) (255 * (1f - progressToFullscreenView)); @@ -340,7 +347,15 @@ public void onPageScrollStateChanged(int i) { } } if ((onlySelectedType || forceAbout) && fragment != null) { - fragment.presentFragment(new PremiumPreviewFragment(PremiumPreviewFragment.featureTypeToServerString(featureData.type))); + BaseFragment premiumFragment = new PremiumPreviewFragment(PremiumPreviewFragment.featureTypeToServerString(featureData.type)); + if (fragment instanceof ThemePreviewActivity) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + fragment.showAsSheet(premiumFragment, params); + } else { + fragment.presentFragment(premiumFragment); + } } else { PremiumPreviewFragment.buyPremium(fragment, selectedTier, PremiumPreviewFragment.featureTypeToServerString(featureData.type)); } @@ -479,6 +494,8 @@ private void setButtonText() { } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS) { premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.UnlockPremiumIcons)); premiumButtonView.setIcon(R.raw.unlock_icon); + } else { + premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.AboutTelegramPremium)); } } else { premiumButtonView.buttonTextView.setText(PremiumPreviewFragment.getPremiumButtonText(currentAccount, selectedTier)); @@ -678,6 +695,15 @@ void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { title.setText(LocaleController.getString(R.string.PremiumPreviewTranslations)); description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewTranslationsDescription))); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER) { + title.setText(LocaleController.getString(R.string.PremiumPreviewWallpaper)); + description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewWallpaperDescription))); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_NAME_COLOR) { + title.setText(LocaleController.getString(R.string.PremiumPreviewProfileColor)); + description.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PremiumPreviewProfileColorDescription))); + } else { + title.setText(featureData.title); + description.setText(AndroidUtilities.replaceTags(featureData.description)); } topViewOnFullHeight = false; } else { @@ -809,7 +835,7 @@ void checkTopOffset() { } else { closeLayout.setVisibility(View.VISIBLE); } - content.setTranslationX(content.getMeasuredWidth() * progressToGradient); + content.setTranslationX(fullscreenNext ? content.getMeasuredWidth() * progressToGradient : -content.getMeasuredWidth() * progressToGradient); if (localOffset != topCurrentOffset) { topCurrentOffset = localOffset; for (int i = 0; i < viewPager.getChildCount(); i++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java index 280572241d..be24d24810 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.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 void setColorFilter(int color, PorterDuff.Mode mode) { } 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 PremiumGradientTools(int colorKey1, int colorKey2, int colorKey3, int col 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 806ccf2957..694cd32414 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 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.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; @@ -67,22 +72,25 @@ 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; @@ -108,6 +116,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i ValueAnimator enterAnimator; boolean animateConfetti; + boolean animateConfettiWithStars; FrameLayout buttonContainer; FrameLayout bulletinContainer; @@ -139,26 +148,16 @@ public PremiumPreviewBottomSheet(BaseFragment fragment, int currentAccount, TLRP gradientTools.cx = 0; gradientTools.cy = 0; - paddingRow = rowCount++; - featuresStartRow = rowCount; - rowCount += premiumFeatures.size(); - featuresEndRow = rowCount; - sectionRow = rowCount++; - if (!UserConfig.getInstance(currentAccount).isPremium() && true) { - 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(); @@ -171,6 +170,21 @@ public PremiumPreviewBottomSheet(BaseFragment fragment, int currentAccount, TLRP 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() && true) { + buttonRow = rowCount++; + } + } + public PremiumPreviewBottomSheet setOutboundGift(boolean outboundGift) { isOutboundGift = outboundGift; return this; @@ -181,6 +195,11 @@ public PremiumPreviewBottomSheet setAnimateConfetti(boolean animateConfetti) { return this; } + public PremiumPreviewBottomSheet setAnimateConfettiWithStars(boolean animateConfettiWithStars) { + this.animateConfettiWithStars = animateConfettiWithStars; + return this; + } + private void showDialog(Dialog dialog) { if (iconTextureView != null) { iconTextureView.setDialogVisible(true); @@ -214,13 +233,17 @@ public void onViewCreated(FrameLayout containerView) { 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); @@ -229,7 +252,8 @@ protected void onPreMeasure(int widthMeasureSpec, int heightMeasureSpec) { } private FrameLayout titleViewContainer; - private LinkSpanDrawable.LinksTextView titleView[]; + protected LinkSpanDrawable.LinksTextView titleView[]; + private void titleLoaded(CharSequence newText, boolean animated) { if (titleView == null) { return; @@ -262,7 +286,8 @@ private void titleLoaded(CharSequence newText, boolean animated) { } } - private TextView subtitleView; + protected TextView subtitleView; + public void setTitle(boolean animated) { if (titleView == null || subtitleView == null) { return; @@ -400,6 +425,14 @@ protected RecyclerListView.SelectionAdapter createAdapter() { 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 @@ -407,6 +440,11 @@ private class Adapter extends RecyclerListView.SelectionAdapter { 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) { @@ -446,7 +484,7 @@ protected void onDetachedFromWindow() { 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) { @@ -501,7 +539,7 @@ public int overrideColor() { 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)); @@ -518,9 +556,18 @@ public int overrideColor() { @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 @@ -539,11 +586,6 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); } @@ -576,8 +618,25 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); } @@ -585,6 +644,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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); } } @@ -597,6 +658,8 @@ public int getItemCount() { 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) { @@ -605,16 +668,34 @@ public int getItemViewType(int position) { 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++) { @@ -637,7 +718,7 @@ public void show() { if (!NekoConfig.disableVibration.Bool()) 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 80e4d070d6..05c536b519 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 StarParticlesView(Context context) { } drawable = new Drawable(particlesCount); + configure(); + } + + protected void configure() { drawable.type = 100; drawable.roundEffect = true; drawable.useRotate = true; @@ -219,6 +223,18 @@ private void generateBitmaps() { stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; + } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER) { + int res; + if (i == 0) { + res = R.raw.premium_object_user; + } else if (i == 1) { + res = R.raw.cache_photos; + } else { + res = R.raw.cache_profile_photos; + } + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); + svg = true; + continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS) { int res; if (i == 0) { @@ -525,6 +541,7 @@ public void genPosition(long time) { type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS || type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS || type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI || + type == PremiumPreviewFragment.PREMIUM_FEATURE_WALLPAPER || type == PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS ) { randomRotate = (int) (45 * ((Utilities.fastRandom.nextInt() % 100) / 100f)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java index d728c621c5..c055a6b23b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java @@ -3,7 +3,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -38,7 +37,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.Locale; public class StoriesPageView extends BaseListPageView { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java index 04019e1a1f..fb9d287f9d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java @@ -35,7 +35,7 @@ public BoostCounterView(Context context, Theme.ResourcesProvider resourcesProvid countText = new AnimatedTextView.AnimatedTextDrawable(false, false, true); countText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); countText.setCallback(this); - countText.setTextSize(dp(11)); + countText.setTextSize(dp(11.5f)); countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); countText.setTextColor(Color.WHITE); countText.setText(""); @@ -83,14 +83,19 @@ public void setCount(int count, boolean animated) { 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 @@ protected void onDraw(Canvas canvas) { 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,6 +114,7 @@ protected void onDraw(Canvas canvas) { } canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(10), dp(10), bgPaint); + 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 64ea478d74..176fbef656 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.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 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.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 static void showToastError(Context context, TLRPC.TL_error error) { } } + 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) @@ -127,6 +157,9 @@ public static void showBulletin(FrameLayout container, Theme.ResourcesProvider r } public static void showBulletin(final BaseFragment baseFragment, final TLRPC.Chat chat, final boolean isGiveaway) { + if (baseFragment == null) { + return; + } BulletinFactory bulletinFactory = BulletinFactory.of(baseFragment); showBulletin(bulletinFactory, baseFragment.getResourceProvider(), chat, isGiveaway); } @@ -488,6 +521,11 @@ public static void showAbout(String from, long msgDate, TLRPC.TL_payments_giveaw 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); @@ -533,10 +571,13 @@ public static void showAbout(String from, long msgDate, TLRPC.TL_payments_giveaw 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)); @@ -551,6 +592,11 @@ public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giv 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); @@ -571,28 +617,28 @@ public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giv 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) { @@ -604,15 +650,30 @@ public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giv }); } 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) { @@ -639,7 +700,20 @@ public static void openGiveAwayStatusDialog(MessageObject messageObject, Browser 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 -> { @@ -679,11 +753,22 @@ private static String getGiveawayCreatorName(MessageObject messageObject) { } 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) { @@ -726,7 +811,7 @@ public static void showBulletinAbout(MessageObject messageObject) { }); } - 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) { @@ -734,8 +819,12 @@ public static void showMoreBoostsNeeded(long dialogId) { } 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 50532e5849..f17dac3128 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 static boolean isGoogleBillingAvailable() { // 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 static boolean isGoogleBillingAvailable() { // 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 static boolean isGoogleBillingAvailable() { // }); // } - 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,13 +280,159 @@ public static void launchPreparedGiveaway(TL_stories.TL_prepaidGiveaway prepaidG }); } - 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, +// 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_payments_getPaymentForm req = new TLRPC.TL_payments_getPaymentForm(); +// TLRPC.TL_inputInvoicePremiumGiftCode invoice = new TLRPC.TL_inputInvoicePremiumGiftCode(); +// 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) { +// if (o instanceof TLRPC.Chat) { +// payload.additional_peers.add(controller.getInputPeer(-((TLRPC.Chat) o).id)); +// } +// } +// payload.boost_peer = controller.getInputPeer(-chat.id); +// payload.boost_peer = controller.getInputPeer(-chat.id); +// payload.currency = option.currency; +// payload.amount = option.amount; +// +// for (TLObject object : selectedCountries) { +// TLRPC.TL_help_country country = (TLRPC.TL_help_country) object; +// payload.countries_iso2.add(country.iso2); +// } +// +// invoice.purpose = payload; +// invoice.option = option; +// +// final JSONObject themeParams = BotWebViewSheet.makeThemeParams(baseFragment.getResourceProvider()); +// if (themeParams != null) { +// req.theme_params = new TLRPC.TL_dataJSON(); +// req.theme_params.data = themeParams.toString(); +// req.flags |= 1; +// } +// req.invoice = invoice; +// +// int requestId = connection.sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { +// if (error != null) { +// onError.run(error); +// return; +// } +// PaymentFormActivity paymentFormActivity = null; +// if (response instanceof TLRPC.TL_payments_paymentForm) { +// TLRPC.TL_payments_paymentForm form = (TLRPC.TL_payments_paymentForm) response; +// form.invoice.recurring = true; +// controller.putUsers(form.users, false); +// paymentFormActivity = new PaymentFormActivity(form, invoice, baseFragment); +// } else if (response instanceof TLRPC.TL_payments_paymentReceipt) { +// paymentFormActivity = new PaymentFormActivity((TLRPC.TL_payments_paymentReceipt) response); +// } +// if (paymentFormActivity != null) { +// paymentFormActivity.setPaymentFormCallback(status -> { +// if (status == PaymentFormActivity.InvoiceStatus.PAID) { +// onSuccess.run(null); +// } else if (status != PaymentFormActivity.InvoiceStatus.PENDING) { +// onError.run(null); +// } +// }); +// LaunchActivity.getLastFragment().showAsSheet(paymentFormActivity, new BaseFragment.BottomSheetParams()); +// } else { +// onError.run(null); +// } +// })); +// } +// +// 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) { +// if (o instanceof TLRPC.Chat) { +// payload.additional_peers.add(controller.getInputPeer(-((TLRPC.Chat) o).id)); +// } +// } +// payload.boost_peer = controller.getInputPeer(-chat.id); +// for (TLObject object : selectedCountries) { +// TLRPC.TL_help_country country = (TLRPC.TL_help_country) object; +// payload.countries_iso2.add(country.iso2); +// } +// +// QueryProductDetailsParams.Product product = QueryProductDetailsParams.Product.newBuilder() +// .setProductType(BillingClient.ProductType.INAPP) +// .setProductId(option.store_product) +// .build(); +// BillingController.getInstance().queryProductDetails(Arrays.asList(product), (billingResult, list) -> { +// ProductDetails.OneTimePurchaseOfferDetails offerDetails = list.get(0).getOneTimePurchaseOfferDetails(); +// payload.currency = offerDetails.getPriceCurrencyCode(); +// payload.amount = (long) ((offerDetails.getPriceAmountMicros() / Math.pow(10, 6)) * Math.pow(10, BillingController.getInstance().getCurrencyExp(option.currency))); +// +// TLRPC.TL_payments_canPurchasePremium req = new TLRPC.TL_payments_canPurchasePremium(); +// req.purpose = payload; +// connection.sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { +// if (error != null) { +// onError.run(error); +// return; +// } +// if (response != null) { +// BillingController.getInstance().addResultListener(list.get(0).getProductId(), billingResult1 -> { +// if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { +// AndroidUtilities.runOnUIThread(() -> onSuccess.run(null)); +// } +// }); +// BillingController.getInstance().setOnCanceled(() -> { +// AndroidUtilities.runOnUIThread(() -> onError.run(null)); +// }); +// BillingController.getInstance().launchBillingFlow( +// baseFragment.getParentActivity(), AccountInstance.getInstance(UserConfig.selectedAccount), payload, +// Collections.singletonList(BillingFlowParams.ProductDetailsParams.newBuilder() +// .setProductDetails(list.get(0)) +// .build()) +// ); +// } +// })); +// }); +// } // // 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) { // MessagesController controller = MessagesController.getInstance(UserConfig.selectedAccount); @@ -420,6 +579,21 @@ public static List filterGiftOptions(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 +643,10 @@ public static void loadGiftOptions(TLRPC.Chat chat, Utilities.Callback { // if (response != null) { @@ -508,6 +684,35 @@ public static void loadGiftOptions(TLRPC.Chat chat, 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 +796,7 @@ public static void applyGiftCode(String slug, Utilities.Callback onDone, U 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 9f89f3fa23..f18878f181 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 @@ -7,14 +7,16 @@ 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.ApplicationLoader; 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 +35,7 @@ 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 +73,10 @@ public interface ActionListener { 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 +97,36 @@ public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolea 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 +157,7 @@ public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolea } 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 +178,10 @@ public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolea }, 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 +216,7 @@ public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolea 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,13 +239,15 @@ public BoostViaGiftsBottomSheet(BaseFragment fragment, boolean needFocus, boolea boolean onlyNewSubscribers = selectedParticipantsType == ParticipantsTypeCell.TYPE_NEW; int dateInt = BoostRepository.prepareServerDate(selectedEndDate); actionBtn.updateLoading(true); - BoostRepository.payGiveAway(selectedChats, selectedCountries, option, currentChat, dateInt, onlyNewSubscribers, fragment, result -> { - dismiss(); - AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(UserConfig.selectedAccount).postNotificationName(NotificationCenter.boostByChannelCreated, currentChat, true), 220); - }, error -> { - actionBtn.updateLoading(false); - BoostDialogs.showToastError(getContext(), error); - }); +// 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 -> { +// actionBtn.updateLoading(false); +// BoostDialogs.showToastError(getContext(), error); +// }); + Toast.makeText(ApplicationLoader.applicationContext, R.string.nekoXPaymentRemovedToast, Toast.LENGTH_SHORT).show(); + // NekoX: The payment function has been removed. break; } } @@ -321,11 +364,6 @@ private void updateRows(boolean animated, boolean notify) { 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 +374,56 @@ private void updateRows(boolean animated, boolean notify) { 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 0000000000..00a72c9f36 --- /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 119a2625eb..f5ef0d54c0 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 static void show(BaseFragment fragment, String slug, Browser.Progress pro 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(); } @@ -107,10 +122,10 @@ public GiftInfoBottomSheet(BaseFragment fragment, boolean needFocus, boolean has this.giftCode = giftCode; this.slug = slug; setApplyTopPadding(false); - setApplyBottomPadding(true); + setApplyBottomPadding(false); fixNavigationBar(); updateTitle(); - adapter.init(fragment, giftCode, slug); + 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 0000000000..cd82c38961 --- /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 0000000000..262722dc41 --- /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 0000000000..69f34c6f9f --- /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 0000000000..eb584bf3ed --- /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 5f86010612..87268ccb81 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 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.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.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 ReassignBoostBottomSheet(BaseFragment fragment, TL_stories.TL_premium_myB 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 void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi 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 TopCell(Context context) { 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 TopCell(Context context) { 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 void showChats(List selectedChats, TLRPC.Chat currentChat) { 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 void showChats(List selectedChats, TLRPC.Chat currentChat) { 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 void onAnimationEnd(Animator animation) { 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 void onAnimationEnd(Animator animation) { 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 83d6a4e3da..103ad2ad54 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 void updateItems(boolean animated, boolean notify) { 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 0000000000..aa55dd99a8 --- /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 2e4138e887..0fddfb8dcd 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.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 void updateBoostCounter(int value) { ((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 boolean isEnabled(RecyclerView.ViewHolder holder) { || 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 RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int 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 void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi 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 static Item asPeer(TLRPC.InputPeer peer, boolean removable, int count) { 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 386348ff9d..081079743a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java @@ -3,11 +3,13 @@ import static org.telegram.tgnet.TLRPC.TL_payments_checkedGiftCode.NO_USER_ID; import android.content.Context; +import android.graphics.Color; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -47,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 @@ -110,6 +114,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int break; case HOLDER_TYPE_BUTTON: view = new ActionBtnCell(context, resourcesProvider); + view.setPadding(0, 0, 0, AndroidUtilities.dp(14)); break; case HOLDER_TYPE_EMPTY: view = new View(context); @@ -167,7 +172,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi cell.setText(LocaleController.getString("BoostingLinkNotActivated", R.string.BoostingLinkNotActivated)); } else { //activated link - cell.setText(""); + cell.setFixedSize(14); + cell.setText(null); } return; } @@ -178,25 +184,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi 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); @@ -224,7 +212,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi dismiss(); }, error -> { cell.updateLoading(false); - BoostDialogs.showToastError(baseFragment.getContext(), error); + BoostDialogs.processApplyGiftCodeError(error, container, resourcesProvider, this::share); }); } else { dismiss(); @@ -242,6 +230,26 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } } + 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 786473589e..952ab38ed7 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.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 void setData(List items, RecyclerListView listView) { 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 RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int 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 RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int 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 void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi 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 void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi ((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 static Item asLetter(String letter) { 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 boolean equals(Object o) { 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 d6626d363c..9d0e959126 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 void setGiftPremiumStyle(int counter, boolean animated, boolean isEnabled 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 void setCloseStyle(){ 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/ChatCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java index 6ec4cf4db2..ed15c92af9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/ChatCell.java @@ -11,6 +11,7 @@ import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/DurationCell.java index 696e416333..5e0a8c62ac 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 @@ @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 0000000000..6cd9276297 --- /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 0000000000..4c03f708b6 --- /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 55f8401004..b3a38b3f92 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,18 +1,14 @@ package org.telegram.ui.Components.Premium.boosts.cells; -import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.REPLACING_TAG_TYPE_LINKBOLD; 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; @@ -24,31 +20,22 @@ 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 { @@ -177,31 +164,16 @@ public void setUnclaimedText() { 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); - - TLRPC.User toUser = MessagesController.getInstance(UserConfig.selectedAccount).getUser(toUserId); - SpannableStringBuilder userName = new SpannableStringBuilder(); - userName.append("**"); - userName.append(Emoji.replaceEmoji(UserObject.getUserName(toUser), subtitleView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(12), false)); - userName.append("**"); - - descriptionStart = AndroidUtilities.replaceSingleTag( - descriptionStart.toString().replace("**%1$s**", userName), - Theme.key_chat_messageLinkIn, 0, - () -> onObjectClicked.run(toUser), - resourcesProvider - ); - descriptionEnd = AndroidUtilities.replaceTags(descriptionEnd.toString()); - stringBuilder.append(descriptionStart); - stringBuilder.append(descriptionEnd); - } catch (Exception e) { - FileLog.e(e); - } - subtitleView.setText(stringBuilder); + CharSequence description = AndroidUtilities.replaceTags(LocaleController.getString("BoostingLinkAllowsToUser", R.string.BoostingLinkAllowsToUser)); + TLRPC.User toUser = MessagesController.getInstance(UserConfig.selectedAccount).getUser(toUserId); + + 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/LinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java index 5ee5d736b9..4ad6ce2089 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/LinkCell.java @@ -56,11 +56,11 @@ public LinkCell(@NonNull Context context, BaseFragment fragment, Theme.Resources linkContainer.setOnClickListener(v -> AndroidUtilities.addToClipboard(link)); imageView = new ImageView(getContext()); - imageView.setImageResource(R.drawable.msg_copy); + imageView.setImageResource(R.drawable.menu_copy_s); imageView.setColorFilter(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); imageView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); imageView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(20), 0, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_listSelector, resourcesProvider), (int) (255 * 0.3f)))); - addView(imageView, LayoutHelper.createFrame(40, 40, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 15, 0, 15, 0)); + addView(imageView, LayoutHelper.createFrame(40, 40, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 15, 0, 17, 0)); imageView.setOnClickListener(v -> AndroidUtilities.addToClipboard(link)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SwitcherCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SwitcherCell.java new file mode 100644 index 0000000000..006d658733 --- /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 51fa8e5804..053255b729 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/TableCell.java @@ -6,6 +6,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -24,6 +25,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; @@ -161,7 +163,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.clipPath(roundPath); } super.dispatchDraw(canvas); - linePaint.setColor(Theme.getColor(Theme.key_divider, resourcesProvider)); + linePaint.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_divider, resourcesProvider), Color.WHITE, 0.1f)); linePaint.setStrokeWidth(AndroidUtilities.dp(1)); float oneRow = getHeight() / (tableRow4.getVisibility() == VISIBLE ? 5f : 4f); for (int i = 1; i <= 4; i++) { @@ -280,7 +282,6 @@ private TextView createTextView(String text, boolean blueColor) { 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()); @@ -288,7 +289,9 @@ private TextView createTextView(String text, boolean blueColor) { 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 7f6e833f8a..9893bb2623 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java @@ -8,7 +8,6 @@ import static org.telegram.messenger.LocaleController.getString; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -30,6 +29,7 @@ import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageLocation; @@ -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 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 TextPaint counterTextPaint; + private TextPaint chatTextPaint; + private TextPaint textPaint; + private TextPaint textDividerPaint; + private Paint lineDividerPaint; + 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; @@ -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 GiveawayMessageCell(ChatMessageCell parentView) { 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 void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 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 void setMessageContent(MessageObject messageObject, int parentWidth, int } 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 void setMessageContent(MessageObject messageObject, int parentWidth, int 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 void setMessageContent(MessageObject messageObject, int parentWidth, int 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 void setMessageContent(MessageObject messageObject, int parentWidth, int 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 void setMessageContent(MessageObject messageObject, int parentWidth, int 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,15 +429,18 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int } 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 = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + int colorId = ChatObject.getColorId(chat); if (colorId < 7) { color = Theme.getColor(Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { 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 void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesPr } 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 void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesPr 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 void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesPr 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 void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesPr 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 void draw(Canvas canvas, int marginTop, int marginLeft, Theme.ResourcesPr } public void onDetachedFromWindow() { - giftReceiver.onDetachedFromWindow(); + if (giftReceiver != null) { + giftReceiver.onDetachedFromWindow(); + } if (avatarImageReceivers != null) { for (ImageReceiver avatarImageReceiver : avatarImageReceivers) { avatarImageReceiver.onDetachedFromWindow(); @@ -533,7 +617,9 @@ public void onDetachedFromWindow() { } 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 0000000000..f3a6a2be90 --- /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 469f7b6093..01a2598c59 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 void setOnCloseClickListener(Runnable onCloseClickListener) { 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 d5448547c3..1785e1abbb 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 SelectorLetterCell(@NonNull Context context, Theme.ResourcesProvider reso } 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 dec7594086..197eb665f4 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 void afterTextChanged(Editable s) { }); } + 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 0a219c4f38..011d52bf42 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 @@ 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 void draw(Canvas canvas) { 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 void draw(Canvas canvas) { 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 9e18824f4e..594a3b2b1c 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 void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi @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 int getAdditionalHeight() { 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 @@ private void updateCustomReactionsButton() { 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/AddReactionsSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AddReactionsSpan.java new file mode 100644 index 0000000000..12fb4c64b7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AddReactionsSpan.java @@ -0,0 +1,89 @@ +package org.telegram.ui.Components.Reactions; + +import static android.graphics.Canvas.ALL_SAVE_FLAG; +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ReplacementSpan; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; + +public class AddReactionsSpan extends ReplacementSpan { + + private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final RectF rectF = new RectF(); + private StaticLayout layout; + private float width, height; + private int alpha; + + public AddReactionsSpan(float textSize, Theme.ResourcesProvider resourcesProvider) { + textPaint.setTextSize(dp(textSize)); + textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText5, resourcesProvider)); + } + + public void makeLayout() { + if (layout == null) { + layout = new StaticLayout(LocaleController.getString("ReactionAddReactionsHint", R.string.ReactionAddReactionsHint), textPaint, AndroidUtilities.displaySize.x, LocaleController.isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL, 1, 0, false); + width = layout.getLineWidth(0); + height = layout.getHeight(); + } + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { + makeLayout(); + return (int) (dp(8) + width); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float _x, int top, int _y, int bottom, @NonNull Paint paint) { + makeLayout(); + rectF.set(canvas.getClipBounds()); + canvas.saveLayerAlpha(rectF, alpha, ALL_SAVE_FLAG); + float transY = (top + (bottom - top) / 2f - height / 2f); + canvas.translate(_x + dp(4), transY); + layout.draw(canvas); + canvas.restore(); + } + + public void show(View parent) { + ValueAnimator valueAnimator = ValueAnimator.ofInt(alpha, 255); + valueAnimator.addUpdateListener(animator -> { + alpha = (int) animator.getAnimatedValue(); + parent.invalidate(); + }); + valueAnimator.setDuration(200); + valueAnimator.start(); + } + + public void hide(View parent, Runnable after) { + ValueAnimator valueAnimator = ValueAnimator.ofInt(alpha, 0); + valueAnimator.addUpdateListener(animator -> { + alpha = (int) animator.getAnimatedValue(); + parent.invalidate(); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + after.run(); + } + }); + valueAnimator.setDuration(200); + valueAnimator.start(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java new file mode 100644 index 0000000000..cddb46a996 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/BackSpaceButtonView.java @@ -0,0 +1,128 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Stories.RoundRectOutlineProvider; + +@SuppressLint("ViewConstructor") +public class BackSpaceButtonView extends FrameLayout { + + private final Theme.ResourcesProvider resourcesProvider; + private final ImageView backspaceButton; + private boolean backspacePressed; + private boolean backspaceOnce; + private Utilities.Callback onBackspace; + + public BackSpaceButtonView(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + backspaceButton = new ImageView(context) { + private long lastClick = 0; + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (System.currentTimeMillis() < lastClick + 350) { + return false; + } + lastClick = System.currentTimeMillis(); + backspacePressed = true; + backspaceOnce = false; + postBackspaceRunnable(350); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) { + backspacePressed = false; + if (!backspaceOnce) { + if (onBackspace != null) { + onBackspace.run(false); + backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + } + } + super.onTouchEvent(event); + return true; + } + }; + backspaceButton.setHapticFeedbackEnabled(true); + backspaceButton.setImageResource(R.drawable.smiles_tab_clear); + backspaceButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelBackspace), PorterDuff.Mode.MULTIPLY)); + backspaceButton.setScaleType(ImageView.ScaleType.CENTER); + backspaceButton.setContentDescription(LocaleController.getString("AccDescrBackspace", R.string.AccDescrBackspace)); + backspaceButton.setFocusable(true); + backspaceButton.setOnClickListener(v -> { + + }); + addView(backspaceButton, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); + + int rippleColor = Theme.getColor(Theme.key_listSelector); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(36), getThemedColor(Theme.key_windowBackgroundWhite), rippleColor); + if (Build.VERSION.SDK_INT >= 21) { + backspaceButton.setBackground(drawable); + backspaceButton.setOutlineProvider(new RoundRectOutlineProvider(18)); + backspaceButton.setElevation(AndroidUtilities.dp(1)); + backspaceButton.setClipToOutline(true); + } else { + Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); + combinedDrawable.setIconSize(AndroidUtilities.dp(36), AndroidUtilities.dp(36)); + drawable = combinedDrawable; + backspaceButton.setBackground(drawable); + } + + setClickable(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY) + ); + } + + public void setOnBackspace(Utilities.Callback onBackspace) { + this.onBackspace = onBackspace; + } + + private void postBackspaceRunnable(final int time) { + AndroidUtilities.runOnUIThread(() -> { + if (!backspacePressed) { + return; + } + if (onBackspace != null) { + onBackspace.run(time < 300); + backspaceButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + backspaceOnce = true; + postBackspaceRunnable(Math.max(50, time - 100)); + }, time); + } + + private int getThemedColor(int key) { + if (resourcesProvider != null) { + return resourcesProvider.getColor(key); + } + return Theme.getColor(key); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java new file mode 100644 index 0000000000..739b4193ea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatCustomReactionsEditActivity.java @@ -0,0 +1,737 @@ +package org.telegram.ui.Components.Reactions; + +import static org.telegram.messenger.AndroidUtilities.replaceTags; +import static org.telegram.messenger.LocaleController.formatPluralString; +import static org.telegram.messenger.LocaleController.getString; +import static org.telegram.ui.Components.Reactions.ReactionsUtils.addReactionToEditText; +import static org.telegram.ui.Components.Reactions.ReactionsUtils.createAnimatedEmojiSpan; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.Editable; +import android.text.Layout; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.SelectAnimatedEmojiDialog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; + +public class ChatCustomReactionsEditActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + public final static int SELECT_TYPE_NONE = 2, + SELECT_TYPE_SOME = 1, + SELECT_TYPE_ALL = 0; + + private SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; + private FrameLayout bottomDialogLayout; + private BackSpaceButtonView backSpaceButtonView; + private TextCheckCell enableReactionsCell; + private LinearLayout switchLayout; + private LinearLayout contentLayout; + private CustomReactionEditText editText; + private UpdateReactionsButton actionButton; + private ScrollView scrollView; + + private final HashMap selectedEmojisMap = new LinkedHashMap<>(); + private final List selectedEmojisIds = new ArrayList<>(); + private final HashMap initialSelectedEmojis = new LinkedHashMap<>(); + private final List allAvailableReactions = new ArrayList<>(); + + private final int maxReactionsCount = getMessagesController().boostsChannelLevelMax; + private boolean emojiKeyboardVisible = false; + private final TLRPC.ChatFull info; + private final long chatId; + private TLRPC.Chat currentChat; + private TL_stories.TL_premium_boostsStatus boostsStatus; + private int selectedCustomReactions; + private int selectedType = -1; + private boolean isPaused; + private final Runnable checkAfterFastDeleteRunnable = () -> checkMaxCustomReactions(false); + + public ChatCustomReactionsEditActivity(long chatId, TLRPC.ChatFull info) { + super(); + this.chatId = chatId; + this.info = info; + } + + @Override + public boolean onFragmentCreate() { + currentChat = getMessagesController().getChat(chatId); + if (currentChat == null) { + currentChat = MessagesStorage.getInstance(currentAccount).getChatSync(chatId); + if (currentChat != null) { + getMessagesController().putChat(currentChat, true); + } else { + return false; + } + } + + if (info == null) { + return false; + } + + getMessagesController().getBoostsController().getBoostsStats(-chatId, boostsStatus -> { + this.boostsStatus = boostsStatus; + boolean hasChanges = !selectedEmojisMap.keySet().equals(initialSelectedEmojis.keySet()); + if (hasChanges) { + checkMaxCustomReactions(false); + } + }); + getNotificationCenter().addObserver(this, NotificationCenter.reactionsDidLoad); + allAvailableReactions.addAll(getMediaDataController().getEnabledReactionsList()); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + return super.onFragmentCreate(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public View createView(Context context) { + actionBar.setTitle(LocaleController.getString("Reactions", R.string.Reactions)); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (!checkChangesBeforeExit()) { + finishFragment(); + } + } + } + }); + + FrameLayout rootLayout = new FrameLayout(context); + scrollView = new ScrollView(context); + scrollView.setFillViewport(true); + + contentLayout = new LinearLayout(context); + contentLayout.setOrientation(LinearLayout.VERTICAL); + + scrollView.addView(contentLayout); + + enableReactionsCell = new TextCheckCell(context); + enableReactionsCell.setHeight(56); + enableReactionsCell.setBackgroundColor(Theme.getColor(enableReactionsCell.isChecked() ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked)); + enableReactionsCell.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + enableReactionsCell.setColors(Theme.key_windowBackgroundCheckText, Theme.key_switchTrackBlue, Theme.key_switchTrackBlueChecked, Theme.key_switchTrackBlueThumb, Theme.key_switchTrackBlueThumbChecked); + enableReactionsCell.setOnClickListener(v -> { + setCheckedEnableReactionCell(enableReactionsCell.isChecked() ? SELECT_TYPE_NONE : SELECT_TYPE_SOME, true); + }); + contentLayout.addView(enableReactionsCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); + infoCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + infoCell.setTopPadding(12); + infoCell.setBottomPadding(16); + infoCell.setText(LocaleController.getString("ReactionAddEmojiFromAnyPack", R.string.ReactionAddEmojiFromAnyPack)); + contentLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + HeaderCell headerCell = new HeaderCell(context); + headerCell.setText(LocaleController.getString("AvailableReactions", R.string.AvailableReactions)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + headerCell.setTextSize(15); + headerCell.setTopMargin(14); + + switchLayout = new LinearLayout(context); + switchLayout.setOrientation(LinearLayout.VERTICAL); + + contentLayout.addView(switchLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + switchLayout.addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + editText = new CustomReactionEditText(context, getResourceProvider(), maxReactionsCount) { + @Override + protected void onLineCountChanged(int oldLineCount, int newLineCount) { + if (newLineCount > oldLineCount) { + scrollView.smoothScrollBy(0, AndroidUtilities.dp(30)); + } + } + + @Override + public boolean onTextContextMenuItem(int id) { + if (id == R.id.menu_delete || id == android.R.id.cut) { + return deleteSelectedEmojis(); + } else if (id == android.R.id.paste || id == android.R.id.copy) { + return false; + } + return super.onTextContextMenuItem(id); + } + }; + editText.setOnFocused(this::showKeyboard); + + switchLayout.addView(editText, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(200); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + switchLayout.setLayoutTransition(layoutTransition); + + TextInfoPrivacyCell infoCell2 = new TextInfoPrivacyCell(context); + infoCell2.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText4)); + infoCell2.setTopPadding(12); + infoCell2.setBottomPadding(70); + infoCell2.setText(AndroidUtilities.replaceSingleTag( + LocaleController.getString("ReactionCreateOwnPack", R.string.ReactionCreateOwnPack), + Theme.key_chat_messageLinkIn, 0, + () -> presentFragment(ChatActivity.of(429000)), + getResourceProvider() + )); + switchLayout.addView(infoCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + actionButton = new UpdateReactionsButton(context, getResourceProvider()); + actionButton.setDefaultState(); + actionButton.setOnClickListener(v -> { + if (actionButton.isLoading()) { + return; + } + + if (boostsStatus != null && boostsStatus.level < selectedCustomReactions) { + ReactionsUtils.showLimitReachedDialogForReactions(-chatId, selectedCustomReactions, boostsStatus); + return; + } + + actionButton.setLoading(true); + getMessagesController().setCustomChatReactions(chatId, selectedType, grabReactions(false), error -> { + if (isFinishing()) { + return; + } + actionButton.setLoading(false); + if (error.text.equals("CHAT_NOT_MODIFIED")) { + finishFragment(); + } else { + Runnable runnable = () -> { + if (boostsStatus != null && error.text.equals("BOOSTS_REQUIRED")) { + ReactionsUtils.showLimitReachedDialogForReactions(-chatId, selectedCustomReactions, boostsStatus); + } else { + String errText = error.text; + if (error.text.equals("REACTIONS_TOO_MANY")) { + errText = formatPluralString("ReactionMaxCountError", maxReactionsCount); + } + BulletinFactory.of(ChatCustomReactionsEditActivity.this).createErrorBulletin(errText).show(); + } + }; + AndroidUtilities.runOnUIThread(runnable, boostsStatus == null ? 200 : 0); + } + }, this::finishFragment); + }); + rootLayout.addView(scrollView); + rootLayout.addView(actionButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 13, 0, 13, 13)); + rootLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + bottomDialogLayout = new FrameLayout(context) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (emojiKeyboardVisible && changed) { + //support screen rotation + actionButton.setTranslationY(-bottomDialogLayout.getMeasuredHeight()); + updateScrollViewMarginBottom(bottomDialogLayout.getMeasuredHeight()); + scrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + } + }; + + bottomDialogLayout.setVisibility(View.INVISIBLE); + rootLayout.addView(bottomDialogLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + int i = 0; + if (info.available_reactions instanceof TLRPC.TL_chatReactionsAll) { + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_ALL, false); + initialSelectedEmojis.putAll(selectedEmojisMap); + } else if (info.available_reactions instanceof TLRPC.TL_chatReactionsSome) { + TLRPC.TL_chatReactionsSome reactionsSome = (TLRPC.TL_chatReactionsSome) info.available_reactions; + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.Reaction reaction : reactionsSome.reactions) { + if (reaction instanceof TLRPC.TL_reactionEmoji) { + TLRPC.TL_reactionEmoji reactionEmoji = ((TLRPC.TL_reactionEmoji) reaction); + TLRPC.TL_availableReaction availableReaction = getMediaDataController().getReactionsMap().get(reactionEmoji.emoticon); + if (availableReaction == null) { + continue; + } + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + } else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { + addReactionToEditText((TLRPC.TL_reactionCustomEmoji) reaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + } + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_SOME, false); + initialSelectedEmojis.putAll(selectedEmojisMap); + } else if (info.available_reactions instanceof TLRPC.TL_chatReactionsNone) { + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + setCheckedEnableReactionCell(SELECT_TYPE_NONE, false); + } + enableReactionsCell.setTextAndCheck(LocaleController.getString("EnableReactions", R.string.EnableReactions), selectedType != SELECT_TYPE_NONE, false); + editText.addReactionsSpan(); + + fragmentView = rootLayout; + return rootLayout; + } + + private void initSelectAnimatedEmojiDialog() { + if (selectAnimatedEmojiDialog != null) { + return; + } + int accentColor = Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, getResourceProvider()); + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(this, getContext(), false, null, SelectAnimatedEmojiDialog.TYPE_CHAT_REACTIONS, false, getResourceProvider(), 16, accentColor) { + + private boolean firstLayout = true; + + { + setDrawBackground(false); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (firstLayout) { + firstLayout = false; + selectAnimatedEmojiDialog.onShow(null); + } + } + + protected void onEmojiSelected(View view, Long documentId, TLRPC.Document document, Integer until) { + if (selectedEmojisMap.containsKey(documentId)) { + selectedEmojisIds.remove(documentId); + AnimatedEmojiSpan removedSpan = selectedEmojisMap.remove(documentId); + removedSpan.setRemoved(() -> { + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + AnimatedEmojiSpan[] spans = spanned.getSpans(0, spanned.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + if (span == removedSpan) { + int selectionEnd = editText.getEditTextSelectionEnd(); + int spanEnd = spanned.getSpanEnd(span); + int spanStart = spanned.getSpanStart(span); + editText.getText().delete(spanStart, spanEnd); + int spanDiff = spanEnd - spanStart; + editText.setSelection(spanEnd <= selectionEnd ? selectionEnd - spanDiff : selectionEnd); + break; + } + } + }); + animateChangesInNextRows(removedSpan); + selectAnimatedEmojiDialog.setMultiSelected(documentId, true); + checkMaxCustomReactions(false); + } else { + if (selectedEmojisMap.size() >= maxReactionsCount) { + BulletinFactory.of(ChatCustomReactionsEditActivity.this).createErrorBulletin(formatPluralString("ReactionMaxCountError", maxReactionsCount)).show(); + return; + } + try { + int selectionEnd = editText.getEditTextSelectionEnd(); + SpannableString spannable = new SpannableString("b"); + AnimatedEmojiSpan span = createAnimatedEmojiSpan(document, documentId, editText.getFontMetricsInt()); + span.cacheType = AnimatedEmojiDrawable.getCacheTypeForEnterView(); + span.setAdded(); + selectedEmojisIds.add(selectionEnd, documentId); + selectedEmojisMap.put(documentId, span); + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editText.getText().insert(selectionEnd, spannable); + editText.setSelection(selectionEnd + spannable.length()); + selectAnimatedEmojiDialog.setMultiSelected(documentId, true); + checkMaxCustomReactions(true); + animateChangesInNextRows(span); + } catch (Exception e) { + FileLog.e(e); + } + } + } + }; + + selectAnimatedEmojiDialog.setAnimationsEnabled(false); + selectAnimatedEmojiDialog.setClipChildren(false); + selectAnimatedEmojiDialog.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + bottomDialogLayout.addView(selectAnimatedEmojiDialog, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + backSpaceButtonView = new BackSpaceButtonView(getContext(), getResourceProvider()); + backSpaceButtonView.setOnBackspace(isFast -> { + if (deleteSelectedEmojis()) { + return; + } + int selectionEnd = editText.getEditTextSelectionEnd(); + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + AnimatedEmojiSpan[] spans = spanned.getSpans(0, spanned.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + int removedSpanEnd = spanned.getSpanEnd(span); + if (removedSpanEnd == selectionEnd) { + selectedEmojisMap.remove(span.documentId); + selectedEmojisIds.remove(span.documentId); + selectAnimatedEmojiDialog.unselect(span.documentId); + if (isFast) { + editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); + AndroidUtilities.cancelRunOnUIThread(checkAfterFastDeleteRunnable); + AndroidUtilities.runOnUIThread(checkAfterFastDeleteRunnable, 350); + } else { + span.setRemoved(() -> { + Editable editable = editText.getText(); + int spanStart = editable.getSpanStart(span); + int spanEnd = editable.getSpanEnd(span); + int spanDiff = spanEnd - spanStart; + if (spanStart == -1 || spanEnd == -1) { + return; + } + editText.getText().delete(spanStart, spanEnd); + editText.setSelection(Math.min(selectionEnd - spanDiff, editText.getText().length())); + }); + animateChangesInNextRows(span); + checkMaxCustomReactions(false); + } + break; + } + } + }); + bottomDialogLayout.addView(backSpaceButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 8, 8)); + for (Long selectedEmojisId : selectedEmojisIds) { + selectAnimatedEmojiDialog.setMultiSelected(selectedEmojisId, false); + } + } + + private void animateChangesInNextRows(AnimatedEmojiSpan actionSpan) { + Editable editable = editText.getText(); + Layout layout = editText.getLayout(); + int deleteLine = layout.getLineForOffset(editable.getSpanStart(actionSpan)); + int nextLine = deleteLine + 1; + if (nextLine < layout.getLineCount()) { + int newLineStart = layout.getLineStart(nextLine); + AnimatedEmojiSpan[] spans = editable.getSpans(newLineStart, editable.length(), AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + span.setAnimateChanges(); + } + } + } + + private boolean deleteSelectedEmojis() { + int selectionEnd = editText.getEditTextSelectionEnd(); + int selectionStart = editText.getEditTextSelectionStart(); + SpannableStringBuilder spanned = new SpannableStringBuilder(editText.getText()); + if (editText.hasSelection()) { + AnimatedEmojiSpan[] spans = spanned.getSpans(selectionStart, selectionEnd, AnimatedEmojiSpan.class); + for (AnimatedEmojiSpan span : spans) { + selectedEmojisMap.remove(span.documentId); + selectedEmojisIds.remove(span.documentId); + selectAnimatedEmojiDialog.unselect(span.documentId); + } + editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); + checkMaxCustomReactions(false); + return true; + } + return false; + } + + @Override + public boolean canBeginSlide() { + if (checkChangesBeforeExit()) { + return false; + } + return super.canBeginSlide(); + } + + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + super.onTransitionAnimationEnd(isOpen, backward); + if (isOpen && selectedType != SELECT_TYPE_NONE) { + editText.setFocusableInTouchMode(true); + } + if (isOpen && !backward) { + initSelectAnimatedEmojiDialog(); + AndroidUtilities.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512), 200); + } + } + + private void setCheckedEnableReactionCell(int selectType, boolean animated) { + if (selectedType == selectType) { + return; + } + + boolean checked = selectType == SELECT_TYPE_SOME || selectType == SELECT_TYPE_ALL; + enableReactionsCell.setChecked(checked); + int clr = Theme.getColor(checked ? Theme.key_windowBackgroundChecked : Theme.key_windowBackgroundUnchecked); + if (animated) { + if (checked) { + enableReactionsCell.setBackgroundColorAnimated(true, clr); + } else { + enableReactionsCell.setBackgroundColorAnimatedReverse(clr); + } + } else { + enableReactionsCell.setBackgroundColor(clr); + } + + this.selectedType = selectType; + + if (selectType == SELECT_TYPE_SOME || selectType == SELECT_TYPE_ALL) { + switchLayout.setVisibility(View.VISIBLE); + actionButton.setVisibility(View.VISIBLE); + if (animated) { + actionButton.animate().setListener(null).cancel(); + switchLayout.animate().setListener(null).cancel(); + switchLayout.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + editText.setFocusableInTouchMode(true); + } + }).start(); + actionButton.animate().alpha(1f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + if (selectedEmojisMap.isEmpty()) { + selectAnimatedEmojiDialog.clearSelectedDocuments(); + editText.setText(""); + int i = 0; + SpannableStringBuilder editable = new SpannableStringBuilder(); + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + addReactionToEditText(availableReaction, selectedEmojisMap, selectedEmojisIds, editable, selectAnimatedEmojiDialog, editText.getFontMetricsInt()); + i++; + if (i >= maxReactionsCount) { + break; + } + } + editText.append(editable); + editText.addReactionsSpan(); + selectAnimatedEmojiDialog.notifyDataSetChanged(); + checkMaxCustomReactions(false); + } + } + } else { + if (animated) { + closeKeyboard(); + actionButton.animate().setListener(null).cancel(); + switchLayout.animate().setListener(null).cancel(); + actionButton.animate().alpha(0f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + actionButton.setVisibility(View.INVISIBLE); + } + }).start(); + switchLayout.animate().alpha(0f).setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + editText.setFocusableInTouchMode(false); + switchLayout.setVisibility(View.INVISIBLE); + } + }).start(); + } else { + switchLayout.setVisibility(View.INVISIBLE); + actionButton.setVisibility(View.INVISIBLE); + } + } + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + AndroidUtilities.cancelRunOnUIThread(checkAfterFastDeleteRunnable); + if (selectedType == SELECT_TYPE_NONE) { + getMessagesController().setCustomChatReactions(chatId, selectedType, new ArrayList<>(), null, null); + } + } + + @Override + public void onResume() { + super.onResume(); + if (isPaused) { + isPaused = false; + editText.setFocusable(true); + editText.setFocusableInTouchMode(true); + if (emojiKeyboardVisible) { + editText.removeReactionsSpan(false); + AndroidUtilities.runOnUIThread(() -> editText.requestFocus(), 250); + } + } + } + + @Override + public void onPause() { + isPaused = true; + editText.setFocusable(false); + super.onPause(); + } + + @Override + public boolean onBackPressed() { + if (closeKeyboard()) { + return false; + } + if (checkChangesBeforeExit()) { + return false; + } + return super.onBackPressed(); + } + + private boolean checkChangesBeforeExit() { + boolean hasChanges = !selectedEmojisMap.keySet().equals(initialSelectedEmojis.keySet()); + if (boostsStatus != null && boostsStatus.level < selectedCustomReactions) { + hasChanges = false; + } + if (selectedType == SELECT_TYPE_NONE) { + hasChanges = false; + } + if (hasChanges) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), getResourceProvider()); + builder.setTitle(getString("UnsavedChanges", R.string.UnsavedChanges)); + String text = getString("ReactionApplyChangesDialog", R.string.ReactionApplyChangesDialog); + builder.setMessage(text); + builder.setPositiveButton(getString("ApplyTheme", R.string.ApplyTheme), (dialogInterface, i) -> { + actionButton.performClick(); + }); + builder.setNegativeButton(getString("Discard", R.string.Discard), (dialogInterface, i) -> finishFragment()); + builder.show(); + } + return hasChanges; + } + + private void checkMaxCustomReactions(boolean withToast) { + if (boostsStatus == null) { + return; + } + if (selectedType == SELECT_TYPE_ALL) { + selectedType = SELECT_TYPE_SOME; + } + selectedCustomReactions = grabReactions(true).size(); + if (boostsStatus.level < selectedCustomReactions) { + if (withToast) { + CharSequence text = replaceTags(formatPluralString("ReactionReachLvlForReactionShort", selectedCustomReactions, selectedCustomReactions)); + BulletinFactory.of(this) + .createSimpleBulletin(R.raw.chats_infotip, text) + .show(); + } + actionButton.setLvlRequiredState(selectedCustomReactions); + } else { + actionButton.removeLvlRequiredState(); + } + } + + private List grabReactions(boolean onlyCustom) { + List reactions = new ArrayList<>(); + List customReactions = new ArrayList<>(); + for (Long documentId : selectedEmojisIds) { + boolean isReactionEmoji = false; + for (TLRPC.TL_availableReaction availableReaction : allAvailableReactions) { + if (documentId == availableReaction.activate_animation.id) { + TLRPC.TL_reactionEmoji emojiReaction = new TLRPC.TL_reactionEmoji(); + emojiReaction.emoticon = availableReaction.reaction; + reactions.add(emojiReaction); + isReactionEmoji = true; + break; + } + } + + if (!isReactionEmoji) { + TLRPC.TL_reactionCustomEmoji customEmoji = new TLRPC.TL_reactionCustomEmoji(); + customEmoji.document_id = documentId; + reactions.add(customEmoji); + customReactions.add(customEmoji); + } + } + if (onlyCustom) { + return customReactions; + } + return reactions; + } + + private void showKeyboard() { + if (!emojiKeyboardVisible) { + emojiKeyboardVisible = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + updateScrollViewMarginBottom(bottomDialogLayout.getMeasuredHeight()); + bottomDialogLayout.setVisibility(View.VISIBLE); + bottomDialogLayout.setTranslationY(bottomDialogLayout.getMeasuredHeight()); + bottomDialogLayout.animate().setListener(null).cancel(); + bottomDialogLayout.animate().translationY(0).withLayer().setDuration(350).setInterpolator(CubicBezierInterpolator.DEFAULT).setUpdateListener(animation -> { + actionButton.setTranslationY(-(float) animation.getAnimatedValue() * bottomDialogLayout.getMeasuredHeight()); + }).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + scrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }).start(); + } + } + + private boolean closeKeyboard() { + if (emojiKeyboardVisible) { + emojiKeyboardVisible = false; + editText.clearFocus(); + updateScrollViewMarginBottom(0); + 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(); + return true; + } + return false; + } + + private void updateScrollViewMarginBottom(int margin) { + ViewGroup.MarginLayoutParams marginLayoutParams = ((ViewGroup.MarginLayoutParams) scrollView.getLayoutParams()); + marginLayoutParams.bottomMargin = margin; + scrollView.setLayoutParams(marginLayoutParams); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index 74295e18a6..78cbb7cb31 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -164,7 +164,8 @@ public void setAlpha(float alpha) { // sizeNotifierFrameLayout.setFitsSystemWindows(true); containerView = new ContainerView(context); - selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(baseFragment, context, false, null, SelectAnimatedEmojiDialog.TYPE_REACTIONS, type != TYPE_STORY, resourcesProvider, 16) { + int dialogType = reactionsContainerLayout.showExpandableReactions() ? SelectAnimatedEmojiDialog.TYPE_EXPANDABLE_REACTIONS : SelectAnimatedEmojiDialog.TYPE_REACTIONS; + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(baseFragment, context, false, null, dialogType, type != TYPE_STORY, resourcesProvider, 16) { @Override public boolean prevWindowKeyboardVisible() { @@ -343,9 +344,15 @@ private void createTransition(boolean enter) { } windowView.getLocationOnScreen(windowLocation); float y = location[1] - windowLocation[1] - AndroidUtilities.dp(44) - AndroidUtilities.dp(52) - (selectAnimatedEmojiDialog.includeHint ? AndroidUtilities.dp(26) : 0) + reactionsContainerLayout.getTopOffset(); + + if (reactionsContainerLayout.showExpandableReactions()) { + y = location[1] - windowLocation[1] - AndroidUtilities.dp(12); + } + if (y + containerView.getMeasuredHeight() > windowView.getMeasuredHeight() - AndroidUtilities.dp(32)) { y = windowView.getMeasuredHeight() - AndroidUtilities.dp(32) - containerView.getMeasuredHeight(); } + if (y < AndroidUtilities.dp(16)) { y = AndroidUtilities.dp(16); } @@ -733,9 +740,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } int height = size; -// if (height * 1.2 < MeasureSpec.getSize(heightMeasureSpec)) { -// height *= 1.2; -// } + if (reactionsContainerLayout.showExpandableReactions()) { + int rows = (int) Math.ceil(reactions.size() / 8f); + if (rows <= 8) { + height = rows * AndroidUtilities.dp(36) + AndroidUtilities.dp(8); + } else { + height = AndroidUtilities.dp(36) * 8 - AndroidUtilities.dp(8); + } + } super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } @@ -811,7 +823,8 @@ protected void dispatchDraw(Canvas canvas) { } int top = (int) (selectAnimatedEmojiDialog.getX() + selectAnimatedEmojiDialog.emojiGridView.getX()); int left = (int) (selectAnimatedEmojiDialog.getY() + selectAnimatedEmojiDialog.emojiGridView.getY()); - canvas.clipRect(left, top + AndroidUtilities.dp(36) * enterTransitionProgress, left + selectAnimatedEmojiDialog.emojiGridView.getMeasuredHeight(), top + selectAnimatedEmojiDialog.emojiGridView.getMeasuredWidth()); + boolean isEmojiTabsVisible = selectAnimatedEmojiDialog.emojiTabs.getParent() != null; + canvas.clipRect(left, isEmojiTabsVisible ? top + AndroidUtilities.dp(36) * enterTransitionProgress : 0, left + selectAnimatedEmojiDialog.emojiGridView.getMeasuredWidth(), top + selectAnimatedEmojiDialog.emojiGridView.getMeasuredHeight()); for (int i = -1; i < reactionsContainerLayout.recyclerListView.getChildCount(); i++) { View child; if (i == -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java new file mode 100644 index 0000000000..a9bd07b048 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomReactionEditText.java @@ -0,0 +1,165 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Paint; +import android.os.Build; +import android.text.InputFilter; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.util.TypedValue; +import android.view.ActionMode; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.Menu; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.core.view.GestureDetectorCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.EditTextCaption; + +@SuppressLint("ViewConstructor") +public class CustomReactionEditText extends EditTextCaption { + + private final Theme.ResourcesProvider resourcesProvider; + private final GestureDetectorCompat gestureDetector; + private Runnable onFocused; + + public CustomReactionEditText(Context context, Theme.ResourcesProvider resourcesProvider, int maxLength) { + super(context, resourcesProvider); + this.resourcesProvider = resourcesProvider; + this.gestureDetector = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(@NonNull MotionEvent e) { + return true; + } + }); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + setIncludeFontPadding(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setShowSoftInputOnFocus(false); + } + setSingleLine(false); + setMaxLines(50); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(maxLength); + setFilters(inputFilters); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); + setGravity(Gravity.BOTTOM); + setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(4), AndroidUtilities.dp(18), AndroidUtilities.dp(12)); + setTextColor(getThemedColor(Theme.key_chat_messagePanelText)); + setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkOut)); + setHighlightColor(getThemedColor(Theme.key_chat_inTextSelectionHighlight)); + setHintColor(getThemedColor(Theme.key_chat_messagePanelHint)); + setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); + setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); + setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + setFallbackLineSpacing(false); + } + setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus) { + removeReactionsSpan(true); + if (onFocused != null) { + onFocused.run(); + } + } else { + addReactionsSpan(); + } + }); + setTextIsSelectable(true); + setLongClickable(false); + setFocusableInTouchMode(false); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (gestureDetector.onTouchEvent(event)) { + if(!isLongClickable()) { + return false; + } + } + return super.dispatchTouchEvent(event); + } + + @Override + protected void onSelectionChanged(int selStart, int selEnd) { + super.onSelectionChanged(selStart, selEnd); + if (hasSelection()) { + AddReactionsSpan[] spans = getText().getSpans(selStart, selEnd, AddReactionsSpan.class); + if (spans.length != 0) { + setSelection(selStart, selEnd - 1); + } + } + } + + @Override + protected void extendActionMode(ActionMode actionMode, Menu menu) { + menu.clear(); + menu.add(R.id.menu_delete, R.id.menu_delete, 0, LocaleController.getString("Delete", R.string.Delete)); + } + + public void setOnFocused(Runnable onFocused) { + this.onFocused = onFocused; + } + + public void addReactionsSpan() { + setLongClickable(false); + SpannableStringBuilder spannableText = new SpannableStringBuilder(getText()); + AddReactionsSpan[] spans = spannableText.getSpans(0, spannableText.length(), AddReactionsSpan.class); + if (spans.length == 0) { + SpannableStringBuilder builder = new SpannableStringBuilder("x"); + AddReactionsSpan span = new AddReactionsSpan(15, resourcesProvider); + span.show(this); + builder.setSpan(span, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + setText(getText().append(builder)); + } + } + + public void removeReactionsSpan(boolean animate) { + SpannableStringBuilder spannableText = new SpannableStringBuilder(getText()); + AddReactionsSpan[] spans = spannableText.getSpans(0, spannableText.length(), AddReactionsSpan.class); + for (AddReactionsSpan span : spans) { + Runnable action = () -> { + getText().delete(getText().getSpanStart(span), getText().getSpanEnd(span)); + setCursorVisible(true); + setLongClickable(true); + }; + if (animate) { + setCursorVisible(false); + span.hide(this, action); + } else { + action.run(); + } + } + } + + public int getEditTextSelectionEnd() { + int selectionEnd = getSelectionEnd(); + if (selectionEnd < 0) { + selectionEnd = 0; + } + return selectionEnd; + } + + public int getEditTextSelectionStart() { + int selectionStart = getSelectionStart(); + if (selectionStart < 0) { + selectionStart = 0; + } + return selectionStart; + } + + public int getThemedColor(int key) { + return Theme.getColor(key, resourcesProvider); + } + + public Paint.FontMetricsInt getFontMetricsInt() { + return getPaint().getFontMetricsInt(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java index 6d5713f4ea..59c923449b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java @@ -144,14 +144,14 @@ public ReactionsEffectOverlay(Context context, BaseFragment fragment, ReactionsC if (chat == null) { continue; } - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageReceiver.setForUserOrChat(chat, avatarDrawable); } else { user = MessagesController.getInstance(currentAccount).getUser(peerId); if (user == null) { continue; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageReceiver.setForUserOrChat(user, avatarDrawable); } @@ -225,8 +225,8 @@ public ReactionsEffectOverlay(Context context, BaseFragment fragment, ReactionsC fromHeight = holderView.loopImageView.getWidth() * holderView.getScaleX(); } else if (reactionButton != null) { cell.getLocationInWindow(loc); - fromX = loc[0] + cell.reactionsLayoutInBubble.x + reactionButton.x + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageX()); - fromY = loc[1] + cell.reactionsLayoutInBubble.y + reactionButton.y + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageY()); + fromX = loc[0] + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageX()); + fromY = loc[1] + (reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageY()); fromHeight = reactionButton.imageReceiver == null ? 0 : reactionButton.imageReceiver.getImageHeight(); } else if (cell != null) { ((View) cell.getParent()).getLocationInWindow(loc); @@ -315,11 +315,11 @@ protected void dispatchDraw(Canvas canvas) { cell.getLocationInWindow(loc); ReactionsLayoutInBubble.ReactionButton reactionButton = cell.getReactionButton(reaction); - toX = loc[0] + cell.reactionsLayoutInBubble.x; - toY = loc[1] + cell.reactionsLayoutInBubble.y; + toX = loc[0]; + toY = loc[1]; if (reactionButton != null) { - toX += reactionButton.x + reactionButton.drawingImageRect.left; - toY += reactionButton.y + reactionButton.drawingImageRect.top; + toX += reactionButton.drawingImageRect.left; + toY += reactionButton.drawingImageRect.top; } if (chatActivity != null) { toY += chatActivity.drawingChatLisViewYoffset; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java index ef0f86d56c..f20c5ecd70 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java @@ -316,8 +316,6 @@ public void draw(Canvas canvas, float animationProgress, String drawOnlyReaction totalX = totalX * (animationProgress) + fromX * (1f - animationProgress); totalY = totalY * (animationProgress) + fromY * (1f - animationProgress); } - canvas.save(); - canvas.translate(totalX, totalY); for (int i = 0; i < reactionButtons.size(); i++) { ReactionButton reactionButton = reactionButtons.get(i); if (reactionButton.reaction.equals(scrimViewReaction) || (drawOnlyReaction != null && !reactionButton.reaction.equals(drawOnlyReaction))) { @@ -330,27 +328,24 @@ public void draw(Canvas canvas, float animationProgress, String drawOnlyReaction x = reactionButton.x * animationProgress + reactionButton.animateFromX * (1f - animationProgress); y = reactionButton.y * animationProgress + reactionButton.animateFromY * (1f - animationProgress); } - canvas.translate(x, y); float alpha = 1f; if (animationProgress != 1f && reactionButton.animationType == ANIMATION_TYPE_IN) { float s = 0.5f + 0.5f * animationProgress; alpha = animationProgress; - canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f); + canvas.scale(s, s, totalX + x + reactionButton.width / 2f, totalY + y + reactionButton.height / 2f); } - reactionButton.draw(canvas, reactionButton.animationType == ANIMATION_TYPE_MOVE ? animationProgress : 1f, alpha, drawOnlyReaction != null); + reactionButton.draw(canvas, totalX + x, totalY + y, reactionButton.animationType == ANIMATION_TYPE_MOVE ? animationProgress : 1f, alpha, drawOnlyReaction != null); canvas.restore(); } for (int i = 0; i < outButtons.size(); i++) { ReactionButton reactionButton = outButtons.get(i); - canvas.save(); - canvas.translate(reactionButton.x, reactionButton.y); float s = 0.5f + 0.5f * (1f - animationProgress); - canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f); - outButtons.get(i).draw(canvas, 1f, (1f - animationProgress), false); + canvas.save(); + canvas.scale(s, s, totalX + reactionButton.x + reactionButton.width / 2f, totalY + reactionButton.y + reactionButton.height / 2f); + outButtons.get(i).draw(canvas, totalX + reactionButton.x, totalY + reactionButton.y, 1f, (1f - animationProgress), false); canvas.restore(); } - canvas.restore(); } public void recordDrawingState() { @@ -584,12 +579,12 @@ public ReactionButton(ReactionButton reuseFrom, TLRPC.ReactionCount reactionCoun counterDrawable.gravity = Gravity.LEFT; } - public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlayScrim) { + public void draw(Canvas canvas, float x, float y, float progress, float alpha, boolean drawOverlayScrim) { wasDrawn = true; ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; if (isSmall && imageReceiver != null) { imageReceiver.setAlpha(alpha); - drawingImageRect.set(0, 0, AndroidUtilities.dp(14), AndroidUtilities.dp(14)); + drawingImageRect.set((int) x, (int) y, AndroidUtilities.dp(14), AndroidUtilities.dp(14)); imageReceiver.setImageCoords(drawingImageRect); imageReceiver.setRoundRadius(0); drawImage(canvas, alpha); @@ -625,11 +620,11 @@ public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlay if (progress != 1f && animationType == ANIMATION_TYPE_MOVE) { w = (int) (width * progress + animateFromWidth * (1f - progress)); } - AndroidUtilities.rectTmp.set(0, 0, w, height); + AndroidUtilities.rectTmp.set(x, y, x + w, y + height); float rad = height / 2f; if (drawServiceShaderBackground > 0) { Paint paint1 = getThemedPaint(Theme.key_paint_chatActionBackground); - Paint paint2 = Theme.chat_actionBackgroundGradientDarkenPaint; + Paint paint2 = getThemedPaint(Theme.key_paint_chatActionBackgroundDarken); int oldAlpha = paint1.getAlpha(); int oldAlpha2 = paint2.getAlpha(); paint1.setAlpha((int) (oldAlpha * alpha * drawServiceShaderBackground)); @@ -650,32 +645,32 @@ public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlay canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint); if (imageReceiver != null) { - int size, x; + int size, X; if (animatedEmojiDrawable != null) { size = AndroidUtilities.dp(24); - x = AndroidUtilities.dp(6); + X = AndroidUtilities.dp(6); imageReceiver.setRoundRadius(AndroidUtilities.dp(6)); } else { size = AndroidUtilities.dp(20); - x = AndroidUtilities.dp(8); + X = AndroidUtilities.dp(8); imageReceiver.setRoundRadius(0); } - int y = (int) ((height - size) / 2f); - drawingImageRect.set(x, y, x + size, y + size); + int Y = (int) ((height - size) / 2f); + drawingImageRect.set((int) x + X, (int) y + Y, (int) x + X + size, (int) y + Y + size); imageReceiver.setImageCoords(drawingImageRect); drawImage(canvas, alpha); } if (counterDrawable != null && (count != 0 || counterDrawable.countChangeProgress != 1f)) { canvas.save(); - canvas.translate(AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0); + canvas.translate(x + AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); counterDrawable.draw(canvas); canvas.restore(); } if (avatarsDrawable != null) { canvas.save(); - canvas.translate(AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0); + canvas.translate(x + AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), y); avatarsDrawable.setAlpha(alpha); avatarsDrawable.setTransitionProgress(progress); avatarsDrawable.onDraw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java index 1e4f6ff22a..7fb97beb54 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java @@ -1,11 +1,32 @@ package org.telegram.ui.Components.Reactions; +import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_REACTIONS; + +import android.graphics.Paint; +import android.os.Bundle; +import android.text.Editable; +import android.text.SpannableString; import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.EditTextCaption; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.SelectAnimatedEmojiDialog; +import org.telegram.ui.StatisticActivity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; public class ReactionsUtils { @@ -23,7 +44,7 @@ public static boolean compare(TLRPC.Reaction reaction, ReactionsLayoutInBubble.V return false; } - public static boolean compare(TLRPC.Reaction reaction, TLRPC.Reaction reaction2) { + public static boolean compare(TLRPC.Reaction reaction, TLRPC.Reaction reaction2) { if (reaction instanceof TLRPC.TL_reactionEmoji && reaction2 instanceof TLRPC.TL_reactionEmoji && TextUtils.equals(((TLRPC.TL_reactionEmoji) reaction).emoticon, ((TLRPC.TL_reactionEmoji) reaction2).emoticon)) { return true; } @@ -47,10 +68,10 @@ public static TLRPC.Reaction toTLReaction(ReactionsLayoutInBubble.VisibleReactio } public static CharSequence reactionToCharSequence(TLRPC.Reaction reaction) { - if (reaction instanceof TLRPC.TL_reactionEmoji){ + if (reaction instanceof TLRPC.TL_reactionEmoji) { return ((TLRPC.TL_reactionEmoji) reaction).emoticon; } - if (reaction instanceof TLRPC.TL_reactionCustomEmoji){ + if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("d"); spannableStringBuilder.setSpan(new AnimatedEmojiSpan(((TLRPC.TL_reactionCustomEmoji) reaction).document_id, null), 0, 1, 0); return spannableStringBuilder; @@ -89,4 +110,112 @@ public static void applyForStoryViews(TLRPC.Reaction oldReaction, TLRPC.Reaction views.reactions.add(reactionCount); } } + + public static void showLimitReachedDialogForReactions(long dialogId, int lvl, TL_stories.TL_premium_boostsStatus boostsStatus) { + BaseFragment fragment = LaunchActivity.getLastFragment(); + if (fragment == null || boostsStatus == null) { + return; + } + LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(fragment, fragment.getContext(), TYPE_BOOSTS_FOR_REACTIONS, UserConfig.selectedAccount, fragment.getResourceProvider()); + limitReachedBottomSheet.setRequiredLvl(lvl); + limitReachedBottomSheet.setBoostsStats(boostsStatus, true); + limitReachedBottomSheet.setDialogId(dialogId); + limitReachedBottomSheet.showStatisticButtonInLink(() -> { + TLRPC.Chat chat = fragment.getMessagesController().getChat(-dialogId); + Bundle args = new Bundle(); + args.putLong("chat_id", -dialogId); + args.putBoolean("is_megagroup", chat.megagroup); + args.putBoolean("start_from_boosts", true); + TLRPC.ChatFull chatInfo = fragment.getMessagesController().getChatFull(-dialogId); + if (chatInfo == null || !chatInfo.can_view_stats) { + args.putBoolean("only_boosts", true); + } + fragment.presentFragment(new StatisticActivity(args)); + }); + limitReachedBottomSheet.show(); + } + + public static SpannableString createSpannableText(AnimatedEmojiSpan span, String key) { + SpannableString spannable = new SpannableString(key); + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return spannable; + } + + public static AnimatedEmojiSpan createAnimatedEmojiSpan(TLRPC.Document document, Long documentId, Paint.FontMetricsInt fontMetricsInt) { + AnimatedEmojiSpan span; + if (document != null) { + span = new AnimatedEmojiSpan(document, 1.0f, fontMetricsInt); + } else { + span = new AnimatedEmojiSpan(documentId, 1.0f, fontMetricsInt); + } + span.cacheType = AnimatedEmojiDrawable.getCacheTypeForEnterView(); + return span; + } + + public static void addReactionToEditText(TLRPC.TL_availableReaction availableReaction, HashMap selectedEmojis, List selectedEmojisIds, Editable editText, SelectAnimatedEmojiDialog selectAnimatedEmojiDialog, Paint.FontMetricsInt fontMetricsInt) { + long id = availableReaction.activate_animation.id; + AnimatedEmojiSpan span = createAnimatedEmojiSpan(availableReaction.activate_animation, id, fontMetricsInt); + selectedEmojis.put(id, span); + selectedEmojisIds.add(id); + editText.append(createSpannableText(span, "e")); + if (selectAnimatedEmojiDialog != null) { + selectAnimatedEmojiDialog.setMultiSelected(id, false); + } + } + + public static void addReactionToEditText(TLRPC.TL_reactionCustomEmoji customEmoji, HashMap selectedEmojis, List selectedEmojisIds, Editable editText, SelectAnimatedEmojiDialog selectAnimatedEmojiDialog, Paint.FontMetricsInt fontMetricsInt) { + AnimatedEmojiSpan span = createAnimatedEmojiSpan(null, customEmoji.document_id, fontMetricsInt); + selectedEmojis.put(customEmoji.document_id, span); + selectedEmojisIds.add(customEmoji.document_id); + editText.append(createSpannableText(span, "e")); + if (selectAnimatedEmojiDialog != null) { + selectAnimatedEmojiDialog.setMultiSelected(customEmoji.document_id, false); + } + } + + public static List startPreloadReactions(TLRPC.Chat currentChat, TLRPC.ChatFull chatFull) { + List result = new ArrayList<>(); + if (chatFull == null || !ChatObject.isChannelAndNotMegaGroup(currentChat)) { + return result; + } + if (chatFull.available_reactions instanceof TLRPC.TL_chatReactionsSome) { + TLRPC.TL_chatReactionsSome reactionsSome = (TLRPC.TL_chatReactionsSome) chatFull.available_reactions; + for (TLRPC.Reaction reaction : reactionsSome.reactions) { + AnimatedEmojiDrawable animatedEmojiDrawable = null; + if (reaction instanceof TLRPC.TL_reactionEmoji) { + TLRPC.TL_reactionEmoji reactionEmoji = ((TLRPC.TL_reactionEmoji) reaction); + TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsMap().get(reactionEmoji.emoticon); + if (availableReaction == null) { + continue; + } + TLRPC.Document document = availableReaction.activate_animation; + animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), document); + } else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) { + TLRPC.TL_reactionCustomEmoji customEmoji = (TLRPC.TL_reactionCustomEmoji) reaction; + animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), customEmoji.document_id); + } + if (animatedEmojiDrawable != null) { + result.add(animatedEmojiDrawable); + animatedEmojiDrawable.addView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } + } else if (chatFull.available_reactions instanceof TLRPC.TL_chatReactionsAll) { + for (TLRPC.TL_availableReaction availableReaction : MediaDataController.getInstance(UserConfig.selectedAccount).getEnabledReactionsList()) { + if (availableReaction == null) { + continue; + } + TLRPC.Document document = availableReaction.activate_animation; + AnimatedEmojiDrawable animatedEmojiDrawable = AnimatedEmojiDrawable.make(UserConfig.selectedAccount, AnimatedEmojiDrawable.getCacheTypeForEnterView(), document); + result.add(animatedEmojiDrawable); + animatedEmojiDrawable.addView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } + return result; + } + + public static void stopPreloadReactions(List list) { + for (AnimatedEmojiDrawable animatedEmojiDrawable : list) { + animatedEmojiDrawable.removeView((AnimatedEmojiSpan.InvalidateHolder) null); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java new file mode 100644 index 0000000000..861cb02d19 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/UpdateReactionsButton.java @@ -0,0 +1,44 @@ +package org.telegram.ui.Components.Reactions; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.SpannableStringBuilder; +import android.text.Spanned; + +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +@SuppressLint("ViewConstructor") +public class UpdateReactionsButton extends ButtonWithCounterView { + + private SpannableStringBuilder lock; + + public UpdateReactionsButton(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + } + + public UpdateReactionsButton(Context context, boolean filled, Theme.ResourcesProvider resourcesProvider) { + super(context, filled, resourcesProvider); + } + + public void setDefaultState() { + setText(new SpannableStringBuilder(LocaleController.getString("ReactionUpdateReactionsBtn", R.string.ReactionUpdateReactionsBtn)), false); + lock = new SpannableStringBuilder("l"); + ColoredImageSpan coloredImageSpan = new ColoredImageSpan(R.drawable.mini_switch_lock); + coloredImageSpan.setTopOffset(1); + lock.setSpan(coloredImageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + public void setLvlRequiredState(int lvl) { + SpannableStringBuilder buttonLockedText = new SpannableStringBuilder(); + buttonLockedText.append(lock).append(LocaleController.formatPluralString("ReactionLevelRequiredBtn", lvl)); + setSubText(buttonLockedText, true); + } + + public void removeLvlRequiredState() { + setSubText(null, true); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index 5e93a2cab2..640e36a39d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -170,6 +170,7 @@ public void set(ReactionsContainerLayout object, Float value) { HashSet lastVisibleViews = new HashSet<>(); HashSet lastVisibleViewsTmp = new HashSet<>(); private boolean allReactionsAvailable; + private boolean showExpandableReactions; private boolean allReactionsIsDefault; private Paint selectedPaint; ChatScrimPopupContainerLayout parentLayout; @@ -325,6 +326,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int switch (viewType) { default: case VIEW_TYPE_REACTION: + case VIEW_TYPE_CUSTOM_REACTION: view = new ReactionHolderView(context, true); break; case VIEW_TYPE_PREMIUM_BUTTON: @@ -371,7 +373,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_REACTION) { + if (holder.getItemViewType() == VIEW_TYPE_REACTION || holder.getItemViewType() == VIEW_TYPE_CUSTOM_REACTION) { ReactionHolderView h = (ReactionHolderView) holder.itemView; h.setScaleX(1); h.setScaleY(1); @@ -395,6 +397,7 @@ public int getItemViewType(int position) { private static final int VIEW_TYPE_REACTION = 0; private static final int VIEW_TYPE_PREMIUM_BUTTON = 1; private static final int VIEW_TYPE_CUSTOM_EMOJI_BUTTON = 2; + private static final int VIEW_TYPE_CUSTOM_REACTION = 3; @Override public void notifyDataSetChanged() { @@ -402,7 +405,8 @@ public void notifyDataSetChanged() { oldItems.addAll(items); items.clear(); for (int i = 0; i < visibleReactionsList.size(); i++) { - items.add(new InnerItem(VIEW_TYPE_REACTION, visibleReactionsList.get(i))); + ReactionsLayoutInBubble.VisibleReaction visibleReaction = visibleReactionsList.get(i); + items.add(new InnerItem(visibleReaction.emojicon == null ? VIEW_TYPE_CUSTOM_REACTION : VIEW_TYPE_REACTION, visibleReaction)); } if (showUnlockPremiumButton()) { items.add(new InnerItem(VIEW_TYPE_PREMIUM_BUTTON, null)); @@ -427,7 +431,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; InnerItem innerItem = (InnerItem) o; - if (viewType == innerItem.viewType && viewType == VIEW_TYPE_REACTION) { + if (viewType == innerItem.viewType && (viewType == VIEW_TYPE_REACTION || viewType == VIEW_TYPE_CUSTOM_REACTION)) { return reaction != null && reaction.equals(innerItem.reaction); } return viewType == innerItem.viewType; @@ -512,6 +516,10 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R MediaDataController.getInstance(currentAccount).preloadDefaultReactions(); } + public boolean showExpandableReactions() { + return showExpandableReactions; + } + private void animatePullingBack() { if (pullingLeftOffset != 0) { pullingDownBackAnimator = ValueAnimator.ofFloat(pullingLeftOffset, 0); @@ -565,11 +573,11 @@ private void invalidateLoopViews() { } public boolean showCustomEmojiReaction() { - return !MessagesController.getInstance(currentAccount).premiumLocked && allReactionsAvailable; + 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) { @@ -1083,6 +1091,7 @@ public void setMessage(MessageObject message, TLRPC.ChatFull chatFull) { fillRecentReactionsList(visibleReactions); } filterReactions(visibleReactions); + 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) { @@ -1840,7 +1849,7 @@ protected void dispatchDraw(Canvas canvas) { public void checkPlayLoopImage() { ImageReceiver imageReceiver = loopImageView.animatedEmojiDrawable != null ? loopImageView.animatedEmojiDrawable.getImageReceiver() : loopImageView.imageReceiver; if (imageReceiver != null && imageReceiver.getLottieAnimation() != null) { - if (reactionsWindow != null || pressed) { + if (reactionsWindow != null || pressed || !allReactionsIsDefault) { imageReceiver.getLottieAnimation().start(); } else { if (imageReceiver.getLottieAnimation().getCurrentFrame() <= 2) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java index 427365926d..ea3d171127 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.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; @@ -1262,6 +1264,7 @@ public View findChildViewUnder(float x, float y) { 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 d165674f08..bc2e55cc3d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java @@ -17,18 +17,17 @@ import androidx.core.math.MathUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.DialogObject; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; -import xyz.nextalone.nagram.NaConfig; -import xyz.nextalone.nagram.helper.PeerColorHelper; - public class ReplyMessageLine { private final RectF rectF = new RectF(); @@ -53,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; @@ -108,6 +107,7 @@ public void setBackgroundColor(int backgroundColor) { private int wasMessageId; private int wasColorId; private void resolveColor(MessageObject messageObject, int colorId, Theme.ResourcesProvider resourcesProvider) { + final boolean dark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); if (wasColorId != colorId) { final int msgId = messageObject != null ? messageObject.getId() : 0; if (msgId == wasMessageId) { @@ -129,9 +129,9 @@ private void resolveColor(MessageObject messageObject, int colorId, Theme.Resour hasColor2 = hasColor3 = false; return; } - color1 = peerColor.getColor1(); - color2 = peerColor.getColor2(); - color3 = peerColor.getColor3(); + color1 = peerColor.getColor(0, resourcesProvider); + color2 = peerColor.getColor(1, resourcesProvider); + color3 = peerColor.getColor(2, resourcesProvider); hasColor2 = color2 != color1; hasColor3 = color3 != color1; if (hasColor3) { @@ -147,12 +147,13 @@ private void resolveColor(MessageObject messageObject, int colorId, Theme.Resour public static final int TYPE_LINK = 3; public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat currentChat, Theme.ResourcesProvider resourcesProvider, final int type) { + final boolean dark = resourcesProvider != null ? resourcesProvider.isDark() : Theme.isCurrentThemeDark(); reversedOut = false; emojiDocumentId = 0; if (messageObject == null) { hasColor2 = hasColor3 = false; color1 = color2 = color3 = Theme.getColor(Theme.key_chat_inReplyLine, resourcesProvider); - backgroundColor = Theme.multAlpha(color1, Theme.isCurrentThemeDark() ? 0.12f : 0.10f); + backgroundColor = Theme.multAlpha(color1, dark ? 0.12f : 0.10f); return nameColorAnimated.set(nameColor = Theme.getColor(Theme.key_chat_inReplyNameText, resourcesProvider)); } else if (type != TYPE_REPLY && ( messageObject.overrideLinkColor >= 0 || @@ -169,47 +170,49 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat 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) { - if ((messageObject.sponsoredChatInvite.chat.flags2 & 64) != 0) { - colorId = messageObject.sponsoredChatInvite.chat.color; - } else { - colorId = (int) (messageObject.sponsoredChatInvite.chat.id % 7); + colorId = ChatObject.getColorId(messageObject.sponsoredChatInvite.chat); + 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) { TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(-dialogId); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + colorId = ChatObject.getColorId(chat); + } + if (type == TYPE_LINK) { + emojiDocumentId = ChatObject.getEmojiId(chat); } } else { TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(dialogId); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + colorId = UserObject.getColorId(user); + } + 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; - if ((user.flags2 & 128) != 0) { - colorId = user.color; - } else { - colorId = (int) (user.id % 7); + colorId = UserObject.getColorId(user); + if (type == TYPE_LINK) { + emojiDocumentId = UserObject.getEmojiId(user); } } else if (messageObject.isFromUser() && currentUser != null) { - if ((currentUser.flags2 & 128) != 0) { - colorId = currentUser.color; - } else { - colorId = (int) (currentUser.id % 7); - } - if (currentUser.self) { - colorId = PeerColorHelper.replaceColor(colorId); + colorId = UserObject.getColorId(currentUser); + if (type == TYPE_LINK) { + emojiDocumentId = UserObject.getEmojiId(currentUser); } } else if (messageObject.isFromChannel() && currentChat != null) { - if ((currentChat.flags2 & 64) != 0) { - colorId = currentChat.color; - } else { - colorId = (int) (currentChat.id % 7); + colorId = ChatObject.getColorId(currentChat); + if (type == TYPE_LINK) { + emojiDocumentId = ChatObject.getEmojiId(currentChat); } } else { colorId = 0; @@ -234,34 +237,24 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat } else if (DialogObject.isEncryptedDialog(messageObject.replyMessageObject.getDialogId())) { TLRPC.User user = messageObject.replyMessageObject.isOutOwner() ? UserConfig.getInstance(messageObject.replyMessageObject.currentAccount).getCurrentUser() : currentUser; if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); - if ((user.flags2 & 64) != 0) { - emojiDocumentId = user.background_emoji_id; - } + colorId = UserObject.getColorId(user); + emojiDocumentId = UserObject.getEmojiId(user); } else { colorId = 0; } } else if (messageObject.replyMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance(messageObject.currentAccount).getUser(messageObject.replyMessageObject.messageOwner.from_id.user_id); if (user != null) { - colorId = (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); - if ((user.flags2 & 64) != 0) { - emojiDocumentId = user.background_emoji_id; - } - if (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool() && user.self) { - colorId = NaConfig.INSTANCE.getUseLocalQuoteColorColor().Int(); - emojiDocumentId = NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().Long(); - } + colorId = UserObject.getColorId(user); + emojiDocumentId = UserObject.getEmojiId(user); } else { colorId = 0; } } else if (messageObject.replyMessageObject.isFromChannel()) { TLRPC.Chat chat = MessagesController.getInstance(messageObject.currentAccount).getChat(messageObject.replyMessageObject.messageOwner.from_id.channel_id); if (chat != null) { - colorId = (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); - if ((chat.flags2 & 32) != 0) { - emojiDocumentId = chat.background_emoji_id; - } + colorId = ChatObject.getColorId(chat); + emojiDocumentId = ChatObject.getEmojiId(chat); } else { colorId = 0; } @@ -284,8 +277,12 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat 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); @@ -294,10 +291,10 @@ public int check(MessageObject messageObject, TLRPC.User currentUser, TLRPC.Chat reversedOut = true; color1 = Theme.multAlpha(color1, .35f); } - backgroundColor = Theme.multAlpha(color3, Theme.isCurrentThemeDark() ? 0.12f : 0.10f); + backgroundColor = Theme.multAlpha(color3, dark ? 0.12f : 0.10f); nameColor = Theme.getColor(Theme.key_chat_outReplyNameText, resourcesProvider); } - if (type == TYPE_REPLY && messageObject != null && messageObject.overrideLinkEmoji != -1) { + if ((type == TYPE_REPLY || type == TYPE_LINK) && messageObject != null && messageObject.overrideLinkEmoji != -1) { emojiDocumentId = messageObject.overrideLinkEmoji; } if (emojiDocumentId != 0 && emoji == null) { @@ -473,6 +470,13 @@ public void drawBackground(Canvas canvas, RectF rect, float alpha) { 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(); @@ -493,18 +497,19 @@ public void drawBackground(Canvas canvas, RectF rect, float alpha, boolean hasQu 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/ScrollSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java index 4db532954d..2536b7506a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -48,6 +48,7 @@ import org.telegram.messenger.MessageObject; import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -347,7 +348,7 @@ public void addStickerTab(TLRPC.Chat chat) { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(14)); - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(UserConfig.selectedAccount, chat); BackupImageView imageView = stickerTabView.imageView; imageView.setLayerNum(imageReceiversPlayingNum); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java index e3011ff288..d55ac5441b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTextTabStrip.java @@ -121,6 +121,10 @@ public void run() { } }; + protected int processColor(int color) { + return color; + } + public ScrollSlidingTextTabStrip(Context context) { this(context, null); } @@ -144,6 +148,16 @@ public void setAlpha(float alpha) { super.setAlpha(alpha); ScrollSlidingTextTabStrip.this.invalidate(); } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + if (setInitialTab && idToPosition.indexOfKey(selectedTabId) >= 0 && tabsContainer.getChildAt(idToPosition.get(selectedTabId)) != null) { + scrollToChild(idToPosition.get(selectedTabId), false); + setInitialTab = false; + } + } }; tabsContainer.setOrientation(LinearLayout.HORIZONTAL); tabsContainer.setPadding(AndroidUtilities.dp(7), 0, AndroidUtilities.dp(7), 0); @@ -163,8 +177,8 @@ private void setAnimationProgressInernal(TextView newTab, TextView prevTab, floa if (newTab == null || prevTab == null) { return; } - int newColor = Theme.getColor(activeTextColorKey, resourcesProvider); - int prevColor = Theme.getColor(unactiveTextColorKey, resourcesProvider); + int newColor = processColor(Theme.getColor(activeTextColorKey, resourcesProvider)); + int prevColor = processColor(Theme.getColor(unactiveTextColorKey, resourcesProvider)); int r1 = Color.red(newColor); int g1 = Color.green(newColor); @@ -281,7 +295,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { }; tab.setWillNotDraw(false); tab.setGravity(Gravity.CENTER); - tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(Theme.getColor(activeTextColorKey, resourcesProvider), .15f), 3)); + tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(processColor(Theme.getColor(activeTextColorKey, resourcesProvider)), .15f), 3)); tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); tab.setSingleLine(true); tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -337,7 +351,7 @@ public void scrollTo(int pageId, int position1, View v) { if (delegate != null) { delegate.onPageSelected(pageId, scrollingForward); } - scrollToChild(position1); + scrollToChild(position1, true); } public void scrollTo(int pageId) { @@ -349,7 +363,7 @@ public void finishAddingTabs() { for (int a = 0; a < count; a++) { TextView tab = (TextView) tabsContainer.getChildAt(a); tab.setTag(currentPosition == a ? activeTextColorKey : unactiveTextColorKey); - tab.setTextColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider)); + tab.setTextColor(processColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider))); if (a == 0) { tab.getLayoutParams().width = count == 1 ? LayoutHelper.WRAP_CONTENT : 0; } @@ -361,14 +375,27 @@ public void setColors(int line, int active, int unactive, int selector) { activeTextColorKey = active; unactiveTextColorKey = unactive; selectorColorKey = selector; - selectorDrawable.setColor(Theme.getColor(tabLineColorKey, resourcesProvider)); + selectorDrawable.setColor(processColor(Theme.getColor(tabLineColorKey, resourcesProvider))); + } + + public void updateColors() { + int count = tabsContainer.getChildCount(); + for (int a = 0; a < count; a++) { + TextView tab = (TextView) tabsContainer.getChildAt(a); + tab.setTextColor(processColor(Theme.getColor(currentPosition == a ? activeTextColorKey : unactiveTextColorKey, resourcesProvider))); + tab.setBackground(Theme.createSelectorDrawable(Theme.multAlpha(processColor(Theme.getColor(activeTextColorKey, resourcesProvider)), .15f), 3)); + } + selectorDrawable.setColor(processColor(Theme.getColor(tabLineColorKey, resourcesProvider))); + invalidate(); } public int getCurrentTabId() { return selectedTabId; } + private boolean setInitialTab; public void setInitialTabId(int id) { + setInitialTab = true; selectedTabId = id; int pos = idToPosition.get(id); TextView child = (TextView) tabsContainer.getChildAt(pos); @@ -434,7 +461,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - private void scrollToChild(int position) { + private void scrollToChild(int position, boolean smooth) { if (tabCount == 0 || scrollingToChild == position) { return; } @@ -447,9 +474,17 @@ private void scrollToChild(int position) { int left = child.getLeft(); int width = child.getMeasuredWidth(); if (left - AndroidUtilities.dp(50) < currentScrollX) { - smoothScrollTo(left - AndroidUtilities.dp(50), 0); + if (smooth) { + smoothScrollTo(left - AndroidUtilities.dp(50), 0); + } else { + scrollTo(left - AndroidUtilities.dp(50), 0); + } } else if (left + width + AndroidUtilities.dp(21) > currentScrollX + getWidth()) { - smoothScrollTo(left + width, 0); + if (smooth) { + smoothScrollTo(left + width, 0); + } else { + scrollTo(left + width, 0); + } } } @@ -532,7 +567,7 @@ public void selectTabWithId(int id, float progress) { child.setTag(unactiveTextColorKey); nextChild.setTag(activeTextColorKey); } - scrollToChild(tabsContainer.indexOfChild(nextChild)); + scrollToChild(tabsContainer.indexOfChild(nextChild), true); } if (progress >= 1.0f) { currentPosition = position; @@ -561,9 +596,9 @@ public void onPageScrolled(int position, int first) { tabsContainer.getChildAt(a).setSelected(a == position); } if (first == position && position > 1) { - scrollToChild(position - 1); + scrollToChild(position - 1, true); } else { - scrollToChild(position); + scrollToChild(position, true); } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 0661e78608..04fe635449 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -132,7 +132,7 @@ public SearchViewPager(Context context, DialogsActivity fragment, int type, int itemAnimator.setMoveInterpolator(new OvershootInterpolator(1.1f)); itemAnimator.setTranslationInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - dialogsSearchAdapter = new DialogsSearchAdapter(context, fragment, type, initialDialogsType, itemAnimator, fragment.getAllowGlobalSearch()) { + dialogsSearchAdapter = new DialogsSearchAdapter(context, fragment, type, initialDialogsType, itemAnimator, fragment.getAllowGlobalSearch(), null) { @Override public void notifyDataSetChanged() { int itemCount = getCurrentItemCount(); @@ -465,7 +465,7 @@ private void showActionMode(boolean show) { } 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 7f097e1426..ddd1b0cad0 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 interface SeekBarDelegate { 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 ce66c1e6e7..9bd9c1b702 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 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 void setColors(int inner, int outer, int selected) { 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 void setParentView(View view) { 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 void setProgress(float progress) { } 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 @@ private float[] calculateHeights(int count) { 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 void draw(Canvas canvas, View parentView) { 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 void draw(Canvas canvas, View parentView) { 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 void draw(Canvas canvas, View parentView) { } 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 void draw(Canvas canvas, View parentView) { 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 @@ private void drawFill(Canvas canvas, float alpha) { } 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 @@ private void drawFill(Canvas canvas, float alpha) { 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 void setLoading(boolean loading) { 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/SenderSelectView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java index c7e183cc64..caee6be65f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SenderSelectView.java @@ -9,16 +9,12 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.dynamicanimation.animation.FloatPropertyCompat; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; @@ -28,6 +24,8 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import xyz.nextalone.nagram.NaConfig; + public class SenderSelectView extends View { private final static float SPRING_MULTIPLIER = 100f; private final static FloatPropertyCompat MENU_PROGRESS = new SimpleFloatPropertyCompat("menuProgress", obj -> obj.menuProgress, (obj, value) -> { @@ -60,7 +58,8 @@ public SenderSelectView(Context context) { private void updateColors() { backgroundPaint.setColor(Theme.getColor(Theme.key_chat_messagePanelVoiceBackground)); menuPaint.setColor(Theme.getColor(Theme.key_chat_messagePanelVoicePressed)); - selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(16), Color.TRANSPARENT, Theme.getColor(Theme.key_windowBackgroundWhite)); + int value = NaConfig.INSTANCE.getShowSquareAvatar().Bool() ? 0 : 16; + selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(value), Color.TRANSPARENT, Theme.getColor(Theme.key_windowBackgroundWhite)); selectorDrawable.setCallback(this); } @@ -103,7 +102,12 @@ protected void onDraw(Canvas canvas) { int alpha = (int) (menuProgress * 0xFF); backgroundPaint.setAlpha(alpha); - canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth(), getHeight()) / 2f, backgroundPaint); + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, 0, 0, backgroundPaint); + } else { + canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth(), getHeight()) / 2f, backgroundPaint); + } canvas.save(); menuPaint.setAlpha(alpha); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index fbd92291fe..b4e426e362 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -100,6 +100,7 @@ import org.telegram.ui.Adapters.SearchAdapterHelper; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HintDialogCell; +import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Cells.ShareTopicCell; import org.telegram.ui.ChatActivity; @@ -148,11 +149,14 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi private SwitchView switchView; private int containerViewTop = -1; private boolean fullyShown = false; + private boolean includeStory; + public boolean includeStoryFromMessage; private ChatActivity parentFragment; private Activity parentActivity; private boolean darkTheme; + public boolean forceDarkThemeForHint; private RectF rect = new RectF(); private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -462,16 +466,17 @@ public ShareAlert(final Context context, ArrayList messages, fina } public ShareAlert(final Context context, ArrayList messages, final String text, boolean channel, final String copyLink, boolean fullScreen, Theme.ResourcesProvider resourcesProvider) { - this(context, null, messages, text, null, channel, copyLink, null, fullScreen, false, resourcesProvider); + this(context, null, messages, text, null, channel, copyLink, null, fullScreen, false, false, resourcesProvider); } public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall) { - this(context, fragment, messages, text, text2, channel, copyLink, copyLink2, fullScreen, forCall, null); + this(context, fragment, messages, text, text2, channel, copyLink, copyLink2, fullScreen, forCall, false, null); } - public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall, Theme.ResourcesProvider resourcesProvider) { + public ShareAlert(final Context context, ChatActivity fragment, ArrayList messages, final String text, final String text2, boolean channel, final String copyLink, final String copyLink2, boolean fullScreen, boolean forCall, boolean includeStory, Theme.ResourcesProvider resourcesProvider) { super(context, true, resourcesProvider); this.resourcesProvider = resourcesProvider; + this.includeStory = includeStory; if (context instanceof Activity) { parentActivity = (Activity) context; @@ -870,6 +875,7 @@ public void requestLayout() { } private boolean lightStatusBar = AndroidUtilities.computePerceivedBrightness(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)) > .721f; + private final AnimatedFloat pinnedToTop = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @Override protected void onDraw(Canvas canvas) { @@ -880,37 +886,44 @@ protected void onDraw(Canvas canvas) { int height = getMeasuredHeight() + AndroidUtilities.dp(30 + 30) + backgroundPaddingTop; int statusBarHeight = 0; float radProgress = 1.0f; + float pinAlpha = 0; if (!isFullscreen && Build.VERSION.SDK_INT >= 21) { - top += AndroidUtilities.statusBarHeight; y += AndroidUtilities.statusBarHeight; - height -= AndroidUtilities.statusBarHeight; - - if (fullHeight) { - if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight * 2) { - int diff = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight * 2 - top - backgroundPaddingTop); - top -= diff; - height += diff; - radProgress = 1.0f - Math.min(1.0f, (diff * 2) / (float) AndroidUtilities.statusBarHeight); - } - if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight) { - statusBarHeight = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight - top - backgroundPaddingTop); - } - } + final boolean pinnedToTop = fullHeight && top + backgroundPaddingTop < AndroidUtilities.statusBarHeight; + top = AndroidUtilities.lerp(top + AndroidUtilities.statusBarHeight, -backgroundPaddingTop, pinAlpha = this.pinnedToTop.set(pinnedToTop)); +// top += AndroidUtilities.statusBarHeight; +// height -= AndroidUtilities.statusBarHeight; +// +// if (fullHeight) { +// if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight * 2) { +// int diff = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight * 2 - top - backgroundPaddingTop); +// top -= diff; +// height += diff; +// radProgress = 1.0f - Math.min(1.0f, (diff * 2) / (float) AndroidUtilities.statusBarHeight); +// } +// if (top + backgroundPaddingTop < AndroidUtilities.statusBarHeight) { +// statusBarHeight = Math.min(AndroidUtilities.statusBarHeight, AndroidUtilities.statusBarHeight - top - backgroundPaddingTop); +// } +// } } shadowDrawable.setBounds(0, top, getMeasuredWidth(), height); shadowDrawable.draw(canvas); - if (radProgress != 1.0f) { - Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)); - rect1.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); - canvas.drawRoundRect(rect1, AndroidUtilities.dp(12) * radProgress, AndroidUtilities.dp(12) * radProgress, Theme.dialogs_onlineCirclePaint); - } +// if (radProgress != 1.0f) { +// Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_inviteMembersBackground : Theme.key_dialogBackground)); +// Theme.dialogs_onlineCirclePaint.setAlpha((int) (Theme.dialogs_onlineCirclePaint.getAlpha() * pinAlpha)); +// rect1.set(backgroundPaddingLeft, backgroundPaddingTop + top, getMeasuredWidth() - backgroundPaddingLeft, backgroundPaddingTop + top + AndroidUtilities.dp(24)); +// canvas.drawRoundRect(rect1, AndroidUtilities.dp(12) * radProgress, AndroidUtilities.dp(12) * radProgress, Theme.dialogs_onlineCirclePaint); +// } - int w = AndroidUtilities.dp(36); - rect1.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); - Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_scrollUp : Theme.key_sheet_scrollUp)); - canvas.drawRoundRect(rect1, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); + if (pinAlpha < 1) { + int w = AndroidUtilities.dp(36); + rect1.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); + Theme.dialogs_onlineCirclePaint.setColor(getThemedColor(darkTheme ? Theme.key_voipgroup_scrollUp : Theme.key_sheet_scrollUp)); + Theme.dialogs_onlineCirclePaint.setAlpha((int) (Theme.dialogs_onlineCirclePaint.getAlpha() * (1f - pinAlpha))); + canvas.drawRoundRect(rect1, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int flags = getSystemUiVisibility(); @@ -1126,7 +1139,7 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -1176,7 +1189,7 @@ public int getSpanSize(int position) { if (dialog == null) { return; } - selectDialog((ShareDialogCell) view, dialog); + selectDialog(view, dialog); }); searchGridView.setHasFixedSize(true); searchGridView.setItemAnimator(null); @@ -1194,11 +1207,15 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { searchGridView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - RecyclerListView.Holder holder = (RecyclerListView.Holder) parent.getChildViewHolder(view); + final RecyclerListView.Holder holder = (RecyclerListView.Holder) parent.getChildViewHolder(view); if (holder != null) { - int pos = holder.getAdapterPosition(); - outRect.left = pos % 4 == 0 ? 0 : AndroidUtilities.dp(4); - outRect.right = pos % 4 == 3 ? 0 : AndroidUtilities.dp(4); + if (holder.getItemViewType() != 5) { + outRect.left = outRect.right = 0; + } else { + final int pos = holder.getAdapterPosition(); + outRect.left = pos % 4 == 0 ? 0 : AndroidUtilities.dp(4); + outRect.right = pos % 4 == 3 ? 0 : AndroidUtilities.dp(4); + } } else { outRect.left = AndroidUtilities.dp(4); outRect.right = AndroidUtilities.dp(4); @@ -1501,7 +1518,7 @@ protected void onDraw(Canvas canvas) { rect.set(cx - size / 2, 0, cx + size / 2, getMeasuredHeight()); canvas.drawRoundRect(rect, AndroidUtilities.dp(12), AndroidUtilities.dp(12), paint); - paint.setColor(getThemedColor(Theme.key_dialogRoundCheckBox)); + paint.setColor(getThemedColor(Theme.key_dialogFloatingButton)); rect.set(cx - size / 2 + AndroidUtilities.dp(2), AndroidUtilities.dp(2), cx + size / 2 - AndroidUtilities.dp(2), getMeasuredHeight() - AndroidUtilities.dp(2)); canvas.drawRoundRect(rect, AndroidUtilities.dp(10), AndroidUtilities.dp(10), paint); @@ -1523,6 +1540,15 @@ protected void onDraw(Canvas canvas) { DialogsSearchAdapter.loadRecentSearch(currentAccount, 0, new DialogsSearchAdapter.OnRecentSearchLoaded() { @Override public void setRecentSearch(ArrayList arrayList, LongSparseArray hashMap) { + if (arrayList != null) { + for (int i = 0; i < arrayList.size(); ++i) { + DialogsSearchAdapter.RecentSearchObject recentSearchObject = arrayList.get(i); + if (recentSearchObject.object instanceof TLRPC.Chat && !ChatObject.canWriteToChat((TLRPC.Chat) recentSearchObject.object)) { + arrayList.remove(i); + i--; + } + } + } recentSearchObjects = arrayList; recentSearchObjectsById = hashMap; for (int a = 0; a < recentSearchObjects.size(); a++) { @@ -1544,7 +1570,15 @@ public void setRecentSearch(ArrayList a AndroidUtilities.updateViewVisibilityAnimated(searchGridView, false, 1f, false); } - private void selectDialog(ShareDialogCell cell, TLRPC.Dialog dialog) { + protected void onShareStory(View cell) { + + } + + private void selectDialog(View cell, TLRPC.Dialog dialog) { + if (dialog instanceof ShareDialogsAdapter.MyStoryDialog) { + onShareStory(cell); + return; + } if (topicsGridView.getVisibility() != View.GONE || parentActivity == null) { return; } @@ -1584,8 +1618,10 @@ private void selectDialog(ShareDialogCell cell, TLRPC.Dialog dialog) { if (selectedDialogs.indexOfKey(dialog.id) >= 0) { selectedDialogs.remove(dialog.id); selectedDialogTopics.remove(dialog); - if (cell != null) { - cell.setChecked(false, true); + if (cell instanceof ProfileSearchCell) { + ((ProfileSearchCell) cell).setChecked(false, true); + } else if (cell instanceof ShareDialogCell) { + ((ShareDialogCell) cell).setChecked(false, true); } updateSelectedCount(1); } else { @@ -1665,8 +1701,10 @@ public void didReceivedNotification(int id, int account, Object... args) { } selectedDialogs.put(dialog.id, dialog); - if (cell != null) { - cell.setChecked(true, true); + if (cell instanceof ProfileSearchCell) { + ((ProfileSearchCell) cell).setChecked(true, true); + } else if (cell instanceof ShareDialogCell) { + ((ShareDialogCell) cell).setChecked(true, true); } updateSelectedCount(2); long selfUserId = UserConfig.getInstance(currentAccount).clientUserId; @@ -2351,6 +2389,10 @@ public void dismiss() { private class ShareDialogsAdapter extends RecyclerListView.SelectionAdapter { + private class MyStoryDialog extends TLRPC.Dialog { + { id = Long.MAX_VALUE; } + } + private Context context; private int currentCount; private ArrayList dialogs = new ArrayList<>(); @@ -2365,6 +2407,11 @@ public void fetchDialogs() { dialogs.clear(); dialogsMap.clear(); long selfUserId = UserConfig.getInstance(currentAccount).clientUserId; + if (includeStory) { + MyStoryDialog d = new MyStoryDialog(); + dialogs.add(d); + dialogsMap.put(d.id, d); + } if (!MessagesController.getInstance(currentAccount).dialogsForward.isEmpty()) { TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogsForward.get(0); dialogs.add(dialog); @@ -2449,7 +2496,15 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType 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; } @@ -2468,6 +2523,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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); } @@ -2579,7 +2635,12 @@ public class ShareSearchAdapter extends RecyclerListView.SelectionAdapter { public ShareSearchAdapter(Context context) { this.context = context; - searchAdapterHelper = new SearchAdapterHelper(false); + searchAdapterHelper = new SearchAdapterHelper(false) { + @Override + protected boolean filter(TLObject obj) { + return !(obj instanceof TLRPC.Chat) || ChatObject.canWriteToChat((TLRPC.Chat) obj); + } + }; searchAdapterHelper.setDelegate(new SearchAdapterHelper.SearchAdapterHelperDelegate() { @Override public void onDataSetChanged(int searchId) { @@ -2969,11 +3030,15 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: { + case 5: { view = new ShareDialogCell(context, darkTheme ? ShareDialogCell.TYPE_CALL : ShareDialogCell.TYPE_SHARE, resourcesProvider); view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); break; } + case 0: { + view = new ProfileSearchCell(context, resourcesProvider).useCustomPaints(); + break; + } default: case 1: { view = new View(context); @@ -3001,11 +3066,11 @@ public boolean supportsPredictiveItemAnimations() { }; layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); horizontalListView.setLayoutManager(layoutManager); - horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true) { + horizontalListView.setAdapter(categoryAdapter = new DialogsSearchAdapter.CategoryAdapterRecycler(context, currentAccount, true, resourcesProvider) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { HintDialogCell cell = (HintDialogCell) holder.itemView; - if (darkTheme) { + if (darkTheme || forceDarkThemeForHint) { cell.setColors(Theme.key_voipgroup_nameText, Theme.key_voipgroup_inviteMembersBackground); } @@ -3079,16 +3144,19 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { - ShareDialogCell cell = (ShareDialogCell) holder.itemView; + if (holder.getItemViewType() == 0 || holder.getItemViewType() == 5) { +// ShareDialogCell cell = (ShareDialogCell) holder.itemView; +// ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; CharSequence name = null; + TLObject object = null; + TLRPC.EncryptedChat ec = null; long id = 0; if (TextUtils.isEmpty(lastSearchText)) { if (recentDialogsStartRow >= 0 && position >= recentDialogsStartRow) { int p = position - recentDialogsStartRow; DialogsSearchAdapter.RecentSearchObject recentSearchObject = recentSearchObjects.get(p); - TLObject object = recentSearchObject.object; + object = recentSearchObject.object; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; id = user.id; @@ -3099,6 +3167,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { name = chat.title; } else if (object instanceof TLRPC.TL_encryptedChat) { TLRPC.TL_encryptedChat chat = (TLRPC.TL_encryptedChat) object; + ec = chat; TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(chat.user_id); if (user != null) { id = user.id; @@ -3114,9 +3183,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { name = spannableStringBuilder; } } - } - cell.setDialog((int) id, selectedDialogs.indexOfKey(id) >= 0, name); + if (holder.itemView instanceof ProfileSearchCell) { + ((ProfileSearchCell) holder.itemView).setData(object, ec, name, null, false, false); + ((ProfileSearchCell) holder.itemView).useSeparator = position < getItemCount() - 2; + } else if (holder.itemView instanceof ShareDialogCell) { + ((ShareDialogCell) holder.itemView).setDialog(id, selectedDialogs.indexOfKey(id) >= 0, name); + } return; } position--; @@ -3127,7 +3200,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { position -= searchResult.size(); ArrayList arrayList = searchAdapterHelper.getLocalServerSearch(); - TLObject object = arrayList.get(position); + object = arrayList.get(position); if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; id = user.id; @@ -3147,7 +3220,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } } } - cell.setDialog(id, selectedDialogs.indexOfKey(id) >= 0, name); + if (holder.itemView instanceof ProfileSearchCell) { + ((ProfileSearchCell) holder.itemView).setData(object, ec, name, null, false, false); + ((ProfileSearchCell) holder.itemView).useSeparator = position < getItemCount() - 2; + } else if (holder.itemView instanceof ShareDialogCell) { + ((ShareDialogCell) holder.itemView).setDialog((int) id, selectedDialogs.indexOfKey(id) >= 0, name); + } } else if (holder.getItemViewType() == 2) { ((RecyclerListView) holder.itemView).getAdapter().notifyDataSetChanged(); } @@ -3165,7 +3243,7 @@ public int getItemViewType(int position) { } else if (position == resentTitleCell) { return 3; } - return 0; + return TextUtils.isEmpty(lastSearchText) ? 0 : 5; } public boolean isSearching() { @@ -3176,6 +3254,10 @@ public int getSpanSize(int spanCount, int position) { if (position == hintsCell || position == resentTitleCell || position == firstEmptyViewCell || position == lastFilledItem) { return spanCount; } + final int viewType = getItemViewType(position); + if (viewType == 0) { + return spanCount; + } return 1; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index 93c2722b72..e7893e4537 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -1,5 +1,6 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.MediaDataController.MEDIA_PHOTOVIDEO; import android.animation.Animator; @@ -13,15 +14,18 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.os.Bundle; import android.text.Layout; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; @@ -54,6 +58,7 @@ 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; @@ -78,6 +83,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; @@ -100,6 +106,7 @@ 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; @@ -117,11 +124,14 @@ import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.DialogsActivity; import org.telegram.ui.PhotoViewer; +import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.Stories.StoriesListPlaceProvider; import org.telegram.ui.Stories.UserListPoller; import org.telegram.ui.Stories.ViewsForPeerStoriesRequester; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import org.telegram.ui.TopicsFragment; import java.util.ArrayList; import java.util.Collections; @@ -147,6 +157,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public static final int TAB_GROUPUSERS = 7; public static final int TAB_STORIES = 8; public static final int TAB_ARCHIVED_STORIES = 9; + public static final int TAB_RECOMMENDED_CHANNELS = 10; public static final int FILTER_PHOTOS_AND_VIDEOS = 0; public static final int FILTER_PHOTOS_ONLY = 1; @@ -371,7 +382,7 @@ public void drawListForBlur(Canvas blurCanvas) { if (mediaPages[i] != null && mediaPages[i].getVisibility() == View.VISIBLE) { for (int j = 0; j < mediaPages[i].listView.getChildCount(); j++) { View child = mediaPages[i].listView.getChildAt(j); - if (child.getY() < mediaPages[i].listView.blurTopPadding + AndroidUtilities.dp(100)) { + if (child.getY() < mediaPages[i].listView.blurTopPadding + dp(100)) { int restore = blurCanvas.save(); blurCanvas.translate(mediaPages[i].getX() + child.getX(), getY() + mediaPages[i].getY() + mediaPages[i].listView.getY() + child.getY()); child.draw(blurCanvas); @@ -424,11 +435,11 @@ protected void dispatchDraw(Canvas canvas) { boolean isVisible = false; RecyclerListView.FastScroll fastScroll = listView.getFastScroll(); if (fastScroll != null) { - float y = fastScroll.getScrollBarY() + AndroidUtilities.dp(36); + float y = fastScroll.getScrollBarY() + dp(36); if (selectedType == TAB_ARCHIVED_STORIES) { - y += AndroidUtilities.dp(64); + y += dp(64); } - float x = (getMeasuredWidth() - fastScrollHintView.getMeasuredWidth() - AndroidUtilities.dp(16)); + float x = (getMeasuredWidth() - fastScrollHintView.getMeasuredWidth() - dp(16)); fastScrollHintView.setPivotX(fastScrollHintView.getMeasuredWidth()); fastScrollHintView.setPivotY(0); fastScrollHintView.setTranslationX(x); @@ -501,6 +512,7 @@ public void updateFastScrollVisibility(MediaPage mediaPage, boolean animated) { private SharedDocumentsAdapter audioAdapter; private GifAdapter gifAdapter; private CommonGroupsAdapter commonGroupsAdapter; + private ChannelRecommendationsAdapter channelRecommendationsAdapter; private ChatUsersAdapter chatUsersAdapter; private StoriesAdapter storiesAdapter; private StoriesAdapter animationSupportingStoriesAdapter; @@ -528,7 +540,7 @@ public void updateFastScrollVisibility(MediaPage mediaPage, boolean animated) { private ArrayList cache = new ArrayList<>(10); private ArrayList audioCellCache = new ArrayList<>(10); private ArrayList audioCache = new ArrayList<>(10); - private ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip; + public ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip; private View shadowLine; private ChatActionCell floatingDateView; private AnimatorSet floatingDateAnimation; @@ -1027,7 +1039,7 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj object.clipTopAddition = 0; object.starOffset = sharedMediaData[0].startOffset; if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { - object.clipTopAddition += AndroidUtilities.dp(36); + object.clipTopAddition += dp(36); } if (PhotoViewer.isShowingImage(messageObject)) { @@ -1035,10 +1047,10 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj if (pinnedHeader != null) { int top = 0; if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { - top += fragmentContextView.getHeight() - AndroidUtilities.dp(2.5f); + top += fragmentContextView.getHeight() - dp(2.5f); } if (view instanceof SharedDocumentCell) { - top += AndroidUtilities.dp(8f); + top += dp(8f); } final int topOffset = top - object.viewY; if (topOffset > view.getHeight()) { @@ -1046,7 +1058,7 @@ public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObj } else { int bottomOffset = object.viewY - listView.getHeight(); if (view instanceof SharedDocumentCell) { - bottomOffset -= AndroidUtilities.dp(8f); + bottomOffset -= dp(8f); } if (bottomOffset >= 0) { listView.scrollBy(0, bottomOffset + view.getHeight()); @@ -1258,7 +1270,7 @@ public boolean hasInternet() { return profileActivity.getConnectionsManager().getConnectionState() == ConnectionsManager.ConnectionStateConnected; } - public SharedMediaLayout(Context context, long did, SharedMediaPreloader preloader, int commonGroupsCount, ArrayList sortedUsers, TLRPC.ChatFull chatInfo, TLRPC.UserFull userInfo, boolean membersFirst, BaseFragment parent, Delegate delegate, int viewType, Theme.ResourcesProvider resourcesProvider) { + public SharedMediaLayout(Context context, long did, SharedMediaPreloader preloader, int commonGroupsCount, ArrayList sortedUsers, TLRPC.ChatFull chatInfo, TLRPC.UserFull userInfo, int initialTab, BaseFragment parent, Delegate delegate, int viewType, Theme.ResourcesProvider resourcesProvider) { super(context); this.viewType = viewType; this.resourcesProvider = resourcesProvider; @@ -1271,14 +1283,16 @@ public SharedMediaLayout(Context context, long did, SharedMediaPreloader preload int[] mediaCount = preloader.getLastMediaCount(); topicId = sharedMediaPreloader.topicId; hasMedia = new int[]{mediaCount[0], mediaCount[1], mediaCount[2], mediaCount[3], mediaCount[4], mediaCount[5], topicId == 0 ? commonGroupsCount : 0}; - if (userInfo != null && userInfo.stories_pinned_available || chatInfo != null && chatInfo.stories_pinned_available || isStoriesView()) { - initialTab = getInitialTab(); - } else if (membersFirst && topicId == 0) { - initialTab = TAB_GROUPUSERS; + if (initialTab == TAB_RECOMMENDED_CHANNELS) { + this.initialTab = initialTab; + } else if (userInfo != null && userInfo.stories_pinned_available || chatInfo != null && chatInfo.stories_pinned_available || isStoriesView()) { + this.initialTab = getInitialTab(); + } else if (initialTab != -1 && topicId == 0) { + this.initialTab = initialTab; } else { for (int a = 0; a < hasMedia.length; a++) { if (hasMedia[a] == -1 || hasMedia[a] > 0) { - initialTab = a; + this.initialTab = a; break; } } @@ -1314,6 +1328,7 @@ public SharedMediaLayout(Context context, long did, SharedMediaPreloader preload profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.messagePlayingDidStart); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.storiesUpdated); + profileActivity.getNotificationCenter().addObserver(this, NotificationCenter.channelRecommendationsLoaded); for (int a = 0; a < 10; a++) { //cellCache.add(new SharedPhotoVideoCell(context)); @@ -1428,14 +1443,14 @@ public void onLayout(int l, int t, int r, int b) { searchItem.setTranslationX(parent.getMeasuredWidth() - searchItem.getRight()); } }); - searchItem.setTranslationY(AndroidUtilities.dp(10)); + searchItem.setTranslationY(dp(10)); searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); searchItem.setVisibility(isStoriesView() ? View.GONE : View.INVISIBLE); photoVideoOptionsItem = new ImageView(context); photoVideoOptionsItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - photoVideoOptionsItem.setTranslationY(AndroidUtilities.dp(10)); + photoVideoOptionsItem.setTranslationY(dp(10)); photoVideoOptionsItem.setVisibility(View.INVISIBLE); Drawable calendarDrawable = ContextCompat.getDrawable(context, R.drawable.ic_ab_other).mutate(); @@ -1455,7 +1470,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (dividerView.getParent() != null) { dividerView.setVisibility(View.GONE); super.onMeasure(widthMeasureSpec, heightMeasureSpec); - dividerView.getLayoutParams().width = getMeasuredWidth() - AndroidUtilities.dp(16); + dividerView.getLayoutParams().width = getMeasuredWidth() - dp(16); dividerView.setVisibility(View.VISIBLE); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } else { @@ -1618,7 +1633,7 @@ public void onClick(View view) { } } - optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -AndroidUtilities.dp(56)); + optionsWindow = AlertsCreator.showPopupMenu(popupLayout, photoVideoOptionsItem, 0, -dp(56)); } }); @@ -1644,7 +1659,7 @@ public void onClick(View view) { backDrawable.setColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon)); closeButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarActionModeDefaultSelector), 1)); closeButton.setContentDescription(LocaleController.getString("Close", R.string.Close)); - actionModeLayout.addView(closeButton, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(closeButton, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(closeButton); closeButton.setOnClickListener(v -> closeActionMode()); @@ -1655,14 +1670,6 @@ public void onClick(View view) { actionModeLayout.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 18, 0, 0, 0)); actionModeViews.add(selectedMessagesCountTextView); - gotoItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); - gotoItem.setIcon(R.drawable.msg_message); - gotoItem.setContentDescription(LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); - gotoItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); - actionModeViews.add(gotoItem); - gotoItem.setOnClickListener(v -> onActionBarItemClick(v, gotochat)); - if (!DialogObject.isEncryptedDialog(dialog_id)) { forwardNoQuoteItem = new ActionBarMenuItem(context, null, Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), false); forwardNoQuoteItem.setIcon(R.drawable.msg_forward_noquote); @@ -1672,11 +1679,19 @@ public void onClick(View view) { actionModeViews.add(forwardNoQuoteItem); forwardNoQuoteItem.setOnClickListener(v -> onActionBarItemClick(v, forward_noquote)); + gotoItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); + gotoItem.setIcon(R.drawable.msg_message); + gotoItem.setContentDescription(LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); + gotoItem.setDuplicateParentStateEnabled(false); + actionModeLayout.addView(gotoItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeViews.add(gotoItem); + gotoItem.setOnClickListener(v -> onActionBarItemClick(v, gotochat)); + forwardItem = new ActionBarMenuItem(context, null, getThemedColor(Theme.key_actionBarActionModeDefaultSelector), getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); forwardItem.setIcon(R.drawable.msg_forward); forwardItem.setContentDescription(LocaleController.getString("Forward", R.string.Forward)); forwardItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(forwardItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(forwardItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(forwardItem); forwardItem.setOnClickListener(v -> onActionBarItemClick(v, forward)); @@ -1686,7 +1701,7 @@ public void onClick(View view) { deleteItem.setIcon(R.drawable.msg_delete); deleteItem.setContentDescription(LocaleController.getString("Delete", R.string.Delete)); deleteItem.setDuplicateParentStateEnabled(false); - actionModeLayout.addView(deleteItem, new LinearLayout.LayoutParams(AndroidUtilities.dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); + actionModeLayout.addView(deleteItem, new LinearLayout.LayoutParams(dp(54), ViewGroup.LayoutParams.MATCH_PARENT)); actionModeViews.add(deleteItem); deleteItem.setOnClickListener(v -> onActionBarItemClick(v, delete)); @@ -1710,10 +1725,11 @@ public void notifyDataSetChanged() { linksSearchAdapter = new MediaSearchAdapter(context, 3); groupUsersSearchAdapter = new GroupUsersSearchAdapter(context); commonGroupsAdapter = new CommonGroupsAdapter(context); + channelRecommendationsAdapter = new ChannelRecommendationsAdapter(context); chatUsersAdapter = new ChatUsersAdapter(context); if (topicId == 0) { chatUsersAdapter.sortedUsers = sortedUsers; - chatUsersAdapter.chatInfo = membersFirst ? chatInfo : null; + chatUsersAdapter.chatInfo = initialTab == TAB_GROUPUSERS ? chatInfo : null; } storiesAdapter = new StoriesAdapter(context, false) { @Override @@ -1814,7 +1830,7 @@ protected void calculateExtraLayoutSpace(RecyclerView.State state, int[] extraLa if (mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_STORIES || mediaPage.selectedType == TAB_ARCHIVED_STORIES) { extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], SharedPhotoVideoCell.getItemSize(1) * 2); } else if (mediaPage.selectedType == TAB_FILES) { - extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], AndroidUtilities.dp(56f) * 2); + extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], dp(56f) * 2); } } @@ -1915,6 +1931,25 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { UserListPoller poller; + float lastY, startY; + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (profileActivity != null && profileActivity.isInPreviewMode()) { + lastY = event.getY(); + if (event.getAction() == MotionEvent.ACTION_UP) { + profileActivity.finishPreviewFragment(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + float dy = startY - lastY; + profileActivity.movePreviewFragment(dy); + if (dy < 0) { + startY = lastY; + } + } + return true; + } + return super.dispatchTouchEvent(event); + } + @Override protected void dispatchDraw(Canvas canvas) { if (getAdapter() == archivedStoriesAdapter && getChildCount() > 0) { @@ -1929,10 +1964,10 @@ protected void dispatchDraw(Canvas canvas) { } if (archivedHintPaint == null) { archivedHintPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - archivedHintPaint.setTextSize(AndroidUtilities.dp(14)); + archivedHintPaint.setTextSize(dp(14)); archivedHintPaint.setColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2)); } - int width = getMeasuredWidth() - AndroidUtilities.dp(60); + int width = getMeasuredWidth() - dp(60); if (archivedHintLayout == null || archivedHintLayout.getWidth() != width) { archivedHintLayout = new StaticLayout(LocaleController.getString(isArchivedOnlyStoriesView() ? R.string.ProfileStoriesArchiveChannelHint : R.string.ProfileStoriesArchiveHint), archivedHintPaint, width, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false); archivedHintLayoutWidth = 0; @@ -1946,7 +1981,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.save(); canvas.translate( (getWidth() - archivedHintLayoutWidth) / 2f - archivedHintLayoutLeft, - top - (AndroidUtilities.dp(64) + archivedHintLayout.getHeight()) / 2f + top - (dp(64) + archivedHintLayout.getHeight()) / 2f ); archivedHintLayout.draw(canvas); canvas.restore(); @@ -2270,12 +2305,19 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { 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); mediaPages[a].listView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING); - mediaPages[a].listView.setPinnedSectionOffsetY(-AndroidUtilities.dp(2)); - mediaPages[a].listView.setPadding(0, AndroidUtilities.dp(2), 0, 0); + mediaPages[a].listView.setPinnedSectionOffsetY(-dp(2)); + mediaPages[a].listView.setPadding(0, dp(2), 0, 0); mediaPages[a].listView.setItemAnimator(null); mediaPages[a].listView.setClipToPadding(false); mediaPages[a].listView.setSectionsType(RecyclerListView.SECTIONS_TYPE_DATE); @@ -2329,11 +2371,11 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie outRect.left = 0; outRect.bottom = 0; if (!mediaPage.layoutManager.isFirstRow(position)) { - outRect.top = AndroidUtilities.dp(2); + outRect.top = dp(2); } else { outRect.top = 0; } - outRect.right = mediaPage.layoutManager.isLastInRow(position) ? 0 : AndroidUtilities.dp(2); + outRect.right = mediaPage.layoutManager.isLastInRow(position) ? 0 : dp(2); } else if (view instanceof SharedPhotoVideoCell2) { SharedPhotoVideoCell2 cell = (SharedPhotoVideoCell2) view; final int position = mediaPage.listView.getChildAdapterPosition(cell), spanCount = mediaPage.layoutManager.getSpanCount(); @@ -2393,7 +2435,11 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (!profileActivity.getMessagesController().checkCanOpenChat(args, profileActivity)) { return; } - profileActivity.presentFragment(new ChatActivity(args)); + if (chat.forum) { + profileActivity.presentFragment(TopicsFragment.getTopicsOrChat(profileActivity, args)); + } else { + profileActivity.presentFragment(new ChatActivity(args)); + } } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { onItemClick(position, view, ((SharedDocumentCell) view).getMessage(), 0, mediaPage.selectedType); } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { @@ -2418,6 +2464,12 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (messageObject != null) { onItemClick(position, view, messageObject, 0, mediaPage.selectedType); } + } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { + if ((view instanceof ProfileSearchCell || 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)); + } } }); mediaPages[a].listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -2442,51 +2494,71 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { invalidateBlur(); } }); - mediaPages[a].listView.setOnItemLongClickListener((view, position) -> { - if (photoVideoChangeColumnsAnimation) { - return false; - } - if (isActionModeShowed) { - mediaPage.listView.clickItem(view, position); - return true; - } - if (mediaPage.selectedType == TAB_GROUPUSERS && view instanceof UserCell) { - final TLRPC.ChatParticipant participant; - int index = position; - if (!chatUsersAdapter.sortedUsers.isEmpty()) { - if (position >= chatUsersAdapter.sortedUsers.size()) { - return false; - } - index = chatUsersAdapter.sortedUsers.get(position); - } - if (index < 0 || index >= chatUsersAdapter.chatInfo.participants.participants.size()) { + mediaPages[a].listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListenerExtended() { + @Override + public boolean onItemClick(View view, int position, float x, float y) { + if (photoVideoChangeColumnsAnimation) { return false; } - participant = chatUsersAdapter.chatInfo.participants.participants.get(index); - RecyclerListView listView = (RecyclerListView) view.getParent(); - for (int i = 0; i < listView.getChildCount(); ++i) { - View child = listView.getChildAt(i); - if (listView.getChildAdapterPosition(child) == position) { - view = child; - break; + if (isActionModeShowed) { + mediaPage.listView.clickItem(view, position); + return true; + } + if (mediaPage.selectedType == TAB_GROUPUSERS && view instanceof UserCell) { + final TLRPC.ChatParticipant participant; + int index = position; + if (!chatUsersAdapter.sortedUsers.isEmpty()) { + if (position >= chatUsersAdapter.sortedUsers.size()) { + return false; + } + index = chatUsersAdapter.sortedUsers.get(position); + } + if (index < 0 || index >= chatUsersAdapter.chatInfo.participants.participants.size()) { + return false; + } + participant = chatUsersAdapter.chatInfo.participants.participants.get(index); + RecyclerListView listView = (RecyclerListView) view.getParent(); + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == position) { + view = child; + break; + } } + return onMemberClick(participant, true, view); + } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { + return onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); + } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { + return onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); + } else if ((mediaPage.selectedType == TAB_VOICE || mediaPage.selectedType == TAB_AUDIO) && view instanceof SharedAudioCell) { + return onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); + } else if (mediaPage.selectedType == TAB_GIF && view instanceof ContextLinkCell) { + return onItemLongClick((MessageObject) ((ContextLinkCell) view).getParentObject(), view, 0); + } else if ((mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_ARCHIVED_STORIES || mediaPage.selectedType == TAB_STORIES && isStoriesView()) && view instanceof SharedPhotoVideoCell2) { + MessageObject messageObject = ((SharedPhotoVideoCell2) view).getMessageObject(); + if (messageObject != null) { + return onItemLongClick(messageObject, view, mediaPage.selectedType); + } + } else if (mediaPage.selectedType == TAB_RECOMMENDED_CHANNELS) { + channelRecommendationsAdapter.openPreview(position); + return true; } - return onMemberClick(participant, true, view); - } else if (mediaPage.selectedType == TAB_FILES && view instanceof SharedDocumentCell) { - return onItemLongClick(((SharedDocumentCell) view).getMessage(), view, 0); - } else if (mediaPage.selectedType == TAB_LINKS && view instanceof SharedLinkCell) { - return onItemLongClick(((SharedLinkCell) view).getMessage(), view, 0); - } else if ((mediaPage.selectedType == TAB_VOICE || mediaPage.selectedType == TAB_AUDIO) && view instanceof SharedAudioCell) { - return onItemLongClick(((SharedAudioCell) view).getMessage(), view, 0); - } else if (mediaPage.selectedType == TAB_GIF && view instanceof ContextLinkCell) { - return onItemLongClick((MessageObject) ((ContextLinkCell) view).getParentObject(), view, 0); - } else if ((mediaPage.selectedType == TAB_PHOTOVIDEO || mediaPage.selectedType == TAB_ARCHIVED_STORIES || mediaPage.selectedType == TAB_STORIES && isStoriesView()) && view instanceof SharedPhotoVideoCell2) { - MessageObject messageObject = ((SharedPhotoVideoCell2) view).getMessageObject(); - if (messageObject != null) { - return onItemLongClick(messageObject, view, mediaPage.selectedType); + return false; + } + + @Override + public void onMove(float dx, float dy) { + if (profileActivity != null && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + profileActivity.movePreviewFragment(dy); + } + } + + @Override + public void onLongClickRelease() { + if (profileActivity != null && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + profileActivity.finishPreviewFragment(); } } - return false; }); if (a == 0 && scrollToPositionOnRecreate != -1) { layoutManager.scrollToPositionWithOffset(scrollToPositionOnRecreate, scrollToOffsetOnRecreate); @@ -2567,7 +2639,7 @@ protected void onDraw(Canvas canvas) { floatingDateView.setCustomDate((int) (System.currentTimeMillis() / 1000), false, false); floatingDateView.setAlpha(0.0f); floatingDateView.setOverrideColor(Theme.key_chat_mediaTimeBackground, Theme.key_chat_mediaTimeText); - floatingDateView.setTranslationY(-AndroidUtilities.dp(48)); + floatingDateView.setTranslationY(-dp(48)); addView(floatingDateView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 48 + 4, 0, 0)); if (!isStoriesView()) { @@ -2585,7 +2657,7 @@ protected void onDraw(Canvas canvas) { shadowLine = new View(context); shadowLine.setBackgroundColor(getThemedColor(Theme.key_divider)); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1); - layoutParams.topMargin = isStoriesView() ? 0 : AndroidUtilities.dp(48) - 1; + layoutParams.topMargin = isStoriesView() ? 0 : dp(48) - 1; addView(shadowLine, layoutParams); updateTabs(false); @@ -2851,7 +2923,7 @@ private void startPinchToMediaColumnsCount(boolean pinchScaleUp) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - changeColumnsTab == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(2 + 64) : AndroidUtilities.dp(2), + changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(2 + 64) : dp(2), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); @@ -3052,7 +3124,7 @@ private void animateToMediaColumnsCount(int newColumnsCount) { } mediaPage.animationSupportingListView.setPadding( mediaPage.animationSupportingListView.getPaddingLeft(), - AndroidUtilities.dp(2) + (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(64) : 0)), + dp(2) + (mediaPage.animationSupportingListView.hintPaddingTop = (changeColumnsTab == TAB_ARCHIVED_STORIES ? dp(64) : 0)), mediaPage.animationSupportingListView.getPaddingRight(), mediaPage.animationSupportingListView.getPaddingBottom() ); @@ -3136,8 +3208,17 @@ protected void dispatchDraw(Canvas canvas) { } } + protected int processColor(int color) { + return color; + } + private ScrollSlidingTextTabStripInner createScrollingTextTabStrip(Context context) { - ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip = new ScrollSlidingTextTabStripInner(context, resourcesProvider); + ScrollSlidingTextTabStripInner scrollSlidingTextTabStrip = new ScrollSlidingTextTabStripInner(context, resourcesProvider) { + @Override + protected int processColor(int color) { + return SharedMediaLayout.this.processColor(color); + } + }; if (initialTab != -1) { scrollSlidingTextTabStrip.setInitialTabId(initialTab); initialTab = -1; @@ -3256,7 +3337,7 @@ private void hideFloatingDateView(boolean animated) { floatingDateAnimation.setDuration(180); floatingDateAnimation.playTogether( ObjectAnimator.ofFloat(floatingDateView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(floatingDateView, View.TRANSLATION_Y, -AndroidUtilities.dp(48) + additionalFloatingTranslation)); + ObjectAnimator.ofFloat(floatingDateView, View.TRANSLATION_Y, -dp(48) + additionalFloatingTranslation)); floatingDateAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); floatingDateAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -3279,17 +3360,17 @@ private void scrollToTop() { case 1: case 2: case 4: - height = AndroidUtilities.dp(56); + height = dp(56); break; case 3: - height = AndroidUtilities.dp(100); + height = dp(100); break; case 5: - height = AndroidUtilities.dp(60); + height = dp(60); break; case 6: default: - height = AndroidUtilities.dp(58); + height = dp(58); break; } int scrollDistance; @@ -3348,7 +3429,7 @@ private void checkLoadMoreScroll(MediaPage mediaPage, RecyclerListView recyclerV } } - 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]) { @@ -3358,13 +3439,13 @@ private void checkLoadMoreScroll(MediaPage mediaPage, RecyclerListView recyclerV if (archivedStoriesAdapter.storiesList != null && firstVisibleItem + visibleItemCount > archivedStoriesAdapter.storiesList.getLoadedCount() - mediaColumnsCount[1]) { archivedStoriesAdapter.load(false); } - } else if (mediaPage.selectedType == 6) { + } else if (mediaPage.selectedType == TAB_COMMON_GROUPS) { if (visibleItemCount > 0) { if (!commonGroupsAdapter.endReached && !commonGroupsAdapter.loading && !commonGroupsAdapter.chats.isEmpty() && firstVisibleItem + visibleItemCount >= totalItemCount - 5) { commonGroupsAdapter.getChats(commonGroupsAdapter.chats.get(commonGroupsAdapter.chats.size() - 1).id, 100); } } - } else { + } else if (mediaPage.selectedType != TAB_RECOMMENDED_CHANNELS) { final int threshold; if (mediaPage.selectedType == 0) { threshold = 3; @@ -3466,7 +3547,8 @@ public boolean isSearchItemVisible() { 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 ); } @@ -3525,6 +3607,7 @@ public void onDestroy() { profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.messagePlayingDidStart); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesListUpdated); profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.storiesUpdated); + profileActivity.getNotificationCenter().removeObserver(this, NotificationCenter.channelRecommendationsLoaded); if (storiesAdapter != null && storiesAdapter.storiesList != null) { storiesAdapter.destroy(); @@ -3878,10 +3961,10 @@ public void setPadding(int left, int top, int right, int bottom) { mediaPages[a].setTranslationY(topPadding - lastMeasuredTopPadding); } if (fragmentContextView != null) { - fragmentContextView.setTranslationY(AndroidUtilities.dp(48) + top); + fragmentContextView.setTranslationY(dp(48) + top); } additionalFloatingTranslation = top; - floatingDateView.setTranslationY((floatingDateView.getTag() == null ? -AndroidUtilities.dp(48) : 0) + additionalFloatingTranslation); + floatingDateView.setTranslationY((floatingDateView.getTag() == null ? -dp(48) : 0) + additionalFloatingTranslation); } @Override @@ -3967,7 +4050,7 @@ public boolean onTouchEvent(MotionEvent ev) { fwdRestrictedHint.hide(); } } - if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking && ev.getY() >= AndroidUtilities.dp(48)) { + if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking && ev.getY() >= dp(48)) { startedTrackingPointerId = ev.getPointerId(0); maybeStartTracking = true; startedTrackingX = (int) ev.getX(); @@ -4186,7 +4269,7 @@ public boolean closeActionMode(boolean uncheckAnimated) { } public void setVisibleHeight(int height) { - height = Math.max(height, AndroidUtilities.dp(120)); + height = Math.max(height, dp(120)); for (int a = 0; a < mediaPages.length; a++) { float t = -(getMeasuredHeight() - height) / 2f; mediaPages[a].emptyView.setTranslationY(t); @@ -4599,6 +4682,13 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + } else if (id == NotificationCenter.channelRecommendationsLoaded) { + long chatId = (long) args[0]; + if (chatId == -dialog_id) { + channelRecommendationsAdapter.update(true); + updateTabs(true); + checkCurrentTabValid(); + } } } @@ -4891,6 +4981,7 @@ private void updateTabs(boolean animated) { if (!delegate.isFragmentOpened()) { animated = false; } + boolean hasRecommendations = false; int changed = 0; if (((DialogObject.isUserDialog(dialog_id) || DialogObject.isChatDialog(dialog_id)) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || info != null && info.stories_pinned_available || isStoriesView()) && includeStories()) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { changed++; @@ -4926,6 +5017,10 @@ private void updateTabs(boolean animated) { if ((hasMedia[6] <= 0) == scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { changed++; } + hasRecommendations = !channelRecommendationsAdapter.chats.isEmpty(); + if (hasRecommendations != scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { + changed++; + } } if (changed > 0) { if (animated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -4986,8 +5081,8 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta } if (!isStoriesView()) { if (chatUsersAdapter.chatInfo != null) { - if (!scrollSlidingTextTabStrip.hasTab(7)) { - scrollSlidingTextTabStrip.addTextTab(7, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_GROUPUSERS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_GROUPUSERS, LocaleController.getString("GroupMembers", R.string.GroupMembers), idToView); } } if (hasMedia[0] > 0) { @@ -5028,43 +5123,55 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta scrollSlidingTextTabStrip.addTextTab(0, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView, longClickListener); } } + if (!scrollSlidingTextTabStrip.hasTab(TAB_PHOTOVIDEO)) { + if (hasMedia[1] == 0 && hasMedia[2] == 0 && hasMedia[3] == 0 && hasMedia[4] == 0 && hasMedia[5] == 0 && hasMedia[6] == 0 && chatUsersAdapter.chatInfo == null) { + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTabFull2", R.string.SharedMediaTabFull2), idToView); + } else { + scrollSlidingTextTabStrip.addTextTab(TAB_PHOTOVIDEO, LocaleController.getString("SharedMediaTab2", R.string.SharedMediaTab2), idToView); + } + } } if (hasMedia[1] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(1)) { - scrollSlidingTextTabStrip.addTextTab(1, LocaleController.getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_FILES)) { + scrollSlidingTextTabStrip.addTextTab(TAB_FILES, LocaleController.getString("SharedFilesTab2", R.string.SharedFilesTab2), idToView); } } if (!DialogObject.isEncryptedDialog(dialog_id)) { if (hasMedia[3] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(3)) { - scrollSlidingTextTabStrip.addTextTab(3, LocaleController.getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_LINKS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_LINKS, LocaleController.getString("SharedLinksTab2", R.string.SharedLinksTab2), idToView); } } if (hasMedia[4] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(4)) { - scrollSlidingTextTabStrip.addTextTab(4, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } else { if (hasMedia[4] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(4)) { - scrollSlidingTextTabStrip.addTextTab(4, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_AUDIO)) { + scrollSlidingTextTabStrip.addTextTab(TAB_AUDIO, LocaleController.getString("SharedMusicTab2", R.string.SharedMusicTab2), idToView); } } } if (hasMedia[2] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(2)) { - scrollSlidingTextTabStrip.addTextTab(2, LocaleController.getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_VOICE)) { + scrollSlidingTextTabStrip.addTextTab(TAB_VOICE, LocaleController.getString("SharedVoiceTab2", R.string.SharedVoiceTab2), idToView); } } if (hasMedia[5] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(5)) { - scrollSlidingTextTabStrip.addTextTab(5, LocaleController.getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_GIF)) { + scrollSlidingTextTabStrip.addTextTab(TAB_GIF, LocaleController.getString("SharedGIFsTab2", R.string.SharedGIFsTab2), idToView); } } if (hasMedia[6] > 0) { - if (!scrollSlidingTextTabStrip.hasTab(6)) { - scrollSlidingTextTabStrip.addTextTab(6, LocaleController.getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); + if (!scrollSlidingTextTabStrip.hasTab(TAB_COMMON_GROUPS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_COMMON_GROUPS, LocaleController.getString("SharedGroupsTab2", R.string.SharedGroupsTab2), idToView); + } + } + if (hasRecommendations) { + if (!scrollSlidingTextTabStrip.hasTab(TAB_RECOMMENDED_CHANNELS)) { + scrollSlidingTextTabStrip.addTextTab(TAB_RECOMMENDED_CHANNELS, LocaleController.getString(R.string.SimilarChannelsTab), idToView); } } } @@ -5184,7 +5291,7 @@ private void switchToCurrentSelectedMode(boolean animated) { mediaPages[a].listView.setPinnedHeaderShadowDrawable(null); mediaPages[a].listView.setPadding( mediaPages[a].listView.getPaddingLeft(), - AndroidUtilities.dp(2) + (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? AndroidUtilities.dp(64) : 0), + dp(2) + (mediaPages[a].listView.hintPaddingTop = mediaPages[a].selectedType == TAB_ARCHIVED_STORIES ? dp(64) : 0), mediaPages[a].listView.getPaddingRight(), mediaPages[a].listView.getPaddingBottom() ); @@ -5194,7 +5301,7 @@ private void switchToCurrentSelectedMode(boolean animated) { recycleAdapter(currentAdapter); mediaPages[a].listView.setAdapter(photoVideoAdapter); } - layoutParams.leftMargin = layoutParams.rightMargin = -AndroidUtilities.dp(1); + layoutParams.leftMargin = layoutParams.rightMargin = -dp(1); if (sharedMediaData[0].fastScrollDataLoaded && !sharedMediaData[0].fastScrollPeriods.isEmpty()) { fastScrollVisible = true; } @@ -5260,8 +5367,13 @@ private void switchToCurrentSelectedMode(boolean animated) { mediaPages[a].listView.setAdapter(archivedStoriesAdapter); } spanCount = mediaColumnsCount[1]; + } else if (mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { + if (currentAdapter != channelRecommendationsAdapter) { + recycleAdapter(currentAdapter); + mediaPages[a].listView.setAdapter(channelRecommendationsAdapter); + } } - if (mediaPages[a].selectedType == TAB_PHOTOVIDEO || mediaPages[a].selectedType == TAB_STORIES || mediaPages[a].selectedType == TAB_ARCHIVED_STORIES || mediaPages[a].selectedType == TAB_VOICE || mediaPages[a].selectedType == TAB_GIF || mediaPages[a].selectedType == TAB_COMMON_GROUPS || mediaPages[a].selectedType == TAB_GROUPUSERS && !delegate.canSearchMembers()) { + if (mediaPages[a].selectedType == TAB_PHOTOVIDEO || mediaPages[a].selectedType == TAB_STORIES || mediaPages[a].selectedType == TAB_ARCHIVED_STORIES || mediaPages[a].selectedType == TAB_VOICE || mediaPages[a].selectedType == TAB_GIF || mediaPages[a].selectedType == TAB_COMMON_GROUPS || mediaPages[a].selectedType == TAB_GROUPUSERS && !delegate.canSearchMembers() || mediaPages[a].selectedType == TAB_RECOMMENDED_CHANNELS) { if (animated) { searchItemState = 2; } else { @@ -5292,11 +5404,11 @@ private void switchToCurrentSelectedMode(boolean animated) { } } } - 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; @@ -5308,6 +5420,8 @@ private void switchToCurrentSelectedMode(boolean animated) { archivedStoriesAdapter.load(false); mediaPages[a].emptyView.showProgress(storiesList != null && (storiesList.isLoading() || hasInternet() && storiesList.getCount() > 0), animated); fastScrollVisible = storiesList != null && storiesList.getCount() > 0; + } else 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; @@ -6036,7 +6150,7 @@ public EmptyStubView(Context context, Theme.ResourcesProvider resourcesProvider) emptyTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); emptyTextView.setGravity(Gravity.CENTER); emptyTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); addView(emptyTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 24, 0, 0)); } @@ -6046,12 +6160,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int rotation = manager.getDefaultDisplay().getRotation(); ignoreRequestLayout = true; if (AndroidUtilities.isTablet()) { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); } else { if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), 0); + emptyTextView.setPadding(dp(40), 0, dp(40), 0); } else { - emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); + emptyTextView.setPadding(dp(40), 0, dp(40), dp(128)); } } ignoreRequestLayout = false; @@ -6779,6 +6893,205 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { } } + private class ChannelRecommendationsAdapter extends RecyclerListView.SelectionAdapter { + + private final Context mContext; + private final ArrayList chats = new ArrayList<>(); + private int more; + + public ChannelRecommendationsAdapter(Context context) { + mContext = context; + update(false); + } + + public void update(boolean notify) { + if (profileActivity == null || !DialogObject.isChatDialog(dialog_id)) { + return; + } + 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(thisChat.id); + chats.clear(); + if (rec != null) { + 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(); + } + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + @Override + public int getItemCount() { + return chats.size(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + if (viewType == 1) { + MoreRecommendationsCell cell = new MoreRecommendationsCell(profileActivity == null ? UserConfig.selectedAccount : profileActivity.getCurrentAccount(), mContext, resourcesProvider, () -> { + if (profileActivity != null) { + profileActivity.presentFragment(new PremiumPreviewFragment("similar_channels")); + } + }); + view = cell; + } else { // 0 + view = new ProfileSearchCell(mContext, resourcesProvider); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + 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; + if (holder.getItemViewType() == 0) { + cell = (ProfileSearchCell) holder.itemView; + } else if (holder.getItemViewType() == 1) { + cell = ((MoreRecommendationsCell) holder.itemView).channelCell; + } + if (cell != null) { + TLRPC.Chat chat = chats.get(position); + cell.setData(chat, null, null, null, false, false); + cell.useSeparator = position != chats.size() - 1; + } + } + + @Override + public int getItemViewType(int position) { + if (more > 0 && position == getItemCount() - 1) { + return 1; + } + return 0; + } + } + + private static class MoreRecommendationsCell extends FrameLayout { + + private final int currentAccount; + private final Theme.ResourcesProvider resourcesProvider; + + public final ProfileSearchCell channelCell; + + private final View gradientView; + private final ButtonWithCounterView button; + private final LinkSpanDrawable.LinksTextView textView; + + public MoreRecommendationsCell(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, Runnable onPremiumClick) { + super(context); + + this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + + channelCell = new ProfileSearchCell(context, resourcesProvider); + channelCell.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_ALL)); + addView(channelCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + gradientView = new View(context); + gradientView.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[] { + Theme.multAlpha(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider), .4f), + Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider) + })); + addView(gradientView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 60)); + + button = new ButtonWithCounterView(context, resourcesProvider); + SpannableStringBuilder buttonText = new SpannableStringBuilder(); + buttonText.append(LocaleController.getString(R.string.MoreSimilarButton)); + buttonText.append(" "); + SpannableString lock = new SpannableString("l"); + lock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + buttonText.append(lock); + button.setText(buttonText, false); + addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 14, 38, 14, 0)); + button.setOnClickListener(v -> { + if (onPremiumClick != null) { + onPremiumClick.run(); + } + }); + + textView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextAlignment(TEXT_ALIGNMENT_CENTER); + textView.setGravity(Gravity.CENTER); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider)); + textView.setLineSpacing(dp(3), 1f); + SpannableStringBuilder text = AndroidUtilities.premiumText(LocaleController.getString(R.string.MoreSimilarText), () -> { + if (onPremiumClick != null) { + onPremiumClick.run(); + } + }); + SpannableString count = new SpannableString("" + MessagesController.getInstance(currentAccount).recommendedChannelsLimitPremium); + count.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)), 0, count.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(AndroidUtilities.replaceCharSequence("%s", text, count)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 24, 96, 24, 12)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(145), MeasureSpec.EXACTLY)); + } + } + private class CommonGroupsAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; @@ -7716,7 +8029,7 @@ public boolean canZoomOut() { protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == fragmentContextView) { canvas.save(); - canvas.clipRect(0, mediaPages[0].getTop(), child.getMeasuredWidth(),mediaPages[0].getTop() + child.getMeasuredHeight() + AndroidUtilities.dp(12)); + canvas.clipRect(0, mediaPages[0].getTop(), child.getMeasuredWidth(),mediaPages[0].getTop() + child.getMeasuredHeight() + dp(12)); boolean b = super.drawChild(canvas, child, drawingTime); canvas.restore(); return b; @@ -7724,7 +8037,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return super.drawChild(canvas, child, drawingTime); } - private class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { + public class ScrollSlidingTextTabStripInner extends ScrollSlidingTextTabStrip { protected Paint backgroundPaint; public int backgroundColor = Color.TRANSPARENT; @@ -7798,7 +8111,7 @@ public InternalListView(Context context) { @Override public void updateClip(int[] clip) { - clip[0] = getPaddingTop() - AndroidUtilities.dp(2) - hintPaddingTop; + clip[0] = getPaddingTop() - dp(2) - hintPaddingTop; clip[1] = getMeasuredHeight() - getPaddingBottom(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleAvatarView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleAvatarView.java index c4dda1bcc0..a9d4bcfff7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleAvatarView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleAvatarView.java @@ -17,6 +17,8 @@ import org.telegram.tgnet.TLObject; import org.telegram.ui.ActionBar.Theme; +import xyz.nextalone.nagram.NaConfig; + public class SimpleAvatarView extends View { public final static int SELECT_ANIMATION_DURATION = 200; @@ -70,7 +72,12 @@ protected void onDraw(Canvas canvas) { selectPaint.setAlpha((int) (Color.alpha(selectPaint.getColor()) * selectProgress)); float stroke = selectPaint.getStrokeWidth(); AndroidUtilities.rectTmp.set(stroke, stroke, getWidth() - stroke, getHeight() - stroke); - canvas.drawArc(AndroidUtilities.rectTmp, -90, selectProgress * 360, false, selectPaint); + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + final float w = selectPaint.getStrokeWidth(); + canvas.drawRect(w, w, getWidth() - w, getHeight() - w, selectPaint); + } else { + canvas.drawArc(AndroidUtilities.rectTmp, -90, selectProgress * 360, false, selectPaint); + } canvas.restore(); if (!isAvatarHidden) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java index 8cfe7ac356..610559b139 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java @@ -479,6 +479,8 @@ public int getBackgroundTranslationY() { return emojiHeight; } return backgroundTranslationY; + } else if (backgroundDrawable instanceof ChatBackgroundDrawable) { + return backgroundTranslationY; } return 0; } @@ -498,6 +500,8 @@ public int getBackgroundSizeY() { } else { offset = backgroundTranslationY != 0 ? 0 : -keyboardHeight; } + } else if (backgroundDrawable instanceof ChatBackgroundDrawable) { + offset = backgroundTranslationY; } return getMeasuredHeight() - offset; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java index 7de5f6732c..a49fb323f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StaticLayoutEx.java @@ -99,19 +99,15 @@ public static StaticLayout createStaticLayout2(CharSequence source, TextPaint pa .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE); return builder.build(); } else { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); + return createStaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); } } public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines) { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); + return createStaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, true); } - public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { - return createStaticLayout(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad, ellipsize, ellipsisWidth, maxLines, canContainUrl); - } - - public static StaticLayout createStaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerWidth, Layout.Alignment align, float spacingMult, float spacingAdd, boolean includePad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { + public static StaticLayout createStaticLayout(CharSequence source, TextPaint paint, int outerWidth, Layout.Alignment align, float spacingMult, float spacingAdd, boolean includePad, TextUtils.TruncateAt ellipsize, int ellipsisWidth, int maxLines, boolean canContainUrl) { /*if (Build.VERSION.SDK_INT >= 14) { init(); try { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusBadgeComponent.java index e207e00a5d..1db8830bd8 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.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 Drawable updateDrawable(TLRPC.User user, TLRPC.Chat chat, int colorFilter 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) { - statusDrawable.set(verifiedDrawable = (verifiedDrawable == null ? new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable) : verifiedDrawable), animated); + } 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.emoji_status instanceof TLRPC.TL_emojiStatus) { - statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + } 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_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/StickerCategoriesListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java index ed36642213..caf86c1ed6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java @@ -447,7 +447,7 @@ public void draw(Canvas canvas) { // } } - private RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); + private final RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); private void drawSelectedHighlight(Canvas canvas) { float alpha = selectedAlpha.set(selectedCategoryIndex >= 0 ? 1 : 0); float index = selectedCategoryIndex >= 0 ? selectedIndex.set(selectedCategoryIndex) : selectedIndex.get(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java index 984f189be3..44fbdfea12 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 StickerSetBulletinLayout(@NonNull Context context, TLObject setObject, in 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 StickerSetBulletinLayout(@NonNull Context context, TLObject setObject, in } 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/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index 8cf61eb16c..90a45305ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -1162,7 +1162,7 @@ public void onClick(View widget) { pickerBottomLayout.setBackground(null); setButton(null, null, -1); - premiumButtonView.setButton(LocaleController.getString("UnlockPremiumEmoji", R.string.UnlockPremiumEmoji), e -> { + premiumButtonView.setButton(LocaleController.getString(R.string.UnlockPremiumEmoji), e -> { if (parentFragment != null) { new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); } else if (getContext() instanceof LaunchActivity) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java index b38484d471..dcd66375e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java @@ -191,8 +191,8 @@ public int getOpacity() { }; } ColorStateList colorStateList = new ColorStateList( - new int[][]{StateSet.WILD_CARD}, - new int[]{0} + new int[][]{StateSet.WILD_CARD}, + new int[]{0} ); rippleDrawable = new RippleDrawable(colorStateList, null, maskDrawable); if (Build.VERSION.SDK_INT >= 23) { @@ -201,13 +201,11 @@ public int getOpacity() { rippleDrawable.setCallback(this); } if (isChecked && colorSet != 2 || !isChecked && colorSet != 1) { - int color = isChecked ? Theme.getColor(Theme.key_switchTrackBlueSelectorChecked, resourcesProvider) : Theme.getColor(Theme.key_switchTrackBlueSelector, resourcesProvider); - /*if (Build.VERSION.SDK_INT < 28) { - color = Color.argb(Color.alpha(color) * 2, Color.red(color), Color.green(color), Color.blue(color)); - }*/ + int color = Theme.getColor(isChecked ? Theme.key_switchTrackBlueSelectorChecked : Theme.key_switchTrackBlueSelector, resourcesProvider); + color = processColor(color); ColorStateList colorStateList = new ColorStateList( - new int[][]{StateSet.WILD_CARD}, - new int[]{color} + new int[][]{StateSet.WILD_CARD}, + new int[]{color} ); rippleDrawable.setColor(colorStateList); colorSet = isChecked ? 2 : 1; @@ -224,6 +222,10 @@ protected boolean verifyDrawable(Drawable who) { return super.verifyDrawable(who) || rippleDrawable != null && who == rippleDrawable; } + protected int processColor(int color) { + return color; + } + public void setColors(int track, int trackChecked, int thumb, int thumbChecked) { trackColorKey = track; trackCheckedColorKey = trackChecked; @@ -416,8 +418,8 @@ protected void onDraw(Canvas canvas) { colorProgress = progress; } - color1 = Theme.getColor(trackColorKey, resourcesProvider); - color2 = Theme.getColor(trackCheckedColorKey, resourcesProvider); + color1 = processColor(Theme.getColor(trackColorKey, resourcesProvider)); + color2 = processColor(Theme.getColor(trackCheckedColorKey, resourcesProvider)); if (a == 0 && iconDrawable != null && lastIconColor != (isChecked ? color2 : color1)) { iconDrawable.setColorFilter(new PorterDuffColorFilter(lastIconColor = (isChecked ? color2 : color1), PorterDuff.Mode.SRC_IN)); } @@ -471,8 +473,8 @@ protected void onDraw(Canvas canvas) { colorProgress = progress; } - color1 = Theme.getColor(thumbColorKey, resourcesProvider); - color2 = Theme.getColor(thumbCheckedColorKey, resourcesProvider); + color1 = processColor(Theme.getColor(thumbColorKey, resourcesProvider)); + color2 = processColor(Theme.getColor(thumbCheckedColorKey, resourcesProvider)); r1 = Color.red(color1); r2 = Color.red(color2); g1 = Color.green(color1); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java index 9161dba4fc..819cabdfc0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java @@ -14,6 +14,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import androidx.annotation.NonNull; @@ -26,22 +27,34 @@ public class Text { private StaticLayout layout; private float width, left; - public Text(CharSequence text, int textSizeDp) { + public Text(CharSequence text, float textSizeDp) { this(text, textSizeDp, null); } - public Text(CharSequence text, int textSizeDp, Typeface typeface) { + public Text(CharSequence text, float textSizeDp, Typeface typeface) { paint.setTextSize(dp(textSizeDp)); paint.setTypeface(typeface); setText(text); } public void setText(CharSequence text) { - layout = new StaticLayout(text, paint, 99999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + layout = new StaticLayout(AndroidUtilities.replaceNewLines(text), paint, 99999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); width = layout.getLineCount() > 0 ? layout.getLineWidth(0) : 0; left = layout.getLineCount() > 0 ? layout.getLineLeft(0) : 0; } + private boolean hackClipBounds; + public Text hackClipBounds() { + this.hackClipBounds = true; + return this; + } + + private boolean doNotSave; + public Text doNotSave() { + this.doNotSave = true; + return this; + } + public float getTextSize() { return paint.getTextSize(); } @@ -72,23 +85,33 @@ public void draw(Canvas canvas, float x, float cy, int color, float alpha) { return; } paint.setColor(color); + final int wasAlpha = paint.getAlpha(); if (alpha != 1f) { - paint.setAlpha((int) (paint.getAlpha() * alpha)); + paint.setAlpha((int) (wasAlpha * alpha)); + } + if (!doNotSave) { + canvas.save(); } - canvas.save(); canvas.translate(x - left, cy - layout.getHeight() / 2f); draw(canvas); - canvas.restore(); + if (!doNotSave) { + canvas.restore(); + } + paint.setAlpha(wasAlpha); } public void draw(Canvas canvas, float x, float cy) { if (layout == null) { return; } - canvas.save(); + if (!doNotSave) { + canvas.save(); + } canvas.translate(x - left, cy - layout.getHeight() / 2f); draw(canvas); - canvas.restore(); + if (!doNotSave) { + canvas.restore(); + } } private LinearGradient ellipsizeGradient; @@ -99,11 +122,15 @@ public void draw(Canvas canvas) { if (layout == null) { return; } - if (ellipsizeWidth >= 0 && width > ellipsizeWidth) { + if (!doNotSave && ellipsizeWidth >= 0 && width > ellipsizeWidth) { canvas.saveLayerAlpha(0, 0, ellipsizeWidth, layout.getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); } - layout.draw(canvas); - if (ellipsizeWidth >= 0 && width > ellipsizeWidth) { + if (hackClipBounds) { + canvas.drawText(layout.getText().toString(), 0, -paint.getFontMetricsInt().ascent, paint); + } else { + layout.draw(canvas); + } + if (!doNotSave && ellipsizeWidth >= 0 && width > ellipsizeWidth) { if (ellipsizeGradient == null) { ellipsizeGradient = new LinearGradient(0, 0, dp(8), 0, new int[] { 0x00ffffff, 0xffffffff }, new float[] {0, 1}, Shader.TileMode.CLAMP); ellipsizeMatrix = new Matrix(); @@ -121,6 +148,10 @@ public void draw(Canvas canvas) { } } + public Paint.FontMetricsInt getFontMetricsInt() { + return paint.getFontMetricsInt(); + } + public float getWidth() { return ellipsizeWidth >= 0 ? Math.min(ellipsizeWidth, width) : width; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ThanosEffect.java new file mode 100644 index 0000000000..9297734708 --- /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 f94327b3d2..c47e1176b8 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 ThemeSmallPreviewView(Context context, int currentAccount, Theme.Resource 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 ThemeSmallPreviewView(Context context, int currentAccount, Theme.Resource @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 @@ protected void dispatchDraw(Canvas canvas) { 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 void setItem(ChatThemeBottomSheet.ChatThemeItem item, boolean animated) { 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 void setItem(ChatThemeBottomSheet.ChatThemeItem item, boolean animated) { chatBackgroundDrawable = null; } } + backupImageView.setVisibility(item.chatTheme.showAsDefaultStub && fallbackWallpaper != null ? View.GONE : View.VISIBLE); if (itemChanged || darkModeChanged) { if (animated) { @@ -314,7 +333,7 @@ public void setItem(ChatThemeBottomSheet.ChatThemeItem item, boolean animated) { } 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 @@ private Drawable getPreviewDrawable(EmojiThemes.ThemeItem item) { 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 @@ private StaticLayout getNoThemeStaticLayout() { } 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 void drawBackground(Canvas canvas, float alpha) { 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 void draw(Canvas canvas, float alpha) { 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 void draw(Canvas canvas, float alpha) { } } 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 void draw(Canvas canvas, float alpha) { 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 void draw(Canvas canvas, float alpha) { 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 void draw(Canvas canvas, float alpha) { 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/TranscribeButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java index a0ae92c125..e846e29789 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranscribeButton.java @@ -1,11 +1,15 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; @@ -35,6 +39,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; @@ -54,8 +59,11 @@ public class TranscribeButton { private Paint backgroundPaint, strokePaint; private Path progressClipPath; + private boolean drawLock; + private final AnimatedFloat animatedDrawLock; + private boolean loading; - private AnimatedFloat loadingFloat; + private final AnimatedFloat loadingFloat; private int inIconDrawableAlpha; private RLottieDrawable inIconDrawable; @@ -77,11 +85,11 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { start = SystemClock.elapsedRealtime(); this.parent = parent; this.seekBar = seekBar; - this.bounds = new Rect(0, 0, AndroidUtilities.dp(30), AndroidUtilities.dp(30)); + this.bounds = new Rect(0, 0, dp(30), dp(30)); this.pressBounds = new Rect(this.bounds); - this.pressBounds.inset(AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + this.pressBounds.inset(dp(8), dp(8)); - outIconDrawable = new RLottieDrawable(R.raw.transcribe_out, "transcribe_out", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); + outIconDrawable = new RLottieDrawable(R.raw.transcribe_out, "transcribe_out", dp(26), dp(26)); outIconDrawable.setCurrentFrame(0); outIconDrawable.setCallback(parent); outIconDrawable.setOnFinishCallback(() -> { @@ -92,7 +100,7 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { }, 19); outIconDrawable.setAllowDecodeSingleFrame(true); - inIconDrawable = new RLottieDrawable(R.raw.transcribe_in, "transcribe_in", AndroidUtilities.dp(26), AndroidUtilities.dp(26)); + inIconDrawable = new RLottieDrawable(R.raw.transcribe_in, "transcribe_in", dp(26), dp(26)); inIconDrawable.setCurrentFrame(0); inIconDrawable.setCallback(parent); inIconDrawable.setMasterParent(parent); @@ -109,13 +117,24 @@ public TranscribeButton(ChatMessageCell parent, SeekBarWaveform seekBar) { premium = parent.getMessageObject() != null && UserConfig.getInstance(parent.getMessageObject().currentAccount).isPremium(); loadingFloat = new AnimatedFloat(parent, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + animatedDrawLock = new AnimatedFloat(parent, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + public void setLock(boolean drawLock, boolean animated) { + if (this.drawLock != drawLock && parent != null) { + parent.invalidate(); + } + this.drawLock = drawLock; + if (!animated) { + animatedDrawLock.set(drawLock, true); + } } public void setLoading(boolean loading, boolean animated) { this.loading = loading; seekBar.setLoading(loading); if (!animated) { - loadingFloat.set(this.loading ? 1 : 0, true); + loadingFloat.set(this.loading, true); } else { if (loadingFloat.get() <= 0f) { start = SystemClock.elapsedRealtime(); @@ -185,11 +204,14 @@ public boolean onTouch(int action, float x, float y) { } public void onTap() { + if (parent == null) { + return; + } clickedToOpen = false; boolean processClick, toOpen = !shouldBeOpen; if (!shouldBeOpen) { processClick = !loading; - if (premium && parent.getMessageObject().isSent()) { + if ((premium || canTranscribeTrial(parent.getMessageObject())) && parent.getMessageObject().isSent()) { setLoading(true, true); } } else { @@ -204,14 +226,22 @@ public void onTap() { pressed = false; if (processClick) { if (!premium && toOpen) { - if (parent.getDelegate() != null) { - parent.getDelegate().needShowPremiumBulletin(0); + if (canTranscribeTrial(parent.getMessageObject()) || parent.getMessageObject() != null && parent.getMessageObject().messageOwner != null && !TextUtils.isEmpty(parent.getMessageObject().messageOwner.voiceTranscription)) { + transcribePressed(parent.getMessageObject(), toOpen, parent.getDelegate()); + } else { + if (parent.getDelegate() != null) { + if (MessagesController.getInstance(parent.currentAccount).transcribeAudioTrialWeeklyNumber > 0) { + parent.getDelegate().needShowPremiumBulletin(3); + } else { + parent.getDelegate().needShowPremiumBulletin(0); + } + } } } else { if (toOpen) { clickedToOpen = true; } - transcribePressed(parent.getMessageObject(), toOpen); + transcribePressed(parent.getMessageObject(), toOpen, parent.getDelegate()); } } } @@ -237,7 +267,7 @@ public void setColor(int color, int grayColor, boolean isOut, float bgBack) { backgroundPaint.setColor(this.backgroundColor); backgroundPaint.setAlpha((int) (backgroundPaint.getAlpha() * (1f - bgBack))); if (newColor || selectorDrawable == null) { - selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(8), 0, this.rippleColor); + selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(dp(8), 0, this.rippleColor); selectorDrawable.setCallback(parent); } if (newColor) { @@ -287,7 +317,7 @@ public int height() { } public void draw(Canvas canvas, float alpha) { - this.pressBounds.set(this.bounds.left - AndroidUtilities.dp(8), this.bounds.top - AndroidUtilities.dp(8), this.bounds.right + AndroidUtilities.dp(8), this.bounds.bottom + AndroidUtilities.dp(8)); + this.pressBounds.set(this.bounds.left - dp(8), this.bounds.top - dp(8), this.bounds.right + dp(8), this.bounds.bottom + dp(8)); if (boundsPath == null) { boundsPath = new Path(); } else { @@ -341,7 +371,7 @@ public void draw(Canvas canvas, float alpha) { addCorner(progressClipPath, bounds.left, bounds.top, diameter, 4, from, to, 360 - b, 360 - a); addLine(progressClipPath, bounds.left + radius, bounds.top, bounds.centerX(), bounds.top, from, to, 360 - a, 360); - strokePaint.setStrokeWidth(AndroidUtilities.dp(1.5f)); + strokePaint.setStrokeWidth(dp(1.5f)); int wasAlpha = strokePaint.getAlpha(); strokePaint.setAlpha((int) (wasAlpha * alpha)); canvas.drawPath(progressClipPath, strokePaint); @@ -351,7 +381,8 @@ public void draw(Canvas canvas, float alpha) { } canvas.save(); - canvas.translate(bounds.centerX() + AndroidUtilities.dp(2 - 15), bounds.centerY() + AndroidUtilities.dp(-1 - 12)); + canvas.translate(bounds.centerX() + dp(2 - 15), bounds.centerY() + dp(-1 - 12)); + canvas.saveLayerAlpha(0, 0, dp(26), dp(26), 0xFF, Canvas.ALL_SAVE_FLAG); if (isOpen) { inIconDrawable.setAlpha((int) (inIconDrawableAlpha * alpha)); inIconDrawable.draw(canvas); @@ -359,6 +390,55 @@ public void draw(Canvas canvas, float alpha) { outIconDrawable.setAlpha((int) (outIconDrawableAlpha * alpha)); outIconDrawable.draw(canvas); } + drawLock(canvas); + canvas.restore(); + canvas.restore(); + } + + private Paint clipLockPaint; + private Paint lockPaint, lockStrokePaint; + private float lockHandlePathDensity; + private Path lockHandlePath; + + private void drawLock(Canvas canvas) { + final float alpha = animatedDrawLock.set(drawLock && !isOpen && !loading); + if (alpha <= 0) { + return; + } + + canvas.save(); + canvas.translate(dp(16 + 2), dp(10 + 2)); + if (clipLockPaint == null) { + clipLockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + clipLockPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + AndroidUtilities.rectTmp.set(0, -dp(.4f), dp(6.666f), dp(8.333f + .4f)); + canvas.scale(alpha, alpha, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2), dp(2), clipLockPaint); + if (lockPaint == null) { + lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + lockPaint.setColor(iconColor); + lockPaint.setAlpha((int) (0xFF * alpha)); + AndroidUtilities.rectTmp.set(0, dp(3.33f), dp(6.666f), dp(3.33f + 5)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(1.33f), dp(1.33f), lockPaint); + if (lockHandlePath == null || Math.abs(lockHandlePathDensity - AndroidUtilities.density) > 0.1f) { + lockHandlePathDensity = AndroidUtilities.density; + lockHandlePath = new Path(); + lockHandlePath.moveTo(dp(1.66f), dp(3.33f)); + lockHandlePath.lineTo(dp(1.66f), dp(2)); + AndroidUtilities.rectTmp.set(dp(1.66f), dp(0.33f), dp(1.66f + 3.33f), dp(0.33f + 3.33f)); + lockHandlePath.arcTo(AndroidUtilities.rectTmp, -180, 180, false); + lockHandlePath.lineTo(dp(5), dp(3.33f)); + } + if (lockStrokePaint == null) { + lockStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + lockStrokePaint.setStyle(Paint.Style.STROKE); + } + lockStrokePaint.setStrokeWidth(dp(1)); + lockStrokePaint.setColor(iconColor); + lockStrokePaint.setAlpha((int) (0xFF * alpha)); + canvas.drawPath(lockHandlePath, lockStrokePaint); canvas.restore(); } @@ -575,7 +655,7 @@ public static boolean isTranscribing(MessageObject messageObject) { ); } - private static void transcribePressed(MessageObject messageObject, boolean open) { + private static void transcribePressed(MessageObject messageObject, boolean open, ChatMessageCell.ChatMessageCellDelegate delegate) { if (messageObject == null || messageObject.messageOwner == null || !messageObject.isSent()) { return; } @@ -603,6 +683,10 @@ private static void transcribePressed(MessageObject messageObject, boolean open) transcribeOperationsByDialogPosition = new HashMap<>(); } transcribeOperationsByDialogPosition.put((Integer) reqInfoHash(messageObject), messageObject); + int flags = 0; + if (!UserConfig.getInstance(account).isPremium()) { + flags |= ConnectionsManager.RequestFlagDoNotWaitFloodWait; + } ConnectionsManager.getInstance(account).sendRequest(req, (res, err) -> { String text; long id = 0; @@ -615,12 +699,39 @@ private static void transcribePressed(MessageObject messageObject, boolean open) if (TextUtils.isEmpty(text)) { text = !isFinal ? null : ""; } + if ((r.flags & 2) != 0) { + MessagesController.getInstance(account).updateTranscribeAudioTrialCurrentNumber(r.trial_remains_num); + MessagesController.getInstance(account).updateTranscribeAudioTrialCooldownUntil(r.trial_remains_until_date); + AndroidUtilities.runOnUIThread(() -> { + if (delegate != null) { + delegate.needShowPremiumBulletin(r.trial_remains_num > 0 ? 1 : 2); + } + }); + } if (transcribeOperationsById == null) { transcribeOperationsById = new HashMap<>(); } transcribeOperationsById.put(id, messageObject); messageObject.messageOwner.voiceTranscriptionId = id; } else { + if (err != null && err.text != null) { + if (err.text.startsWith("FLOOD_WAIT_")) { + MessagesController.getInstance(account).updateTranscribeAudioTrialCurrentNumber(0); + MessagesController.getInstance(account).updateTranscribeAudioTrialCooldownUntil(ConnectionsManager.getInstance(account).getCurrentTime() + Utilities.parseInt(err.text)); + AndroidUtilities.runOnUIThread(() -> { + if (transcribeOperationsByDialogPosition != null) { + transcribeOperationsByDialogPosition.remove((Integer) reqInfoHash(messageObject)); + } + if (delegate != null) { + delegate.needShowPremiumBulletin(3); + } + NotificationCenter.getInstance(account).postNotificationName(NotificationCenter.voiceTranscriptionUpdate, messageObject); + NotificationCenter.getInstance(account).postNotificationName(NotificationCenter.updateTranscriptionLock); + }); + return; + } + } + text = ""; isFinal = true; } @@ -638,7 +749,7 @@ private static void transcribePressed(MessageObject messageObject, boolean open) if (isFinal) { AndroidUtilities.runOnUIThread(() -> finishTranscription(messageObject, finalId, finalText), Math.max(0, minDuration - duration)); } - }); + }, flags); } } else { if (transcribeOperationsByDialogPosition != null) { @@ -695,4 +806,42 @@ public static void showOffTranscribe(MessageObject messageObject, boolean notify }); } } + + public static boolean canTranscribeTrial(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + ConnectionsManager cc = ConnectionsManager.getInstance(messageObject.currentAccount); + MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + if (mc.transcribeAudioTrialWeeklyNumber <= 0 || messageObject.getDuration() > mc.transcribeAudioTrialDurationMax) { + return false; + } + return mc.transcribeAudioTrialCooldownUntil == 0 || cc.getCurrentTime() > mc.transcribeAudioTrialCooldownUntil || mc.transcribeAudioTrialCurrentNumber > 0; + } + + public static int getTranscribeTrialCount(int currentAccount) { + ConnectionsManager cc = ConnectionsManager.getInstance(currentAccount); + MessagesController mc = MessagesController.getInstance(currentAccount); + if (mc.transcribeAudioTrialWeeklyNumber <= 0) { + return 0; + } + if (mc.transcribeAudioTrialCooldownUntil == 0 || cc.getCurrentTime() > mc.transcribeAudioTrialCooldownUntil) + return mc.transcribeAudioTrialWeeklyNumber; + return mc.transcribeAudioTrialCurrentNumber; + } + + public static boolean showTranscribeLock(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + if (!TextUtils.isEmpty(messageObject.messageOwner.voiceTranscription)) { + return false; + } + ConnectionsManager cc = ConnectionsManager.getInstance(messageObject.currentAccount); + MessagesController mc = MessagesController.getInstance(messageObject.currentAccount); + if (UserConfig.getInstance(messageObject.currentAccount).isPremium()) { + return false; + } + return mc.transcribeAudioTrialCooldownUntil != 0 && cc.getCurrentTime() <= mc.transcribeAudioTrialCooldownUntil && mc.transcribeAudioTrialCurrentNumber <= 0; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java index 75e1c00267..c830ea0d04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -576,7 +576,7 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj icon = 0; AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImageView.setForUserOrChat(user, avatarDrawable); avatarImageView.setVisibility(VISIBLE); timeLeft = 3000; @@ -601,7 +601,7 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj icon = 0; AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(AndroidUtilities.dp(12)); - avatarDrawable.setInfo((TLObject) infoObject); + avatarDrawable.setInfo(currentAccount, (TLObject) infoObject); avatarImageView.setForUserOrChat((TLObject) infoObject, avatarDrawable); avatarImageView.setVisibility(VISIBLE); timeLeft = 3000; @@ -611,12 +611,12 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj String name; if (infoObject instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) infoObject; - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImageView.setForUserOrChat(user, avatarDrawable); name = ContactsController.formatName(user.first_name, user.last_name); } else { TLRPC.Chat chat = (TLRPC.Chat) infoObject; - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); avatarImageView.setForUserOrChat(chat, avatarDrawable); name = chat.title; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java index 28cb79dcd5..1edfda29e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java @@ -1,7 +1,10 @@ package org.telegram.ui.Components; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import androidx.annotation.NonNull; @@ -46,7 +49,7 @@ public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPr this.type = type; this.isPremium = isPremiumUser; int color1 = ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(0), 255); - int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; + int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; int color3 = vectorImageMarkup.background_colors.size() > 2 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(2), 255) : 0; int color4 = vectorImageMarkup.background_colors.size() > 3 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(3), 255) : 0; gradientTools.setColors(color1, color2, color3, color4); @@ -60,6 +63,7 @@ public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPr } animatedEmojiDrawable = new AnimatedEmojiDrawable(cacheType, UserConfig.selectedAccount, emojiMarkup.emoji_id); + animatedEmojiDrawable.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); } else if (vectorImageMarkup instanceof TLRPC.TL_videoSizeStickerMarkup) { sizeStickerMarkup = (TLRPC.TL_videoSizeStickerMarkup) vectorImageMarkup; imageReceiver = new ImageReceiver() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java index e16dfce990..886bbd11b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperCheckBoxView.java @@ -4,6 +4,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -12,6 +13,8 @@ import android.util.Property; import android.view.View; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.ActionBar.Theme; @@ -55,7 +58,7 @@ public Float get(WallpaperCheckBoxView object) { public WallpaperCheckBoxView(Context context, boolean check, View parent, Theme.ResourcesProvider resourcesProvider) { super(context); - // this.resourcesProvider = resourcesProvider; + this.resourcesProvider = resourcesProvider; rect = new RectF(); if (check) { @@ -106,6 +109,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(maxTextSize + AndroidUtilities.dp(14 * 2 + 28), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); } + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float dimAmount; + public void setDimAmount(float dimAmount) { + this.dimAmount = dimAmount; + dimPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (0xFF * dimAmount))); + invalidate(); + } + @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -113,9 +124,11 @@ protected void onDraw(Canvas canvas) { canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, getThemedPaint(Theme.key_paint_chatActionBackground)); boolean hasGradient = resourcesProvider == null ? Theme.hasGradientService() : resourcesProvider.hasGradientService(); if (hasGradient) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, getThemedPaint(Theme.key_paint_chatActionBackgroundDarken)); + } + if (dimAmount > 0) { + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, dimPaint); } - textPaint.setColor(Theme.getColor(Theme.key_chat_serviceText, resourcesProvider)); int x = (getMeasuredWidth() - currentTextSize - AndroidUtilities.dp(28)) / 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect2.java index 098537e446..261be2988a 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.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 static void pause(boolean pause) { 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 void draw(Canvas canvas, View view, int w, int h) { } 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 void draw(Canvas canvas, View view, int w, int h, float alpha) { 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 1e3d2530eb..b5a33440cc 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.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.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 AcceptDeclineView(@NonNull Context context) { 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 boolean onTouchEvent(MotionEvent event) { 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 boolean onTouchEvent(MotionEvent event) { 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 boolean onTouchEvent(MotionEvent event) { 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 boolean onTouchEvent(MotionEvent event) { 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 boolean onTouchEvent(MotionEvent event) { setPressed(false); break; } - return false; } @@ -275,68 +256,33 @@ protected void onDraw(Canvas canvas) { 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 @@ protected void onDraw(Canvas canvas) { 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 @@ protected void onDraw(Canvas canvas) { canvas.restore(); canvas.restore(); + + if (captured) { + invalidate(); + } } public void setListener(Listener listener) { @@ -390,16 +340,43 @@ public interface Listener { 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 @@ protected void drawableStateChanged() { } @Override - public boolean verifyDrawable(Drawable drawable) { + public boolean verifyDrawable(@NonNull Drawable drawable) { return rippleDrawable == drawable || super.verifyDrawable(drawable); } @@ -496,10 +473,6 @@ protected void onVirtualViewClick(int virtualViewId) { 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 0000000000..a97fa69e2c --- /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 0000000000..1f7fc064d1 --- /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 00970215cd..f5b08b01b4 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 @@ protected void onBoundsChange(Rect bounds) { 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/GroupCallMiniTextureView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java index e8e7a52d06..87478e8fe8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java @@ -1085,13 +1085,13 @@ public void onAnimationEnd(Animator animation) { Object parentObject; if (DialogObject.isUserDialog(peerId)) { TLRPC.User currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId); - noVideoStubLayout.avatarDrawable.setInfo(currentUser); + noVideoStubLayout.avatarDrawable.setInfo(currentAccount, currentUser); imageLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_SMALL); parentObject = currentUser; } else { TLRPC.Chat currentChat = AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().getChat(-peerId); - noVideoStubLayout.avatarDrawable.setInfo(currentChat); + noVideoStubLayout.avatarDrawable.setInfo(currentAccount, currentChat); imageLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_SMALL); parentObject = currentChat; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/HideEmojiTextView.java new file mode 100644 index 0000000000..4b177f6947 --- /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 0000000000..d7847f7211 --- /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 0000000000..02f6189fd6 --- /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 0000000000..9c93ddc7d8 --- /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 0000000000..5cf2495337 --- /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 0000000000..a3ed2e7028 --- /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 8825892d1b..f264bd6408 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 boolean onTouchEvent(MotionEvent event) { 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 @@ private void setRelativePositionInternal(float xRelative, float yRelative, int w .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 b9c0cdd109..6aaab0cb3b 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 @@ -410,23 +410,40 @@ public static boolean canRateCall(TLRPC.TL_messageActionPhoneCall call) { return 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); - for (String hash : hashes) { - String[] d = hash.split(" "); - if (d.length < 2) - continue; - if (d[0].equals(call.call_id + "")) { - try { - long accessHash = Long.parseLong(d[1]); - showRateAlert(context, null, call.video, call.call_id, accessHash, UserConfig.selectedAccount, true); - } catch (Exception ignore) { - } - return; - } - } - } + 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); + for (String hash : hashes) { + String[] d = hash.split(" "); + if (d.length < 2) + continue; + if (d[0].equals(call.call_id + "")) { + try { + long accessHash = Long.parseLong(d[1]); + showRateAlert(context, null, call.video, call.call_id, accessHash, UserConfig.selectedAccount, true); + } catch (Exception ignore) { + } + return; + } + } + } public static void showRateAlert(final Context context, final Runnable onDismiss, boolean isVideo, final long callID, final long accessHash, final int account, final boolean userInitiative) { final File log = getLogFile(callID); 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 d34b13d073..caee016900 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.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 void addNotification(int iconRes, String text, String tag, boolean animat 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 void addNotification(int iconRes, String text, String tag, boolean animat } } + 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 @@ private void runDelayed() { 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 @@ private void runDelayed() { 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 @@ private static class NotificationView extends FrameLayout { 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 2f7dde5ab5..e7a2d062ec 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.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 VoIPStatusTextView(@NonNull Context context) { 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 VoIPStatusTextView(@NonNull Context context) { 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 void showTimer(boolean animated) { timerShowing = true; replaceViews(textView[0], timerView, null); } - - ellipsizeAnimator.removeView(textView[0]); - ellipsizeAnimator.removeView(textView[1]); } @@ -169,17 +188,10 @@ private void replaceViews(View out, View in, Runnable onEnd) { 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 void onAnimationEnd(Animator animation) { }).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 7b63a6dcfe..7b55ea5763 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.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 VoIPTimerView(Context context) { 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 @@ protected void onDraw(Canvas canvas) { 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 void setSignalBarCount(int count) { 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 7cf8598bfb..1228014d34 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 VoIPToggleButton(@NonNull Context context, float radius) { 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 void setDrawBackground(boolean value) { 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 @@ protected void onDraw(Canvas canvas) { } } } + 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 e5779637bb..1aeccf27fe 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 boolean onTouchEvent(MotionEvent event) { } 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 boolean onTouchEvent(MotionEvent event) { 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 boolean onTouchEvent(MotionEvent event) { } public void finish() { - finish(150); + finish(330); } public void finish(long animDuration) { @@ -141,7 +141,7 @@ public void finish(long animDuration) { } 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 void onAnimationEnd(Animator animation) { 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 0000000000..e569d15fa5 --- /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 0000000000..0dd78bb059 --- /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 0000000000..cec7d97b00 --- /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 0000000000..f5e705fadb --- /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 0000000000..8f48d428d6 --- /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 0000000000..ccfbc368c2 --- /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/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 5277056b2a..5201608059 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -205,6 +205,7 @@ public void onItemClick(int id) { doneButton = menu.addItem(done_button, LocaleController.getString("Done", R.string.Done).toUpperCase()); fragmentView = new ScrollView(context); + fragmentView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); @@ -876,7 +877,7 @@ public ArrayList getThemeDescriptions() { if (user == null) { return; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); avatarImage.invalidate(); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 30ce2e7b0a..5b18212212 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -1070,7 +1070,9 @@ public void onPause() { @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/DataUsage2Activity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java index 9ded923ceb..5fa4251606 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java @@ -1100,7 +1100,7 @@ public boolean isLightStatusBar() { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - if (event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { + if (event != null && event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { return true; } return pager.getCurrentPosition() == 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java b/TMessagesProj/src/main/java/org/telegram/ui/DefaultThemesPreviewCell.java index 980426c61c..9b4af25497 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 @@ @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 DefaultThemesPreviewCell(Context context, BaseFragment parentFragment, in 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 DefaultThemesPreviewCell(Context context, BaseFragment parentFragment, in 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 void updateLayoutManager() { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } 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 void selectTheme(Theme.ThemeInfo themeInfo) { } 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 444b819770..3d460d132e 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.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.SparseArray; @@ -166,6 +168,7 @@ import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlurredRecyclerView; +import org.telegram.ui.Components.BotWebViewSheet; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatActivityEnterView; @@ -191,6 +194,7 @@ 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; @@ -1313,7 +1317,7 @@ public boolean onTouchEvent(MotionEvent ev) { 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 || @@ -1334,7 +1338,9 @@ public boolean onTouchEvent(MotionEvent ev) { 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(); @@ -2908,6 +2914,11 @@ public void onFragmentDestroy() { SuggestClearDatabaseBottomSheet.dismissDialog(); } + @Override + public boolean dismissDialogOnPause(Dialog dialog) { + return !(dialog instanceof BotWebViewSheet) && super.dismissDialogOnPause(dialog); + } + @Override public ActionBar createActionBar(Context context) { ActionBar actionBar = new ActionBar(context) { @@ -3308,7 +3319,7 @@ public void setTranslationY(float translationY) { @Override protected void onDefaultTabMoved() { - if (!getMessagesController().premiumLocked) { + if (!getMessagesController().premiumFeaturesBlocked()) { try { if (!NekoConfig.disableVibration.Bool()) performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); @@ -3580,7 +3591,7 @@ public void onDeletePressed(int id) { switchItem.addView(imageView, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); TLRPC.User user = getUserConfig().getCurrentUser(); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); imageView.getImageReceiver().setCurrentAccount(currentAccount); Drawable thumb = user != null && user.photo != null && user.photo.strippedBitmap != null ? user.photo.strippedBitmap : avatarDrawable; imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", thumb, user); @@ -4794,7 +4805,7 @@ public void didPressAttachButton() { } @Override - public void needStartRecordVideo(int state, boolean notify, int scheduleDate) { + public void needStartRecordVideo(int state, boolean notify, int scheduleDate, int ttl) { } @@ -5426,21 +5437,28 @@ private int getMaxScrollYOffset() { } public boolean isPremiumRestoreHintVisible() { - if (!MessagesController.getInstance(currentAccount).premiumLocked && folderId == 0) { - return MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_RESTORE") && !getUserConfig().isPremium(); - } +// 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).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"); - return true; - } - } - } +// 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"); +// return true; +// } +// } +// } return false; } @@ -5521,8 +5539,8 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } } }; - 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); @@ -5653,6 +5671,31 @@ private void updateDialogsHint() { } 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); @@ -6047,7 +6090,7 @@ public void updateSpeedItem(boolean visibleByPosition) { 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) { @@ -6176,7 +6219,7 @@ public void onItemClick(int id) { } } 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) { @@ -7379,6 +7422,10 @@ public void setSearchAnimationProgress(float progress, boolean full) { dialogsHintCell.setVisibility(View.INVISIBLE); } else { dialogsHintCell.setVisibility(View.VISIBLE); + ViewParent dialogsHintCellParent = dialogsHintCell.getParent(); + if (dialogsHintCellParent != null) { + dialogsHintCellParent.requestLayout(); + } } } } @@ -7740,22 +7787,36 @@ private void onItemClick(View view, int position, RecyclerListView.Adapter adapt slowedReloadAfterDialogClick = true; if (getMessagesController().checkCanOpenChat(args, DialogsActivity.this)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat != null && chat.forum && topicId == 0 && !NaConfig.INSTANCE.getShowForumAsNormalChat().Bool()) { + TLRPC.Dialog dialog = getMessagesController().getDialog(dialogId); + boolean needOpenChatActivity = dialog != null && dialog.view_forum_as_messages; + if (chat != null && chat.forum && topicId == 0) { if (!LiteMode.isEnabled(LiteMode.FLAG_CHAT_FORUM_TWOCOLUMN)) { - presentFragment(new TopicsFragment(args)); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); + } else { + presentFragment(new TopicsFragment(args)); + } } else { if (!canOpenInRightSlidingView) { - presentFragment(new TopicsFragment(args)); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); + } else { + presentFragment(new TopicsFragment(args)); + } } else if (!searching) { - if (rightSlidingDialogContainer.currentFragment != null && ((TopicsFragment) rightSlidingDialogContainer.currentFragment).getDialogId() == dialogId) { - rightSlidingDialogContainer.finishPreview(); + if (needOpenChatActivity) { + presentFragment(new ChatActivity(args)); } else { - viewPages[0].listView.prepareSelectorForAnimation(); - TopicsFragment topicsFragment = new TopicsFragment(args); - topicsFragment.parentDialogsActivity = this; - rightSlidingDialogContainer.presentFragment(getParentLayout(), topicsFragment); + if (rightSlidingDialogContainer.currentFragment != null && ((TopicsFragment) rightSlidingDialogContainer.currentFragment).getDialogId() == dialogId) { + rightSlidingDialogContainer.finishPreview(); + } else { + viewPages[0].listView.prepareSelectorForAnimation(); + TopicsFragment topicsFragment = new TopicsFragment(args); + topicsFragment.parentDialogsActivity = this; + rightSlidingDialogContainer.presentFragment(getParentLayout(), topicsFragment); + } + searchViewPager.updateTabs(); } - searchViewPager.updateTabs(); } } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java index 95feb0bfeb..35fde2f861 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/EmojiAnimationsOverlay.java @@ -797,7 +797,7 @@ private void showStickerSetBulletin(TLRPC.TL_messages_stickerSet stickerSet, Mes 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/GroupCallActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java index b25f4c028b..6c0d0d0a87 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java @@ -121,8 +121,6 @@ import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BlobDrawable; -import org.telegram.ui.Components.Bulletin; -import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CheckBoxSquare; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextBoldCursor; @@ -7037,7 +7035,7 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, lo imageView.setRoundRadius(AndroidUtilities.dp(20)); frameLayout.addView(imageView, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 22, 5, 22, 0)); - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); String name; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index c8ac956a0c..0d4206c3fd 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 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } 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 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } 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 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } 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 int getItemCount() { 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 void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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 void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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 int getItemViewType(int i) { } 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 b5140c83f4..640de93dfe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -174,6 +174,7 @@ 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; @@ -285,16 +286,25 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati private List overlayPasscodeViews = new ArrayList<>(); private TermsOfServiceView termsOfServiceView; private BlockingUpdateView blockingUpdateView; - private AlertDialog visibleDialog; - private AlertDialog proxyErrorDialog; + public final ArrayList visibleDialogs = new ArrayList<>(); + private Dialog proxyErrorDialog; private RecyclerListView sideMenu; private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; private SideMenultItemAnimator itemAnimator; 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 AlertDialog localeDialog; + private Dialog localeDialog; private boolean loadingLocaleDialog; private HashMap systemLocaleStrings; private HashMap englishLocaleStrings; @@ -1013,6 +1023,7 @@ private void showAttachMenuBot(TLRPC.TL_attachMenuBot attachMenuBot, String star 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); webViewSheet.show(); + visibleDialogs.add(webViewSheet); } @Override @@ -1270,9 +1281,7 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } ((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) : @@ -1290,8 +1299,8 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } } }; - 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); @@ -1718,6 +1727,9 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool if (GiftInfoBottomSheet.handleIntent(intent, progress)) { return true; } + if (UserSelectorBottomSheet.handleIntent(intent, progress)) { + return true; + } if (AndroidUtilities.handleProxyIntent(this, intent)) { return true; } @@ -3375,10 +3387,10 @@ public boolean shouldShowNextButton(DialogsActivity dialogsFragment, ArrayList arrayList) { + private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, int messageId, TLRPC.TL_forumTopic forumTopic, Runnable whenDone, String quote, int fromMessageId, ArrayList arrayList, int quoteOffset) { if (forumTopic == null) { forumTopic = MessagesController.getInstance(intentAccount).getTopicsController().findTopic(chat.id, topicId); } @@ -3466,7 +3478,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i MessagesController.getInstance(intentAccount).getTopicsController().processTopics(chat.id, topics.topics, messagesMap, false, TopicsController.LOAD_TYPE_LOAD_UNKNOWN, -1); TLRPC.TL_forumTopic topic = MessagesController.getInstance(intentAccount).getTopicsController().findTopic(chat.id, topicId); - openTopicRequest(intentAccount, topicId, chat, messageId, topic, whenDone, quote, fromMessageId, arrayList); + openTopicRequest(intentAccount, topicId, chat, messageId, topic, whenDone, quote, fromMessageId, arrayList, quoteOffset); }; })); return; @@ -3474,7 +3486,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i BaseFragment lastFragment = !mainFragmentsStack.isEmpty() ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; if (lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == -chat.id && ((ChatActivity) lastFragment).isTopic && ((ChatActivity) lastFragment).getTopicId() == forumTopic.id) { if (quote != null) { - ((ChatActivity) lastFragment).setHighlightQuote(messageId, quote); + ((ChatActivity) lastFragment).setHighlightQuote(messageId, quote, quoteOffset); } ((ChatActivity) lastFragment).scrollToMessageId(messageId, fromMessageId, true, 0, true, 0, null); } else { @@ -3493,7 +3505,7 @@ private void openTopicRequest(int intentAccount, int topicId, TLRPC.Chat chat, i chatActivity.setThreadMessages(arrayList, chat, messageId, forumTopic.read_inbox_max_id, forumTopic.read_outbox_max_id, forumTopic); if (messageId != forumTopic.id) { if (quote != null) { - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); } else { chatActivity.setHighlightMessageId(messageId); } @@ -3641,7 +3653,7 @@ private void openGroupCall(AccountInstance accountInstance, TLRPC.Chat chat, Str VoIPHelper.startCall(chat, null, hash, false, this, mainFragmentsStack.get(mainFragmentsStack.size() - 1), accountInstance); } - public void openMessage(long dialogId, int messageId, String quote, final Browser.Progress progress, int fromMessageId) { + public void openMessage(long dialogId, int messageId, String quote, final Browser.Progress progress, int fromMessageId, final int quoteOffset) { if (dialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); if (chat != null && ChatObject.isForum(chat)) { @@ -3652,7 +3664,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } } @@ -3669,7 +3681,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (progress != null) { progress.end(); } - }, fromMessageId); + }, fromMessageId, quoteOffset); return; } args.putLong("chat_id", -dialogId); @@ -3679,7 +3691,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse if (lastFragment == null || MessagesController.getInstance(currentAccount).checkCanOpenChat(args, lastFragment)) { AndroidUtilities.runOnUIThread(() -> { ChatActivity chatActivity = new ChatActivity(args); - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); if (!(AndroidUtilities.isTablet() ? rightActionBarLayout : getActionBarLayout()).presentFragment(chatActivity) && dialogId < 0) { TLRPC.TL_channels_getChannels req = new TLRPC.TL_channels_getChannels(); TLRPC.TL_inputChannel inputChannel = new TLRPC.TL_inputChannel(); @@ -3701,7 +3713,7 @@ public void openMessage(long dialogId, int messageId, String quote, final Browse } if (lastFragment == null || MessagesController.getInstance(currentAccount).checkCanOpenChat(args, lastFragment)) { ChatActivity chatActivity2 = new ChatActivity(args); - chatActivity.setHighlightQuote(messageId, quote); + chatActivity.setHighlightQuote(messageId, quote, quoteOffset); getActionBarLayout().presentFragment(chatActivity2); } } @@ -3965,7 +3977,7 @@ private void runLinkRequest(final int intentAccount, } }), 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); @@ -3983,15 +3995,15 @@ private void runLinkRequest(final int intentAccount, } }), 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; } @@ -4290,7 +4302,7 @@ public void didChangeOwner(TLRPC.User user) { } else { Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialog_id); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); try { dismissLoading.run(); } catch (Exception e) { @@ -4426,7 +4438,7 @@ public void onError() { if (invite.chat.forum) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", invite.chat.id); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); } else { MessagesController.getInstance(intentAccount).ensureMessagesLoaded(-invite.chat.id, 0, new MessagesController.MessagesLoadedCallback() { @Override @@ -4979,7 +4991,7 @@ private void processWebAppBot(final int intentAccount, 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(); @@ -5004,12 +5016,15 @@ private void processWebAppBot(final int intentAccount, 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); sheet.show(); + 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); @@ -5140,6 +5155,16 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM if (!attachMenuBot.inactive) { if (dialogsActivity != null) { + if (lastFragment != null) { + lastFragment.dismissCurrentDialog(); + } + 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; @@ -5167,6 +5192,16 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM if (response2 instanceof TLRPC.TL_boolTrue) { MediaDataController.getInstance(intentAccount).loadAttachMenuBots(false, true, () -> { if (dialogsActivity != null) { + if (lastFragment != null) { + lastFragment.dismissCurrentDialog(); + } + 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); @@ -5183,14 +5218,14 @@ private void processAttachMenuBot(int intentAccount, long peerId, String attachM } private void openForumFromLink(long dialogId, Integer messageId, Runnable onOpened) { - openForumFromLink(dialogId, messageId, null, onOpened, 0); + openForumFromLink(dialogId, messageId, null, onOpened, 0, -1); } - private void openForumFromLink(long dialogId, Integer messageId, String quote, Runnable onOpened, int fromMessageId) { + private void openForumFromLink(long dialogId, Integer messageId, String quote, Runnable onOpened, int fromMessageId, int quoteOffset) { if (messageId == null) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialogId); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); if (onOpened != null) { onOpened.run(); @@ -5214,13 +5249,13 @@ private void openForumFromLink(long dialogId, Integer messageId, String quote, R } if (message != null) { - runCommentRequest(currentAccount, null, message.id, null, MessageObject.getTopicId(message, MessagesController.getInstance(currentAccount).isForum(message)), MessagesController.getInstance(currentAccount).getChat(-dialogId), onOpened, quote, fromMessageId); + runCommentRequest(currentAccount, null, message.id, null, MessageObject.getTopicId(message, MessagesController.getInstance(currentAccount).isForum(message)), MessagesController.getInstance(currentAccount).getChat(-dialogId), onOpened, quote, fromMessageId, quoteOffset); return; } Bundle bundle = new Bundle(); bundle.putLong("chat_id", -dialogId); - presentFragment(new TopicsFragment(bundle)); + presentFragment(TopicsFragment.getTopicsOrChat(this, bundle)); if (onOpened != null) { onOpened.run(); @@ -5345,21 +5380,13 @@ public void checkAppUpdate(boolean force) { })); } - public AlertDialog showAlertDialog(AlertDialog.Builder builder) { - try { - if (visibleDialog != null) { - visibleDialog.dismiss(); - visibleDialog = null; - } - } catch (Exception e) { - FileLog.e(e); - } + public Dialog showAlertDialog(AlertDialog.Builder builder) { 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; @@ -5378,15 +5405,16 @@ public AlertDialog showAlertDialog(AlertDialog.Builder builder) { FileLog.e(e); } localeDialog = null; - } else if (visibleDialog == proxyErrorDialog) { + } else if (dialog == proxyErrorDialog) { SharedConfig.setProxyEnable(false); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); proxyErrorDialog = null; } } - visibleDialog = null; + visibleDialogs.remove(dialog); }); - return visibleDialog; + visibleDialogs.add(dialog); + return dialog; } catch (Exception e) { FileLog.e(e); } @@ -5995,10 +6023,13 @@ protected void onDestroy() { 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); } @@ -6974,10 +7005,13 @@ private void showLanguageAlertInternal(LocaleController.LocaleInfo systemInfo, L 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/LiteModeSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LiteModeSettingsActivity.java index 1764383f93..2dca64a3ad 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.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 @@ private void updateItems() { 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 @@ private int preprocessFlagsCount(int flags) { 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/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 9255f8729b..c52e3ef582 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -1521,9 +1521,9 @@ private Bitmap createUserBitmap(LiveLocation liveLocation) { } else { AvatarDrawable avatarDrawable = new AvatarDrawable(); if (liveLocation.user != null) { - avatarDrawable.setInfo(liveLocation.user); + avatarDrawable.setInfo(currentAccount, liveLocation.user); } else if (liveLocation.chat != null) { - avatarDrawable.setInfo(liveLocation.chat); + avatarDrawable.setInfo(currentAccount, liveLocation.chat); } canvas.translate(AndroidUtilities.dp(6), AndroidUtilities.dp(6)); avatarDrawable.setBounds(0, 0, AndroidUtilities.dp(50), AndroidUtilities.dp(50)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java index c7adda3a63..7f172e396f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java @@ -1,19 +1,11 @@ package org.telegram.ui; import android.content.Context; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; -import android.text.style.DynamicDrawableSpan; -import android.text.style.ImageSpan; -import android.util.Log; import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; @@ -25,7 +17,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -40,13 +31,11 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; -import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.AvatarsImageView; @@ -412,7 +401,7 @@ public void setUser(TLObject object, int date) { updateStatus(false); if (object != null) { - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); ImageLocation imageLocation = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); avatarImageView.setImage(imageLocation, "50_50", avatarDrawable, object); nameView.setText(ContactsController.formatName(object)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java index 72f551ccbb..f098e8653e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -18,11 +18,10 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -31,6 +30,7 @@ import android.widget.Toast; import androidx.collection.ArraySet; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; @@ -55,14 +55,15 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.EmptyCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LoadingCell; @@ -72,12 +73,15 @@ import org.telegram.ui.Charts.data.ChartData; import org.telegram.ui.Charts.data.StackLinearChartData; import org.telegram.ui.Charts.view_data.ChartHeaderView; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Stories.StoriesListPlaceProvider; +import org.telegram.ui.Stories.StoriesUtilities; import java.util.ArrayList; @@ -93,19 +97,22 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati private MessageObject messageObject; private StatisticActivity.ChartViewData interactionsViewData; + private StatisticActivity.ChartViewData reactionsByEmotionData; private LruCache childDataCache = new LruCache<>(15); private StatisticActivity.ZoomCancelable lastCancelable; - private ArrayList messages = new ArrayList<>(); + private ArrayList messages = new ArrayList<>(); private boolean statsLoaded; private boolean loading; private boolean firstLoaded; + private String nextOffset = null; private int headerRow; private int startRow; private int endRow; private int loadingRow; private int interactionsChartRow; + private int reactionsByEmotionChartRow; private int overviewRow; private int overviewHeaderRow; private int emptyRow; @@ -116,12 +123,12 @@ public class MessageStatisticActivity extends BaseFragment implements Notificati private RLottieImageView imageView; private LinearLayout progressLayout; - private int nextRate; private int publicChats; private boolean endReached; ImageReceiver thumbImage; boolean drawPlay; + boolean hasThumb; private final Runnable showProgressbar = new Runnable() { @Override @@ -132,6 +139,8 @@ public void run() { private FrameLayout listContainer; private ChatAvatarContainer avatarContainer; private BaseChartView.SharedUiComponents sharedUi; + private boolean needActionbarMenu; + private StatisticActivity.RecentPostInfo recentPostInfo; public MessageStatisticActivity(MessageObject message) { messageObject = message; @@ -146,6 +155,19 @@ public MessageStatisticActivity(MessageObject message) { this.chat = getMessagesController().getChatFull(chatId); } + public MessageStatisticActivity(StatisticActivity.RecentPostInfo recentPostInfo, long chatId, boolean needActionbarMenu) { + this(recentPostInfo.message, chatId, needActionbarMenu); + this.recentPostInfo = recentPostInfo; + } + + public MessageStatisticActivity(MessageObject message, long chatId, boolean needActionbarMenu) { + messageObject = message; + messageId = 0; + this.chatId = chatId; + this.chat = getMessagesController().getChatFull(chatId); + this.needActionbarMenu = needActionbarMenu; + } + private void updateRows() { shadowDivideCells.clear(); headerRow = -1; @@ -153,6 +175,7 @@ private void updateRows() { endRow = -1; loadingRow = -1; interactionsChartRow = -1; + reactionsByEmotionChartRow = -1; overviewHeaderRow = -1; overviewRow = -1; @@ -178,6 +201,10 @@ public void onAnimationEnd(Animator animation) { interactionsChartRow = rowCount++; shadowDivideCells.add(rowCount++); } + if (reactionsByEmotionData != null) { + reactionsByEmotionChartRow = rowCount++; + shadowDivideCells.add(rowCount++); + } if (!messages.isEmpty()) { headerRow = rowCount++; @@ -220,12 +247,8 @@ public void onFragmentDestroy() { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.chatInfoDidLoad) { TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; - if (chat == null && chatFull.id == chatId) { - TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); - if (chatLocal != null) { - avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); - } + if (chat == null && chatFull.id == chatId) { + setAvatarAndTitle(); chat = chatFull; loadStat(); loadChats(100); @@ -234,12 +257,23 @@ public void didReceivedNotification(int id, int account, Object... args) { } } + private boolean checkIsDeletedStory(MessageObject message) { + if (message == null || !message.isStory()) { + return false; + } + if (message.storyItem instanceof TL_stories.TL_storyItemDeleted) { + BulletinFactory.of(this).createSimpleBulletin(R.raw.story_bomb1, LocaleController.getString("StoryNotFound", R.string.StoryNotFound)).show(); + return true; + } + return false; + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); fragmentView = new FrameLayout(context); - fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider())); FrameLayout frameLayout = (FrameLayout) fragmentView; emptyView = new EmptyTextProgressView(context); @@ -257,14 +291,14 @@ public View createView(Context context) { TextView loadingTitle = new TextView(context); loadingTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); loadingTitle.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); + loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider())); loadingTitle.setTag(Theme.key_player_actionBarTitle); loadingTitle.setText(LocaleController.getString("LoadingStats", R.string.LoadingStats)); loadingTitle.setGravity(Gravity.CENTER_HORIZONTAL); TextView loadingSubtitle = new TextView(context); loadingSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); loadingSubtitle.setTag(Theme.key_player_actionBarSubtitle); loadingSubtitle.setText(LocaleController.getString("LoadingStatsDescription", R.string.LoadingStatsDescription)); loadingSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); @@ -276,7 +310,7 @@ public View createView(Context context) { frameLayout.addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); - listView = new RecyclerListView(context); + listView = new RecyclerListView(context, getResourceProvider()); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); ((SimpleItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); listView.setAdapter(listViewAdapter = new ListAdapter(context)); @@ -284,21 +318,69 @@ public View createView(Context context) { listView.setOnItemClickListener((view, position) -> { if (position >= startRow && position < endRow) { - TLRPC.Message message = messages.get(position - startRow); - long did = MessageObject.getDialogId(message); + MessageObject message = messages.get(position - startRow); + if (message.isStory()) { + if (checkIsDeletedStory(message)) { + return; + } + getOrCreateStoryViewer().open(getContext(), message.storyItem, StoriesListPlaceProvider.of(listView)); + return; + } + long did = MessageObject.getDialogId(message.messageOwner); Bundle args = new Bundle(); if (DialogObject.isUserDialog(did)) { args.putLong("user_id", did); } else { args.putLong("chat_id", -did); } - args.putInt("message_id", message.id); + args.putInt("message_id", message.getId()); args.putBoolean("need_remove_previous_same_chat_activity", false); if (getMessagesController().checkCanOpenChat(args, this)) { presentFragment(new ChatActivity(args)); } } }); + listView.setOnItemLongClickListener((view, position) -> { + if (position >= startRow && position < endRow) { + try { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) {} + MessageObject message = messages.get(position - startRow); + final long did = MessageObject.getDialogId(message.messageOwner); + final boolean isDialog = DialogObject.isUserDialog(did); + final ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + final ArrayList icons = new ArrayList<>(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), getResourceProvider()); + if (message.isStory()) { + items.add(isDialog ? LocaleController.getString("OpenProfile", R.string.OpenProfile) : LocaleController.getString("OpenChannel2", R.string.OpenChannel2)); + icons.add(isDialog ? R.drawable.msg_openprofile : R.drawable.msg_channel); + } else { + items.add(LocaleController.getString("ViewMessage", R.string.ViewMessage)); + icons.add(R.drawable.msg_msgbubble3); + } + actions.add(0); + builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { + if (message.isStory()) { + presentFragment(isDialog ? ProfileActivity.of(did) : ChatActivity.of(did)); + } else { + Bundle args = new Bundle(); + if (isDialog) { + args.putLong("user_id", did); + } else { + args.putLong("chat_id", -did); + } + args.putInt("message_id", message.getId()); + args.putBoolean("need_remove_previous_same_chat_activity", false); + if (getMessagesController().checkCanOpenChat(args, this)) { + presentFragment(new ChatActivity(args)); + } + } + }); + showDialog(builder.create()); + } + return false; + }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -335,8 +417,19 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - thumbImage.setImageCoords(avatarContainer.getSubtitleTextView().getX(), avatarContainer.getSubtitleTextView().getY(), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); - thumbImage.draw(canvas); + thumbImage.setImageCoords( + avatarContainer.getAvatarImageView().getX(), + avatarContainer.getAvatarImageView().getY(), + avatarContainer.getAvatarImageView().getWidth(), + avatarContainer.getAvatarImageView().getHeight()); + + if (hasThumb) { + canvas.save(); + canvas.scale(0.9f, 0.9f, thumbImage.getCenterX(), thumbImage.getCenterY()); + thumbImage.draw(canvas); + canvas.restore(); + } + if (drawPlay) { int x = (int) (thumbImage.getCenterX() - Theme.dialogs_playDrawable.getIntrinsicWidth() / 2); int y = (int) (thumbImage.getCenterY() - Theme.dialogs_playDrawable.getIntrinsicHeight() / 2); @@ -360,64 +453,66 @@ protected void onDetachedFromWindow() { thumbImage = new ImageReceiver(); thumbImage.setParentView(avatarContainer); - thumbImage.setRoundRadius(AndroidUtilities.dp(2)); - actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); - - TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); - if (chatLocal != null) { - avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); - } - - boolean hasThumb = false; - - if (!messageObject.needDrawBluredPreview() && (messageObject.isPhoto() || messageObject.isNewGif() || messageObject.isVideo())) { - String type = messageObject.isWebpage() ? messageObject.messageOwner.media.webpage.type : null; - if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { - TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); - TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - if (smallThumb == bigThumb) { - bigThumb = null; - } - if (smallThumb != null) { - hasThumb = true; - drawPlay = messageObject.isVideo(); - String fileName = FileLoader.getAttachFileName(bigThumb); - if (messageObject.mediaExists || DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { - int size; - if (messageObject.type == MessageObject.TYPE_PHOTO) { - size = bigThumb != null ? bigThumb.size : 0; + thumbImage.setRoundRadius(AndroidUtilities.dp(9)); + + hasThumb = false; + if (!messageObject.isStory()) { + if (!messageObject.needDrawBluredPreview() && (messageObject.isPhoto() || messageObject.isNewGif() || messageObject.isVideo())) { + String type = messageObject.isWebpage() ? messageObject.messageOwner.media.webpage.type : null; + if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { + TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); + TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + if (smallThumb == bigThumb) { + bigThumb = null; + } + if (smallThumb != null) { + hasThumb = true; + drawPlay = messageObject.isVideo(); + String fileName = FileLoader.getAttachFileName(bigThumb); + if (messageObject.mediaExists || DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + int size; + if (messageObject.type == MessageObject.TYPE_PHOTO) { + size = bigThumb != null ? bigThumb.size : 0; + } else { + size = 0; + } + thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "50_50", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "50_50", size, null, messageObject, 0); } else { - size = 0; + thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "50_50", (Drawable) null, messageObject, 0); } - thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", size, null, messageObject, 0); - } else { - thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", (Drawable) null, messageObject, 0); } } } - } - CharSequence message; - if (!TextUtils.isEmpty(messageObject.caption)) { - message = messageObject.caption; - } else if (!TextUtils.isEmpty(messageObject.messageOwner.message)) { - message = messageObject.messageText; - if (message.length() > 150) { - message = message.subSequence(0, 150); + CharSequence message; + if (!TextUtils.isEmpty(messageObject.caption)) { + message = messageObject.caption; + } else if (!TextUtils.isEmpty(messageObject.messageOwner.message)) { + message = messageObject.messageText; + if (message.length() > 150) { + message = message.subSequence(0, 150); + } + message = Emoji.replaceEmoji(message, avatarContainer.getSubtitleTextView().getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); + } else { + message = messageObject.messageText; + } + + if (messageObject.isVideo() || messageObject.isPhoto()) { + avatarContainer.hideSubtitle(); + } else { + avatarContainer.setSubtitle(message); } - } else { - message = messageObject.messageText; } - if (hasThumb) { - SpannableStringBuilder builder = new SpannableStringBuilder(message); - builder.insert(0, " "); - builder.setSpan(new DialogCell.FixedWidthSpan(AndroidUtilities.dp(18 + 6)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - avatarContainer.setSubtitle(builder); - } else { - avatarContainer.setSubtitle(messageObject.messageText); + int avatarContainerMarginLeft = 56; + if (hasThumb || messageObject.isStory()) { + avatarContainer.setRightAvatarPadding(-AndroidUtilities.dp(3)); + avatarContainerMarginLeft = 50; } + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? avatarContainerMarginLeft : 0, 0, 40, 0)); + + setAvatarAndTitle(); + actionBar.setBackButtonDrawable(new BackDrawable(false)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -426,26 +521,25 @@ public void onItemClick(final int id) { finishFragment(); } else if (id == 1) { Bundle args = new Bundle(); - if (messageObject.messageOwner.fwd_from == null) { - args.putLong("chat_id", messageObject.getChatId()); - } else { - args.putLong("chat_id", -messageObject.getFromChatId()); - } + args.putLong("chat_id", chatId); presentFragment(new StatisticActivity(args)); } } }); - avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle), Theme.getColor(Theme.key_player_actionBarSubtitle)); - avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), false); - actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); - actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider()), Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); + actionBar.setItemsColor(Theme.getColor(Theme.key_player_actionBarTitle, getResourceProvider()), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector, getResourceProvider()), false); + actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); avatarContainer.setOnClickListener(view -> { + if (messageObject.isStory()) { + return; + } if (getParentLayout().getFragmentStack().size() > 1) { BaseFragment previousFragemnt = getParentLayout().getFragmentStack().get(getParentLayout().getFragmentStack().size() - 2); - if (previousFragemnt instanceof ChatActivity && ((ChatActivity) previousFragemnt).getCurrentChat().id == chatId) { + if (previousFragemnt instanceof ChatActivity && ((ChatActivity) previousFragemnt).getCurrentChat().id == chatId) { finishFragment(); return; } @@ -462,7 +556,35 @@ public void onItemClick(final int id) { return fragmentView; } + private void setAvatarAndTitle() { + if (messageObject.isStory()) { + avatarContainer.setTitle(LocaleController.getString("StoryStatistics", R.string.StoryStatistics)); + avatarContainer.hideSubtitle(); + avatarContainer.allowDrawStories = true; + avatarContainer.setStoriesForceState(StoriesUtilities.STATE_HAS_UNREAD); + if (messageObject.photoThumbs != null) { + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + TLRPC.PhotoSize thumbSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 50); + avatarContainer.getAvatarImageView().setImage( + ImageLocation.getForObject(size, messageObject.photoThumbsObject), "50_50", + ImageLocation.getForObject(thumbSize, messageObject.photoThumbsObject), "b1", 0, messageObject); + avatarContainer.setClipChildren(false); + avatarContainer.getAvatarImageView().setScaleX(0.96f); + avatarContainer.getAvatarImageView().setScaleY(0.96f); + } + } else { + avatarContainer.setTitle(LocaleController.getString("PostStatistics", R.string.PostStatistics)); + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); + if (chatLocal != null && !hasThumb) { + avatarContainer.setChatAvatar(chatLocal); + } + } + } + private void updateMenu() { + if (!needActionbarMenu) { + return; + } if (chat != null && chat.can_view_stats) { ActionBarMenu menu = actionBar.createMenu(); menu.clearItems(); @@ -479,6 +601,54 @@ private void loadChats(int count) { if (listViewAdapter != null) { listViewAdapter.notifyDataSetChanged(); } + if (messageObject.isStory()) { + TLRPC.TL_stats_getStoryPublicForwards req = new TLRPC.TL_stats_getStoryPublicForwards(); + req.limit = count; + req.id = messageObject.storyItem.id; + req.peer = getMessagesController().getInputPeer(-chatId); + req.offset = nextOffset == null ? "" : nextOffset; + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.TL_stats_publicForwards res = (TLRPC.TL_stats_publicForwards) response; + if ((res.flags & 1) != 0) { + nextOffset = res.next_offset; + } else { + nextOffset = null; + } + if (res.count != 0) { + publicChats = res.count; + } else if (publicChats == 0) { + publicChats = res.forwards.size(); + } + endReached = nextOffset == null; + getMessagesController().putChats(res.chats, false); + getMessagesController().putUsers(res.users, false); + + for (TLRPC.PublicForward forward : res.forwards) { + if (forward instanceof TL_stories.TL_publicForwardStory) { + TL_stories.TL_publicForwardStory forwardStory = (TL_stories.TL_publicForwardStory) forward; + forwardStory.story.dialogId = DialogObject.getPeerDialogId(forwardStory.peer); + forwardStory.story.messageId = forwardStory.story.id; + MessageObject msg = new MessageObject(currentAccount, forwardStory.story); + msg.generateThumbs(false); + messages.add(msg); + } else if (forward instanceof TLRPC.TL_publicForwardMessage) { + TLRPC.TL_publicForwardMessage forwardMessage = (TLRPC.TL_publicForwardMessage) forward; + messages.add(new MessageObject(currentAccount, forwardMessage.message, false, true)); + } + } + + if (emptyView != null) { + emptyView.showTextView(); + } + } + firstLoaded = true; + loading = false; + updateRows(); + }), null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + return; + } TLRPC.TL_stats_getMessagePublicForwards req = new TLRPC.TL_stats_getMessagePublicForwards(); req.limit = count; if (messageObject.messageOwner.fwd_from != null) { @@ -488,29 +658,38 @@ private void loadChats(int count) { req.msg_id = messageObject.getId(); req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); } - if (!messages.isEmpty()) { - TLRPC.Message message = messages.get(messages.size() - 1); - 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); - messages.addAll(res.messages); + + 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(); } @@ -523,22 +702,45 @@ private void loadChats(int count) { } private void loadStat() { - TLRPC.TL_stats_getMessageStats req = new TLRPC.TL_stats_getMessageStats(); - if (messageObject.messageOwner.fwd_from != null) { - req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; - req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + TLObject reqObject; + if (messageObject.isStory()) { + TL_stories.TL_stats_getStoryStats req = new TL_stories.TL_stats_getStoryStats(); + req.id = messageObject.storyItem.id; + req.peer = getMessagesController().getInputPeer(-chatId); + reqObject = req; } else { - req.msg_id = messageObject.getId(); - req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); + TLRPC.TL_stats_getMessageStats req = new TLRPC.TL_stats_getMessageStats(); + if (messageObject.messageOwner.fwd_from != null) { + req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; + req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + } else { + req.msg_id = messageObject.getId(); + req.channel = getMessagesController().getInputChannel(-messageObject.getDialogId()); + } + reqObject = req; } - getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + + getConnectionsManager().sendRequest(reqObject, (response, error) -> AndroidUtilities.runOnUIThread(() -> { statsLoaded = true; if (error != null) { updateRows(); return; } - TLRPC.TL_stats_messageStats res = (TLRPC.TL_stats_messageStats) response; - interactionsViewData = StatisticActivity.createViewData(res.views_graph, LocaleController.getString("InteractionsChartTitle", R.string.InteractionsChartTitle), 1, false); + + TLRPC.StatsGraph views_graph; + TLRPC.StatsGraph reactions_by_emotion_graph; + if (response instanceof TL_stories.TL_stats_storyStats) { + TL_stories.TL_stats_storyStats res = (TL_stories.TL_stats_storyStats) response; + views_graph = res.views_graph; + reactions_by_emotion_graph = res.reactions_by_emotion_graph; + } else { + TLRPC.TL_stats_messageStats res = (TLRPC.TL_stats_messageStats) response; + views_graph = res.views_graph; + reactions_by_emotion_graph = res.reactions_by_emotion_graph; + } + + interactionsViewData = StatisticActivity.createViewData(views_graph, LocaleController.getString("ViewsAndSharesChartTitle", R.string.ViewsAndSharesChartTitle), 1, false); + reactionsByEmotionData = StatisticActivity.createViewData(reactions_by_emotion_graph, LocaleController.getString("ReactionsByEmotionChartTitle", R.string.ReactionsByEmotionChartTitle), 2, false); if (interactionsViewData != null && interactionsViewData.chartData.x.length <= 5) { statsLoaded = false; TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); @@ -621,20 +823,23 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType View view; switch (viewType) { case 0: - view = new ManageChatUserCell(mContext, 6, 2, false); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + ManageChatUserCell cell = new ManageChatUserCell(mContext, 6, 2, false, getResourceProvider()); + cell.setDividerColor(Theme.key_divider); + view = cell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 1: - view = new ShadowSectionCell(mContext); + view = new ShadowSectionCell(mContext, getResourceProvider()); break; case 2: - HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 16, 11, false); - headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlackText, 16, 11, false, getResourceProvider()); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); headerCell.setHeight(43); view = headerCell; break; case 4: - view = new StatisticActivity.BaseChartCell(mContext, 1, sharedUi = new BaseChartView.SharedUiComponents()) { + case 7: + view = new StatisticActivity.BaseChartCell(mContext, viewType == 4 ? 1 : 2, sharedUi = new BaseChartView.SharedUiComponents(getResourceProvider()), getResourceProvider()) { @Override public void onZoomed() { @@ -728,17 +933,17 @@ void loadData(StatisticActivity.ChartViewData viewData) { // viewData.load(currentAccount, classGuid, ); } }; - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 5: view = new OverviewCell(mContext); view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 6: view = new EmptyCell(mContext, 16); view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 16)); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); break; case 3: default: @@ -753,26 +958,38 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 0: ManageChatUserCell userCell = (ManageChatUserCell) holder.itemView; - TLRPC.Message item = getItem(position); - long did = MessageObject.getDialogId(item); + MessageObject item = getItem(position); + long did = MessageObject.getDialogId(item.messageOwner); TLObject object; String status = null; - if (DialogObject.isUserDialog(did)) { - object = getMessagesController().getUser(did); + if (item.isStory()) { + object = DialogObject.isUserDialog(did) ? getMessagesController().getUser(did) : getMessagesController().getChat(-did); + boolean isZeroViews = item.storyItem.views == null || item.storyItem.views.views_count == 0; + status = isZeroViews ? LocaleController.getString("NoViews", R.string.NoViews) : LocaleController.formatPluralString("Views", item.storyItem.views.views_count); + userCell.setData(object, null, status, position != endRow - 1); + userCell.setStoryItem(item.storyItem, v -> { + if (checkIsDeletedStory(item)) { + return; + } + getOrCreateStoryViewer().open(getContext(), item.storyItem, StoriesListPlaceProvider.of(listView)); + }); } else { - object = getMessagesController().getChat(-did); - TLRPC.Chat chat = (TLRPC.Chat) object; - if (chat.participants_count != 0) { + userCell.setStoryItem(null, null); + if (DialogObject.isUserDialog(did)) { + object = getMessagesController().getUser(did); + } else { + object = getMessagesController().getChat(-did); + TLRPC.Chat chat = (TLRPC.Chat) object; if (ChatObject.isChannel(chat) && !chat.megagroup) { - status = LocaleController.formatPluralString("Subscribers", chat.participants_count); - } else { + status = LocaleController.formatPluralString("Views", item.messageOwner.views); + } else if (chat.participants_count != 0) { status = LocaleController.formatPluralString("Members", chat.participants_count); + status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.messageOwner.views)); } - status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.views)); } - } - if (object != null) { - userCell.setData(object, null, status, position != endRow - 1); + if (object != null) { + userCell.setData(object, null, status, position != endRow - 1); + } } break; case 1: @@ -781,9 +998,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { case 2: HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == overviewHeaderRow) { + headerCell.setTopMargin(9); + headerCell.setPadding(0, 0, 0, AndroidUtilities.dp(8)); headerCell.setText(LocaleController.formatString("StatisticOverview", R.string.StatisticOverview)); } else { - headerCell.setText(LocaleController.formatPluralString("PublicSharesCount", publicChats)); + headerCell.setTopMargin(11); + headerCell.setPadding(0, 0, 0, 0); + headerCell.setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); } break; case 4: @@ -795,6 +1016,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { OverviewCell overviewCell = (OverviewCell) holder.itemView; overviewCell.setData(); break; + case 7: + StatisticActivity.BaseChartCell chartCell2 = (StatisticActivity.BaseChartCell) holder.itemView; + chartCell2.updateData(reactionsByEmotionData, false); + chartCell2.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + break; } } @@ -819,11 +1045,13 @@ public int getItemViewType(int position) { return 5; } else if (position == emptyRow) { return 6; + } else if (position == reactionsByEmotionChartRow) { + return 7; } return 0; } - public TLRPC.Message getItem(int position) { + public MessageObject getItem(int position) { if (position >= startRow && position < endRow) { return messages.get(position - startRow); } @@ -833,64 +1061,90 @@ public TLRPC.Message getItem(int position) { public class OverviewCell extends LinearLayout { - TextView[] primary = new TextView[3]; - TextView[] title = new TextView[3]; - View[] cell = new View[3]; + TextView[] primary = new TextView[4]; + TextView[] title = new TextView[4]; public OverviewCell(Context context) { super(context); setOrientation(VERTICAL); setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(16)); - LinearLayout linearLayout = new LinearLayout(context); - linearLayout.setOrientation(HORIZONTAL); + for (int i = 0; i < 2; i++) { + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(HORIZONTAL); - for (int j = 0; j < 3; j++) { - LinearLayout contentCell = new LinearLayout(context); - cell[j] = contentCell; - contentCell.setOrientation(VERTICAL); + for (int j = 0; j < 2; j++) { + LinearLayout contentCell = new LinearLayout(context); + contentCell.setOrientation(VERTICAL); - primary[j] = new TextView(context); - title[j] = new TextView(context); + LinearLayout infoLayout = new LinearLayout(context); + infoLayout.setOrientation(HORIZONTAL); + primary[i * 2 + j] = new TextView(context); + title[i * 2 + j] = new TextView(context); - primary[j].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - primary[j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); - title[j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + primary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); + title[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + title[i * 2 + j].setGravity(Gravity.LEFT); - contentCell.addView(primary[j]); - contentCell.addView(title[j]); - linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); + infoLayout.addView(primary[i * 2 + j]); + + contentCell.addView(infoLayout); + contentCell.addView(title[i * 2 + j]); + linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); + } + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, i == 0 ? 16 : 0)); } - addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } public void setData() { - primary[0].setText(AndroidUtilities.formatWholeNumber(messageObject.messageOwner.views, 0)); - title[0].setText(LocaleController.getString("StatisticViews", R.string.StatisticViews)); - - if (publicChats > 0) { - cell[1].setVisibility(View.VISIBLE); - primary[1].setText(AndroidUtilities.formatWholeNumber(publicChats, 0)); - title[1].setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); + int views; + int forwards; + int reactions; + + if (recentPostInfo != null) { + views = recentPostInfo.getViews(); + forwards = recentPostInfo.getForwards(); + reactions = recentPostInfo.getReactions(); } else { - cell[1].setVisibility(View.GONE); + views = messageObject.isStory() ? messageObject.storyItem.views.views_count : messageObject.messageOwner.views; + forwards = messageObject.isStory() ? messageObject.storyItem.views.forwards_count : messageObject.messageOwner.forwards; + reactions = 0; + if (messageObject.isStory()) { + reactions = messageObject.storyItem.views.reactions_count; + } else { + if (messageObject.messageOwner.reactions != null) { + for (int i = 0; i < messageObject.messageOwner.reactions.results.size(); i++) { + reactions += messageObject.messageOwner.reactions.results.get(i).count; + } + } + } } - int privateChats = messageObject.messageOwner.forwards - publicChats; - if (privateChats > 0) { - cell[2].setVisibility(View.VISIBLE); - primary[2].setText(AndroidUtilities.formatWholeNumber(privateChats, 0)); - title[2].setText(LocaleController.formatString("PrivateShares", R.string.PrivateShares)); - } else { - cell[2].setVisibility(View.GONE); + primary[0].setText(AndroidUtilities.formatWholeNumber(views, 0)); + title[0].setText(LocaleController.getString("StatisticViews", R.string.StatisticViews)); + + primary[1].setText(AndroidUtilities.formatWholeNumber(publicChats, 0)); + title[1].setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); + + primary[2].setText(AndroidUtilities.formatWholeNumber(reactions, 0)); + title[2].setText(LocaleController.formatString("Reactions", R.string.Reactions)); + + boolean isReactionsNotVisible = chat != null && chat.available_reactions instanceof TLRPC.TL_chatReactionsNone && reactions == 0; + if (isReactionsNotVisible) { + ((ViewGroup) title[2].getParent()).setVisibility(GONE); } + int privateChats = Math.max(0, forwards - publicChats); + primary[3].setText(AndroidUtilities.formatWholeNumber(privateChats, 0)); + title[3].setText(LocaleController.formatString("PrivateShares", R.string.PrivateShares)); + updateColors(); } private void updateColors() { - for (int i = 0; i < 3; i++) { - primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + for (int i = 0; i < 4; i++) { + primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, getResourceProvider())); + title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, getResourceProvider())); } } } @@ -923,7 +1177,7 @@ public ArrayList getThemeDescriptions() { sharedUi.invalidate(); } - avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle, getResourceProvider())); }; themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); @@ -959,6 +1213,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_actionBarDefaultSubmenuItemIcon)); StatisticActivity.putColorFromData(interactionsViewData, themeDescriptions, cellDelegate); + StatisticActivity.putColorFromData(reactionsByEmotionData, themeDescriptions, cellDelegate); return themeDescriptions; } @@ -967,10 +1222,10 @@ private void recolorRecyclerItem(View child) { ((ManageChatUserCell) child).update(0); } else if (child instanceof StatisticActivity.BaseChartCell) { ((StatisticActivity.BaseChartCell) child).recolor(); - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } else if (child instanceof ShadowSectionCell) { Drawable shadowDrawable = Theme.getThemedDrawableByKey(ApplicationLoader.applicationContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); - Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray, getResourceProvider())); CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); combinedDrawable.setFullsize(true); child.setBackground(combinedDrawable); @@ -978,10 +1233,16 @@ private void recolorRecyclerItem(View child) { ((ChartHeaderView) child).recolor(); } else if (child instanceof OverviewCell) { ((OverviewCell) child).updateColors(); - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } if (child instanceof EmptyCell) { - child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider())); } } + + @Override + public boolean isLightStatusBar() { + int color = Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider()); + return ColorUtils.calculateLuminance(color) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MultiContactsSelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/MultiContactsSelectorBottomSheet.java new file mode 100644 index 0000000000..9bcf578729 --- /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/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java index fc9795c1ef..710b4c2d78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java @@ -1,65 +1,86 @@ package org.telegram.ui; -import static android.content.DialogInterface.BUTTON_NEGATIVE; import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; -import static org.telegram.messenger.AndroidUtilities.getPath; -import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR; -import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.Drawable; -import android.icu.util.Measure; import android.os.Build; import android.os.Bundle; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.util.Log; +import android.text.TextUtils; +import android.text.style.ReplacementSpan; +import android.util.SparseIntArray; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import 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.FileLog; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.ThemePreviewMessagesCell; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AvatarDrawable; @@ -68,17 +89,27 @@ import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Easings; +import org.telegram.ui.Components.FilledTabsView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.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; import org.telegram.ui.Stories.recorder.ButtonWithCounterView; +import java.io.File; import java.util.ArrayList; import java.util.List; import xyz.nextalone.nagram.NaConfig; +import xyz.nextalone.nagram.helper.PeerColorHelper; public class PeerColorActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -86,39 +117,745 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente private final long dialogId; private FrameLayout contentView; - private RecyclerListView listView; - private RecyclerView.Adapter listAdapter; - private FrameLayout buttonContainer; - private ButtonWithCounterView button; - private PeerColorGrid peerColorPicker; - - private int selectedColor; - private long selectedEmoji; - private ThemePreviewMessagesCell messagesCellPreview; - private SetReplyIconCell setReplyIconCell; - - private CharSequence buttonLocked, buttonUnlocked; - - int previewRow; - int colorPickerRow; - int infoRow; - int iconRow; - int info2Row; - int buttonRow; - - int rowCount; - - private static final int VIEW_TYPE_MESSAGE = 0; - private static final int VIEW_TYPE_COLOR_PICKER = 1; - private static final int VIEW_TYPE_INFO = 2; - private static final int VIEW_TYPE_ICON = 3; - private static final int VIEW_TYPE_BUTTONPAD = 5; + private ColoredActionBar colorBar; + + public static final int PAGE_NAME = 0; + public static final int PAGE_PROFILE = 1; + + public Page namePage; + public Page profilePage; + + public Page getCurrentPage() { + return viewPager.getCurrentPosition() == 0 ? namePage : profilePage; + } + + public boolean loading; + + private class Page extends FrameLayout { + + private ProfilePreview profilePreview; + + private RecyclerListView listView; + private RecyclerView.Adapter listAdapter; + private FrameLayout buttonContainer; + private ButtonWithCounterView button; + private PeerColorGrid peerColorPicker; + + private int selectedColor = -1; + private long selectedEmoji = 0; + private ThemePreviewMessagesCell messagesCellPreview; + private SetReplyIconCell setReplyIconCell; + + private CharSequence buttonLocked, buttonUnlocked; + + int previewRow = -1; + int colorPickerRow = -1; + int infoRow = -1; + int iconRow = -1; + int info2Row = -1; + int buttonRow = -1; + int clearRow = -1; + int shadowRow = -1; + int rowCount; + + private static final int VIEW_TYPE_MESSAGE = 0; + private static final int VIEW_TYPE_COLOR_PICKER = 1; + private static final int VIEW_TYPE_INFO = 2; + private static final int VIEW_TYPE_ICON = 3; + private static final int VIEW_TYPE_BUTTONPAD = 5; + private static final int VIEW_TYPE_TEXT = 6; + + private final int type; + public Page(Context context, int type) { + super(context); + this.type = type; + + if (type == PAGE_PROFILE) { + if (dialogId < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + selectedColor = ChatObject.getProfileColorId(chat); + selectedEmoji = ChatObject.getProfileEmojiId(chat); + } else { + TLRPC.User user = getUserConfig().getCurrentUser(); + selectedColor = UserObject.getProfileColorId(user); + selectedEmoji = UserObject.getProfileEmojiId(user); + } + } else { + if (dialogId < 0) { + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + selectedColor = ChatObject.getColorId(chat); + selectedEmoji = ChatObject.getEmojiId(chat); + } else { + TLRPC.User user = getUserConfig().getCurrentUser(); + selectedColor = UserObject.getColorId(user); + selectedEmoji = UserObject.getEmojiId(user); + } + } + + listView = new RecyclerListView(getContext(), getResourceProvider()) { + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, heightSpec); + updateButtonY(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + updateButtonY(); + } + }; + ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); + listView.setLayoutManager(new LinearLayoutManager(getContext())); + listView.setAdapter(listAdapter = new RecyclerListView.SelectionAdapter() { + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_ICON || holder.getItemViewType() == VIEW_TYPE_TEXT; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_MESSAGE: + ThemePreviewMessagesCell messagesCell = messagesCellPreview = new ThemePreviewMessagesCell(getContext(), parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId, resourceProvider); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + messagesCell.fragment = PeerColorActivity.this; + view = messagesCell; + break; + default: + case VIEW_TYPE_INFO: + TextInfoPrivacyCell cell = new TextInfoPrivacyCell(getContext(), getResourceProvider()); + view = cell; + break; + case VIEW_TYPE_COLOR_PICKER: + PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(getContext(), type, currentAccount, resourceProvider); + colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + colorPicker.setSelected(selectedColor, false); + colorPicker.setOnColorClick(colorId -> { + selectedColor = colorId; + colorPicker.setSelected(colorId, true); + updateMessages(); + if (setReplyIconCell != null) { + setReplyIconCell.invalidate(); + } + if (type == PAGE_PROFILE && colorBar != null) { + 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; + break; + case VIEW_TYPE_BUTTONPAD: + view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(14 + 48 + 14), MeasureSpec.EXACTLY)); + } + }; + break; + case VIEW_TYPE_ICON: + SetReplyIconCell setcell = setReplyIconCell = new SetReplyIconCell(getContext()); + setcell.update(false); + view = setcell; + break; + case VIEW_TYPE_TEXT: + TextCell textCell = new TextCell(getContext(), getResourceProvider()); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + break; + case 4: + view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(16), MeasureSpec.EXACTLY) + ); + } + }; + view.setBackground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + switch (getItemViewType(position)) { + case VIEW_TYPE_INFO: + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + if (position == infoRow) { + if (type == PAGE_NAME) { + cell.setText(LocaleController.getString(isChannel ? R.string.ChannelColorHint : R.string.UserColorHint)); + } else { + cell.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileHint : R.string.UserProfileHint)); + } + cell.setBackground(Theme.getThemedDrawableByKey(getContext(), clearRow >= 0 ? R.drawable.greydivider : R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (position == shadowRow) { + cell.setText(""); + cell.setBackground(Theme.getThemedDrawableByKey(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } + break; + case VIEW_TYPE_TEXT: + TextCell textCell = (TextCell) holder.itemView; + textCell.updateColors(); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + if (position == clearRow) { + textCell.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileColorReset : R.string.UserProfileColorReset), false); + } + break; + } + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public int getItemViewType(int position) { + if (position == previewRow) { + return VIEW_TYPE_MESSAGE; + } + if (position == infoRow || position == info2Row || position == shadowRow) { + return VIEW_TYPE_INFO; + } + if (position == colorPickerRow) { + return VIEW_TYPE_COLOR_PICKER; + } + if (position == iconRow) { + return VIEW_TYPE_ICON; + } + if (position == buttonRow) { + return VIEW_TYPE_BUTTONPAD; + } + if (position == clearRow) { + return VIEW_TYPE_TEXT; + } + if (position == getItemCount() - 1) { + return 4; + } + return VIEW_TYPE_INFO; + } + }); + listView.setOnItemClickListener((view, position) -> { + if (view instanceof SetReplyIconCell) { + showSelectStatusDialog((SetReplyIconCell) view); + } else if (position == clearRow) { + selectedColor = -1; + selectedEmoji = 0; + if (peerColorPicker != null) { + peerColorPicker.setSelected(selectedColor, true); + } + updateMessages(); + if (type == PAGE_PROFILE) { + namePage.updateMessages(); + } + if (setReplyIconCell != null) { + setReplyIconCell.update(true); + } + if (type == PAGE_PROFILE && colorBar != null) { + 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(); + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + buttonContainer = new FrameLayout(getContext()); + buttonContainer.setPadding(dp(14), dp(14), dp(14), dp(14)); + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + + SpannableStringBuilder buttonLock = new SpannableStringBuilder("l"); + buttonLock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + buttonUnlocked = LocaleController.getString(isChannel ? R.string.ChannelColorApply : R.string.UserColorApplyIcon); + buttonLocked = new SpannableStringBuilder(buttonLock).append(" ").append(buttonUnlocked); + + button = new ButtonWithCounterView(getContext(), getResourceProvider()); + button.text.setHacks(true, true, true); + button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), false); + button.setOnClickListener(v -> buttonClick()); + buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + + addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + updateButtonY(); + } + }); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); + + if (type == PAGE_PROFILE) { + profilePreview = new ProfilePreview(getContext(), 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)); + } + + updateColors(); + updateRows(); + + setWillNotDraw(false); + } + + private int actionBarHeight; + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getParentLayout() != null) { + getParentLayout().drawHeaderShadow(canvas, actionBarHeight); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (type == PAGE_NAME) { + actionBarHeight = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; + } else { + actionBarHeight = dp(144) + AndroidUtilities.statusBarHeight; + ((MarginLayoutParams) listView.getLayoutParams()).topMargin = actionBarHeight; + ((MarginLayoutParams) profilePreview.getLayoutParams()).height = actionBarHeight; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public boolean hasUnsavedChanged() { + if (isChannel) { + final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (chat == null) return false; + if (type == PAGE_NAME) { + return !(selectedColor == ChatObject.getColorId(chat) && selectedEmoji == ChatObject.getEmojiId(chat)); + } else { + return !(selectedColor == ChatObject.getProfileColorId(chat) && selectedEmoji == ChatObject.getProfileEmojiId(chat)); + } + } else { + final TLRPC.User me = getUserConfig().getCurrentUser(); + if (me == null) return false; + if (type == PAGE_NAME) { + return !(selectedColor == UserObject.getColorId(me) && selectedEmoji == UserObject.getEmojiId(me)); + } else { + return !(selectedColor == UserObject.getProfileColorId(me) && selectedEmoji == UserObject.getProfileEmojiId(me)); + } + } + } + + private void updateButtonY() { + if (buttonContainer == null) { + return; + } + final int lastPosition = listAdapter.getItemCount() - 1; + boolean foundLastPosition = false; + int maxTop = 0; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + final int position = listView.getChildAdapterPosition(child); + if (position != RecyclerListView.NO_POSITION && position <= lastPosition) { + maxTop = Math.max(maxTop, child.getTop()); + if (position == lastPosition) { + foundLastPosition = true; + } + } + } + if (!foundLastPosition) { + maxTop = listView.getMeasuredHeight(); + } + buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14)))); + } + + + private class SetReplyIconCell extends FrameLayout { + + private TextView textView; + private Text offText; + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; + + public SetReplyIconCell(Context context) { + super(context); + + setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + if (type == PAGE_NAME) { + textView.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIcon : R.string.UserReplyIcon)); + } else { + textView.setText(LocaleController.getString(isChannel ? R.string.ChannelProfileIcon : R.string.UserProfileIcon)); + } + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 20, 0)); + + imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + } + + public void updateColors() { + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + } + + public void update(boolean animated) { + if (selectedEmoji != 0) { + imageDrawable.set(selectedEmoji, animated); + offText = null; + } else { + imageDrawable.set((Drawable) null, animated); + if (offText == null) { + offText = new Text(LocaleController.getString(isChannel ? R.string.ChannelReplyIconOff : R.string.UserReplyIconOff), 16); + } + } + } + + public void updateImageBounds() { + imageDrawable.setBounds( + 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 + ); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + updateImageBounds(); + imageDrawable.setColor(getColor()); + if (offText != null) { + offText.draw(canvas, getMeasuredWidth() - offText.getWidth() - dp(19), getMeasuredHeight() / 2f, getThemedColor(Theme.key_windowBackgroundWhiteBlueText4), 1f); + } else { + imageDrawable.draw(canvas); + } + } + + public int getColor() { + if (selectedColor < 0) { + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + return Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourceProvider); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + return Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle, resourceProvider), .5f); + } else { + return Theme.blendOver(Theme.getColor(Theme.key_windowBackgroundWhite, resourceProvider), Theme.multAlpha(adaptProfileEmojiColor(Theme.getColor(Theme.key_actionBarDefault, resourceProvider)), .7f)); + } + } else if (selectedColor < 7) { + return getThemedColor(Theme.keys_avatar_nameInMessage[selectedColor]); + } else { + MessagesController.PeerColors peerColors = type == PAGE_NAME ? MessagesController.getInstance(currentAccount).peerColors : MessagesController.getInstance(currentAccount).profilePeerColors; + if (peerColors != null) { + MessagesController.PeerColor color = peerColors.getColor(selectedColor); + if (color != null) { + return color.getColor1(); + } + } + } + return getThemedColor(Theme.keys_avatar_nameInMessage[0]); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY) + ); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + imageDrawable.detach(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + imageDrawable.attach(); + } + } + + private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; + public void showSelectStatusDialog(SetReplyIconCell cell) { + if (selectAnimatedEmojiDialog != null || cell == null) { + return; + } + final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; + int xoff = 0, yoff = 0; + + AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; + View scrimDrawableParent = null; + final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); + final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); + if (cell != null) { + scrimDrawable = cell.imageDrawable; + scrimDrawableParent = cell; + if (cell.imageDrawable != null) { + cell.imageDrawable.play(); + cell.updateImageBounds(); + AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); + if (type == PAGE_NAME) { + yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; + } else { + yoff = -(cell.getHeight() - AndroidUtilities.rectTmp2.centerY()) - AndroidUtilities.dp(16); + } + xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); + } + } + SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(PeerColorActivity.this, getContext(), true, xoff, type == PAGE_NAME ? SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON : SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON_BOTTOM, true, getResourceProvider(), type == PAGE_NAME ? 24 : 16, cell.getColor()) { + @Override + protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { + selectedEmoji = documentId == null ? 0 : documentId; + if (cell != null) { + cell.update(true); + } + if (profilePreview != null) { + profilePreview.setEmoji(selectedEmoji, true); + } + updateMessages(); + if (popup[0] != null) { + selectAnimatedEmojiDialog = null; + popup[0].dismiss(); + } + } + + @Override + protected float getScrimDrawableTranslationY() { + return 0; + } + }; + popupLayout.useAccentForPlus = true; + popupLayout.setSelected(selectedEmoji == 0 ? null : selectedEmoji); + popupLayout.setSaveState(3); + popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); + popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + selectAnimatedEmojiDialog = null; + } + }; + popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); + popup[0].dimBehind(); + } + + public void checkResetColorButton() { + if (type != PAGE_PROFILE) { + return; + } + final int wasIndex = clearRow; + updateRows(); + if (wasIndex >= 0 && clearRow < 0) { + listAdapter.notifyItemRangeRemoved(wasIndex, 2); + } else if (wasIndex < 0 && clearRow >= 0) { + listAdapter.notifyItemRangeInserted(clearRow, 2); + } + } + + private void updateRows() { + rowCount = 0; + if (type == PAGE_NAME) { + previewRow = rowCount++; + } + colorPickerRow = rowCount++; + iconRow = rowCount++; + infoRow = rowCount++; + if (type == PAGE_PROFILE && selectedColor >= 0) { + clearRow = rowCount++; + shadowRow = rowCount++; + } else { + clearRow = -1; + shadowRow = -1; + } + buttonRow = rowCount++; + } + + private void updateMessages() { + if (messagesCellPreview != null) { + ChatMessageCell[] cells = messagesCellPreview.getCells(); + for (int i = 0; i < cells.length; ++i) { + if (cells[i] != null) { + MessageObject msg = cells[i].getMessageObject(); + if (msg != null) { + if (peerColorPicker != null) { + msg.overrideLinkColor = peerColorPicker.getColorId(); + } + msg.overrideLinkEmoji = selectedEmoji; + cells[i].setAvatar(msg); + cells[i].invalidate(); + } + } + } + } + } + + public void updateColors() { + listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + if (type == PAGE_PROFILE && colorBar != null) { + colorBar.setColor(currentAccount, selectedColor, true); + } + if (button != null) { + button.updateColors(); + } + if (messagesCellPreview != null) { + messagesCellPreview.invalidate(); + } + if (profilePreview != null) { + profilePreview.setColor(selectedColor, false); + } + buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof PeerColorGrid) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((PeerColorGrid) view).updateColors(); + } else if (view instanceof TextCell) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((TextCell) view).updateColors(); + } else if (view instanceof SetReplyIconCell) { + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + ((SetReplyIconCell) view).updateColors(); + } + }); + } + + public void premiumChanged() { + if (button != null && !isChannel) { + button.setText(!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked, true); + } + } + } + + private Theme.ResourcesProvider parentResourcesProvider; + private final SparseIntArray currentColors = new SparseIntArray(); + private final Theme.MessageDrawable msgInDrawable, msgInDrawableSelected; + + public void updateThemeColors() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("themeconfig", Activity.MODE_PRIVATE); + String dayThemeName = preferences.getString("lastDayTheme", "Blue"); + if (Theme.getTheme(dayThemeName) == null || Theme.getTheme(dayThemeName).isDark()) { + dayThemeName = "Blue"; + } + String nightThemeName = preferences.getString("lastDarkTheme", "Dark Blue"); + if (Theme.getTheme(nightThemeName) == null || !Theme.getTheme(nightThemeName).isDark()) { + nightThemeName = "Dark Blue"; + } + Theme.ThemeInfo themeInfo = Theme.getActiveTheme(); + if (dayThemeName.equals(nightThemeName)) { + if (themeInfo.isDark() || dayThemeName.equals("Dark Blue") || dayThemeName.equals("Night")) { + dayThemeName = "Blue"; + } else { + nightThemeName = "Dark Blue"; + } + } + + if (isDark) { + themeInfo = Theme.getTheme(nightThemeName); + } else { + themeInfo = Theme.getTheme(dayThemeName); + } + + currentColors.clear(); + final String[] wallpaperLink = new String[1]; + final SparseIntArray themeColors; + if (themeInfo.assetName != null) { + themeColors = Theme.getThemeFileValues(null, themeInfo.assetName, wallpaperLink); + } else { + themeColors = Theme.getThemeFileValues(new File(themeInfo.pathToFile), null, wallpaperLink); + } + int[] defaultColors = Theme.getDefaultColors(); + if (defaultColors != null) { + for (int i = 0; i < defaultColors.length; ++i) { + currentColors.put(i, defaultColors[i]); + } + } + 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) { + Theme.BackgroundDrawableSettings bg = Theme.createBackgroundDrawable(themeInfo, currentColors, wallpaperLink[0], 0, true); + namePage.messagesCellPreview.setOverrideBackground(bg.themedWallpaper != null ? bg.themedWallpaper : bg.wallpaper); + } + } public PeerColorActivity(long dialogId) { super(); this.dialogId = dialogId; this.isChannel = dialogId != 0; + + resourceProvider = new Theme.ResourcesProvider() { + @Override + public int getColor(int key) { + int index = currentColors.indexOfKey(key); + if (index >= 0) { + return currentColors.valueAt(index); + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getColor(key); + } + return Theme.getColor(key); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (drawableKey.equals(Theme.key_drawable_msgIn)) { + return msgInDrawable; + } + if (drawableKey.equals(Theme.key_drawable_msgInSelected)) { + return msgInDrawableSelected; + } + if (parentResourcesProvider != null) { + return parentResourcesProvider.getDrawable(drawableKey); + } + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public Paint getPaint(String paintKey) { + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public boolean isDark() { + return isDark; + } + }; + msgInDrawable = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, false, resourceProvider); + msgInDrawableSelected = new Theme.MessageDrawable(Theme.MessageDrawable.TYPE_TEXT, false, true, resourceProvider); + } + + @Override + public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + parentResourcesProvider = resourceProvider; + } + + private boolean startAtProfile; + public PeerColorActivity startOnProfile() { + this.startAtProfile = true; + return this; } private BaseFragment bulletinFragment; @@ -148,271 +885,195 @@ public boolean clipWithGradient(int tag) { return super.onFragmentCreate(); } + private ViewPagerFixed viewPager; + + private ImageView backButton; + private ImageView dayNightItem; + + private FrameLayout actionBarContainer; + private FilledTabsView tabsView; + private SimpleTextView titleView; + @Override public View createView(Context context) { - actionBar.setTitle(LocaleController.getString(isChannel ? R.string.ChannelColorTitle : R.string.UserColorTitle)); - actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setAllowOverlayTitle(true); - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + namePage = new Page(context, PAGE_NAME); + profilePage = new Page(context, PAGE_PROFILE); + + actionBar.setCastShadows(false); + actionBar.setVisibility(View.GONE); + actionBar.setAllowOverlayTitle(false); + + FrameLayout frameLayout = new FrameLayout(context) { @Override - public void onItemClick(int id) { - if (id == -1) { - if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { - showUnsavedAlert(); - return; - } - finishFragment(); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (actionBarContainer != null) { + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).height = ActionBar.getCurrentActionBarHeight(); + ((MarginLayoutParams) actionBarContainer.getLayoutParams()).topMargin = AndroidUtilities.statusBarHeight; } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - }); + }; + frameLayout.setFitsSystemWindows(true); - if (dialogId < 0) { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if ((chat.flags2 & 32) != 0) { - selectedEmoji = chat.background_emoji_id; - } - if ((chat.flags2 & 64) != 0) { - selectedColor = chat.color; - } else { - selectedColor = (int) (chat.id % 7); - } - } else { - TLRPC.User user = getUserConfig().getCurrentUser(); - if ((user.flags2 & 64) != 0) { - selectedEmoji = user.background_emoji_id; - } - if ((user.flags2 & 128) != 0) { - selectedColor = user.color; - } else { - selectedColor = (int) (user.id % 7); - } - if (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool()) { - selectedColor = NaConfig.INSTANCE.getUseLocalQuoteColorColor().Int(); - selectedEmoji = NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().Long(); + colorBar = new ColoredActionBar(context, resourceProvider) { + @Override + protected void onUpdateColor() { + updateLightStatusBar(); + updateActionBarButtonsColor(); + if (tabsView != null) { + tabsView.setBackgroundColor(getTabsViewBackgroundColor()); + } } - } - FrameLayout frameLayout = new FrameLayout(context); - - listView = new RecyclerListView(context) { - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - super.onMeasure(widthSpec, heightSpec); - updateButtonY(); + 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(currentAccount, profilePage.selectedColor, false); + } + frameLayout.addView(colorBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + viewPager = new ViewPagerFixed(context) { @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - updateButtonY(); + protected void onTabAnimationUpdate(boolean manual) { + tabsView.setSelected(viewPager.getPositionAnimated()); + colorBar.setProgressToGradient(viewPager.getPositionAnimated()); } }; - ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); - listView.setLayoutManager(new LinearLayoutManager(context)); - listView.setAdapter(listAdapter = new RecyclerListView.SelectionAdapter() { + viewPager.setAdapter(new ViewPagerFixed.Adapter() { @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == VIEW_TYPE_ICON; + public int getItemCount() { + return 2; } - @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case VIEW_TYPE_MESSAGE: - ThemePreviewMessagesCell messagesCell = messagesCellPreview = new ThemePreviewMessagesCell(context, parentLayout, ThemePreviewMessagesCell.TYPE_PEER_COLOR, dialogId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - messagesCell.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - } - messagesCell.fragment = PeerColorActivity.this; - view = messagesCell; - break; - default: - case VIEW_TYPE_INFO: - TextInfoPrivacyCell cell = new TextInfoPrivacyCell(context); - view = cell; - break; - case VIEW_TYPE_COLOR_PICKER: - PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(context, currentAccount); - colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); - colorPicker.setSelected(selectedColor); - colorPicker.setOnColorClick(colorId -> { - selectedColor = colorId; - colorPicker.setSelected(colorId); - updateMessages(); - if (setReplyIconCell != null) { - setReplyIconCell.invalidate(); - } - }); - view = colorPicker; - break; - case VIEW_TYPE_BUTTONPAD: - view = new View(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(14 + 48 + 14), MeasureSpec.EXACTLY)); - } - }; - break; - case VIEW_TYPE_ICON: - SetReplyIconCell setcell = setReplyIconCell = new SetReplyIconCell(context); - setcell.update(false); - view = setcell; - break; - case 4: - view = new View(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(16), MeasureSpec.EXACTLY) - ); - } - }; - view.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - break; - } - return new RecyclerListView.Holder(view); + public View createView(int viewType) { + if (viewType == PAGE_NAME) return namePage; + if (viewType == PAGE_PROFILE) return profilePage; + return null; } @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - switch (getItemViewType(position)) { - case VIEW_TYPE_INFO: - TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; - if (position == infoRow) { - cell.setText(LocaleController.getString(isChannel ? R.string.ChannelColorHint : R.string.UserColorHint)); - cell.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); - } else if (position == info2Row) { - cell.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIconHint : R.string.UserReplyIconHint)); - cell.setBackground(Theme.getThemedDrawableByKey(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - } - } + public int getItemViewType(int position) { + return position; } @Override - public int getItemCount() { - return rowCount; - } + public void bindView(View view, int position, int viewType) { - @Override - public int getItemViewType(int position) { - if (position == previewRow) { - return VIEW_TYPE_MESSAGE; - } - if (position == infoRow || position == info2Row) { - return VIEW_TYPE_INFO; - } - if (position == colorPickerRow) { - return VIEW_TYPE_COLOR_PICKER; - } - if (position == iconRow) { - return VIEW_TYPE_ICON; - } - if (position == buttonRow) { - return VIEW_TYPE_BUTTONPAD; - } - if (position == getItemCount() - 1) { - return 4; - } - return VIEW_TYPE_INFO; - } - }); - listView.setOnItemClickListener((view, position) -> { - if (view instanceof SetReplyIconCell) { - showSelectStatusDialog((SetReplyIconCell) view); } }); - frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); - buttonContainer = new FrameLayout(context); - buttonContainer.setPadding(dp(14), dp(14), dp(14), dp(14)); - buttonContainer.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + actionBarContainer = new FrameLayout(context); + frameLayout.addView(actionBarContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - SpannableStringBuilder buttonLock = new SpannableStringBuilder("l"); - buttonLock.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock2), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - buttonUnlocked = LocaleController.getString(isChannel ? R.string.ChannelColorApply : R.string.UserColorApplyIcon); - buttonLocked = new SpannableStringBuilder(buttonLock).append(" ").append(buttonUnlocked); + if (!isChannel) { + tabsView = new FilledTabsView(context); + tabsView.setTabs( + LocaleController.getString(isChannel ? R.string.ChannelColorTabName : R.string.UserColorTabName), + LocaleController.getString(isChannel ? R.string.ChannelColorTabProfile : R.string.UserColorTabProfile) + ); + tabsView.onTabSelected(tab -> { + if (viewPager != null) { + viewPager.scrollToPosition(tab); + } + }); + actionBarContainer.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.CENTER)); + } else { + titleView = new SimpleTextView(context); + titleView.setText(LocaleController.getString(R.string.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)); + } - button = new ButtonWithCounterView(context, getResourceProvider()); - button.text.setHacks(true, true, true); - button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), false); - button.setOnClickListener(v -> buttonClick()); - buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + if (startAtProfile) { + viewPager.setPosition(1); + if (tabsView != null) { + tabsView.setSelected(1); + } + if (colorBar != null) { + colorBar.setProgressToGradient(1f); + updateLightStatusBar(); + } + } - frameLayout.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); - listView.setOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - updateButtonY(); + backButton = new ImageView(context); + backButton.setScaleType(ImageView.ScaleType.CENTER); + backButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarWhiteSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + backButton.setImageResource(R.drawable.ic_ab_back); + backButton.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + backButton.setOnClickListener(v -> { + if (onBackPressed()) { + finishFragment(); } }); + actionBarContainer.addView(backButton, LayoutHelper.createFrame(54, 54, Gravity.LEFT | Gravity.CENTER_VERTICAL)); - fragmentView = contentView = frameLayout; + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (!isDark) { + sunDrawable.setCustomEndFrame(0); + sunDrawable.setCurrentFrame(0); + } else { + sunDrawable.setCurrentFrame(35); + sunDrawable.setCustomEndFrame(36); + } + sunDrawable.beginApplyLayerColors(); + int color = Theme.getColor(Theme.key_chats_menuName); + sunDrawable.setLayerColor("Sunny.**", color); + sunDrawable.setLayerColor("Path 6.**", color); + sunDrawable.setLayerColor("Path.**", color); + sunDrawable.setLayerColor("Path 5.**", color); + sunDrawable.commitApplyLayerColors(); + + dayNightItem = new ImageView(context); + dayNightItem.setScaleType(ImageView.ScaleType.CENTER); + dayNightItem.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_actionBarWhiteSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + dayNightItem.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + dayNightItem.setOnClickListener(v -> { + toggleTheme(); + }); + actionBarContainer.addView(dayNightItem, LayoutHelper.createFrame(54, 54, Gravity.RIGHT | Gravity.CENTER_VERTICAL)); + dayNightItem.setImageDrawable(sunDrawable); - updateColors(); - updateRows(); + colorBar.updateColors(); + + fragmentView = contentView = frameLayout; return contentView; } - private void updateButtonY() { - if (buttonContainer == null) { - return; - } - final int lastPosition = listAdapter.getItemCount() - 1; - boolean foundLastPosition = false; - int maxTop = 0; - for (int i = 0; i < listView.getChildCount(); ++i) { - View child = listView.getChildAt(i); - final int position = listView.getChildAdapterPosition(child); - if (position != RecyclerListView.NO_POSITION && position <= lastPosition) { - maxTop = Math.max(maxTop, child.getTop()); - if (position == lastPosition) { - foundLastPosition = true; - } - } - } - if (!foundLastPosition) { - maxTop = listView.getMeasuredHeight(); - } - buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14)))); - } + private boolean isDark = Theme.isCurrentThemeDark(); + private RLottieDrawable sunDrawable; - private void showBoostLimit(boolean error) { - getMessagesController().getBoostsController().getBoostsStats(dialogId, boostsStatus -> { - if (error || boostsStatus.level < getMessagesController().channelColorLevelMin) { - getMessagesController().getBoostsController().userCanBoostChannel(dialogId, boostsStatus, canApplyBoost -> { - if (getContext() == null) { - return; - } - LimitReachedBottomSheet limitReachedBottomSheet = new LimitReachedBottomSheet(this, getContext(), TYPE_BOOSTS_FOR_COLOR, currentAccount, getResourceProvider()); - limitReachedBottomSheet.setCanApplyBoost(canApplyBoost); - - limitReachedBottomSheet.setBoostsStats(boostsStatus, true); - limitReachedBottomSheet.setDialogId(dialogId); - limitReachedBottomSheet.showStatisticButtonInLink(() -> { - TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - Bundle args = new Bundle(); - args.putLong("chat_id", -dialogId); - args.putBoolean("is_megagroup", chat.megagroup); - args.putBoolean("start_from_boosts", true); - TLRPC.ChatFull chatInfo = getMessagesController().getChatFull(-dialogId); - if (chatInfo == null || !chatInfo.can_view_stats) { - args.putBoolean("only_boosts", true); - }; - StatisticActivity fragment = new StatisticActivity(args); - presentFragment(fragment); - }); - showDialog(limitReachedBottomSheet); - AndroidUtilities.runOnUIThread(() -> button.setLoading(false), 300); - }); - } else { - apply(); - } - }); + public boolean hasUnsavedChanged() { + return namePage.hasUnsavedChanged() || profilePage.hasUnsavedChanged(); + } + + 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 @@ -424,25 +1085,6 @@ public boolean onBackPressed() { return super.onBackPressed(); } - public boolean hasUnsavedChanged() { - if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat == null) { - return false; - } - if (selectedColor == chat.color && selectedEmoji == ((chat.flags2 & 64) == 0 ? 0 : chat.background_emoji_id)) { - return false; - } - return true; - } else { - final TLRPC.User me = getUserConfig().getCurrentUser(); - if (selectedColor == me.color && selectedEmoji == ((me.flags2 & 64) == 0 ? 0 : me.background_emoji_id)) { - return false; - } - return true; - } - } - @Override public boolean isSwipeBackEnabled(MotionEvent event) { if (!isChannel && hasUnsavedChanged() && getUserConfig().isPremium()) { @@ -470,22 +1112,14 @@ private void showUnsavedAlert() { } private void buttonClick() { - if (button.isLoading()) { + if (loading) { return; } if (isChannel) { - button.setLoading(true); - showBoostLimit(false); - return; + finishFragment(); } else { if (!getUserConfig().isPremium()) { - Bulletin bulletin = BulletinFactory.of(this).createSimpleBulletin(R.raw.star_premium_2, AndroidUtilities.premiumText(LocaleController.getString(R.string.UserColorApplyPremium), () -> { - presentFragment(new PremiumPreviewFragment("name_color")); - })); - bulletin.getLayout().setPadding(dp(8 + 6), dp(8), dp(8 + 6), dp(8)); - bulletin.show(); - - BotWebViewVibrationEffect.APP_ERROR.vibrate(); + showDialog(new PremiumFeatureBottomSheet(PeerColorActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_NAME_COLOR, true)); return; } } @@ -495,74 +1129,68 @@ private void buttonClick() { showBulletin(); } + private boolean applyingName, applyingProfile; private boolean applying; private void apply() { - if (applying || peerColorPicker == null || !isChannel && !getUserConfig().isPremium()) { + if (applying || !isChannel && !getUserConfig().isPremium()) { return; } if (isChannel) { - final TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat == null) { - return; - } - if (selectedColor == chat.color && selectedEmoji == ((chat.flags2 & 64) == 0 ? 0 : chat.background_emoji_id)) { - return; - } - TLRPC.TL_channels_updateColor req = new TLRPC.TL_channels_updateColor(); - req.channel = getMessagesController().getInputChannel(-dialogId); - if (req.channel == null) { - return; - } - chat.flags2 |= 64; - req.color = chat.color = selectedColor; - if (selectedEmoji != 0) { - chat.flags2 |= 32; - chat.background_emoji_id = selectedEmoji; - - req.flags |= 1; - req.background_emoji_id = selectedEmoji; - } else { - chat.flags2 &= ~32; - chat.background_emoji_id = 0; - } - button.setLoading(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 { - if (NaConfig.INSTANCE.getUseLocalQuoteColor().Bool()) { - NaConfig.INSTANCE.getUseLocalQuoteColorColor().setConfigInt(selectedColor); - NaConfig.INSTANCE.getUseLocalQuoteColorEmoji().setConfigLong(selectedEmoji); - } + PeerColorHelper.apply(namePage.selectedColor, namePage.selectedEmoji, profilePage.selectedColor, profilePage.selectedEmoji); final TLRPC.User me = getUserConfig().getCurrentUser(); - if (selectedColor == me.color && selectedEmoji == ((me.flags2 & 64) == 0 ? 0 : me.background_emoji_id)) { - return; + if (me.color == null) { + me.color = new TLRPC.TL_peerColor(); + me.color.color = (int) (me.id % 7); + } + if (namePage.selectedColor != UserObject.getColorId(me) || namePage.selectedEmoji != UserObject.getEmojiId(me)) { + applyingName = true; + TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); + me.flags2 |= 256; + me.color.flags |= 1; + req.flags |= 4; + req.color = me.color.color = namePage.selectedColor; + if (namePage.selectedEmoji != 0) { + req.flags |= 1; + me.color.flags |= 2; + req.background_emoji_id = me.color.background_emoji_id = namePage.selectedEmoji; + } else { + me.color.flags &=~ 2; + me.color.background_emoji_id = 0; + } + getConnectionsManager().sendRequest(req, null); } - TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); - me.flags2 |= 128; - req.color = me.color = selectedColor; - if (selectedEmoji != 0) { - me.flags2 |= 64; - me.background_emoji_id = selectedEmoji; - - req.flags |= 1; - req.background_emoji_id = selectedEmoji; - } else { - me.flags2 &= ~64; - me.background_emoji_id = 0; + if (profilePage.selectedColor != UserObject.getProfileColorId(me) || profilePage.selectedEmoji != UserObject.getProfileEmojiId(me)) { + applyingProfile = true; + if (me.profile_color == null) { + me.profile_color = new TLRPC.TL_peerColor(); + } + TLRPC.TL_account_updateColor req = new TLRPC.TL_account_updateColor(); + req.for_profile = true; + me.flags2 |= 512; + if (profilePage.selectedColor < 0) { + me.profile_color.flags &=~ 1; + } else { + me.profile_color.flags |= 1; + req.flags |= 4; + req.color = me.profile_color.color = profilePage.selectedColor; + } + if (profilePage.selectedEmoji != 0) { + req.flags |= 1; + me.profile_color.flags |= 2; + req.background_emoji_id = me.profile_color.background_emoji_id = profilePage.selectedEmoji; + } else { + me.profile_color.flags &=~ 2; + me.profile_color.background_emoji_id = 0; + } + getConnectionsManager().sendRequest(req, null); } getMessagesController().putUser(me, false); getUserConfig().saveConfig(true); - getConnectionsManager().sendRequest(req, null); + finishFragment(); + showBulletin(); } applying = true; getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_EMOJI_STATUS); @@ -570,27 +1198,32 @@ private void apply() { private void showBulletin() { if (bulletinFragment != null) { - BulletinFactory.of(bulletinFragment).createSimpleBulletin(PeerColorDrawable.from(currentAccount, selectedColor), LocaleController.getString(isChannel ? R.string.ChannelColorApplied : R.string.UserColorApplied)).show(); - bulletinFragment = null; - } - } - - private void updateMessages() { - if (messagesCellPreview != null) { - ChatMessageCell[] cells = messagesCellPreview.getCells(); - for (int i = 0; i < cells.length; ++i) { - if (cells[i] != null) { - MessageObject msg = cells[i].getMessageObject(); - if (msg != null) { - if (peerColorPicker != null) { - msg.overrideLinkColor = peerColorPicker.getColorId(); - } - msg.overrideLinkEmoji = selectedEmoji; - cells[i].setAvatar(msg); - cells[i].invalidate(); + if (applyingName && (!applyingProfile || getCurrentPage() == namePage)) { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + PeerColorDrawable.from(currentAccount, namePage.selectedColor), + LocaleController.getString(isChannel ? R.string.ChannelColorApplied : R.string.UserColorApplied) + ).show(); + } else if (applyingProfile && (!applyingName || getCurrentPage() == profilePage)) { + if (profilePage.selectedColor < 0) { + if (profilePage.selectedEmoji != 0) { + BulletinFactory.of(bulletinFragment).createStaticEmojiBulletin( + AnimatedEmojiDrawable.findDocument(currentAccount, profilePage.selectedEmoji), + LocaleController.getString(isChannel ? R.string.ChannelProfileColorEmojiApplied : R.string.UserProfileColorEmojiApplied) + ).show(); + } else { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + R.raw.contact_check, + LocaleController.getString(isChannel ? R.string.ChannelProfileColorResetApplied : R.string.UserProfileColorResetApplied) + ).show(); } + } else { + BulletinFactory.of(bulletinFragment).createSimpleBulletin( + PeerColorDrawable.fromProfile(currentAccount, profilePage.selectedColor), + LocaleController.getString(isChannel ? R.string.ChannelProfileColorApplied : R.string.UserProfileColorApplied) + ).show(); } } + bulletinFragment = null; } } @@ -600,161 +1233,6 @@ public void onFragmentClosed() { Bulletin.removeDelegate(this); } - private class SetReplyIconCell extends FrameLayout { - - private TextView textView; - private Text offText; - private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable imageDrawable; - - public SetReplyIconCell(Context context) { - super(context); - - setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); - - textView = new TextView(context); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); - textView.setText(LocaleController.getString(isChannel ? R.string.ChannelReplyIcon : R.string.UserReplyIcon)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, 20, 0, 48, 0)); - - imageDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(24), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); - } - - public void update(boolean animated) { - if (selectedEmoji != 0) { - imageDrawable.set(selectedEmoji, animated); - offText = null; - } else { - imageDrawable.set((Drawable) null, animated); - if (offText == null) { - offText = new Text(LocaleController.getString(isChannel ? R.string.ChannelReplyIconOff : R.string.UserReplyIconOff), 16); - } - } - } - - public void updateImageBounds() { - imageDrawable.setBounds( - getWidth() - imageDrawable.getIntrinsicWidth() - dp(21), - (getHeight() - imageDrawable.getIntrinsicHeight()) / 2, - getWidth() - dp(21), - (getHeight() + imageDrawable.getIntrinsicHeight()) / 2 - ); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - updateImageBounds(); - imageDrawable.setColor(getColor()); - if (offText != null) { - offText.draw(canvas, getMeasuredWidth() - offText.getWidth() - dp(19), getMeasuredHeight() / 2f, getThemedColor(Theme.key_windowBackgroundWhiteBlueText4), 1f); - } else { - imageDrawable.draw(canvas); - } - } - - public int getColor() { - if (selectedColor < 7) { - return getThemedColor(Theme.keys_avatar_nameInMessage[selectedColor]); - } else { - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors != null) { - MessagesController.PeerColor color = peerColors.getColor(selectedColor); - if (color != null) { - return color.getColor1(); - } - } - } - return getThemedColor(Theme.keys_avatar_nameInMessage[0]); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(50), MeasureSpec.EXACTLY) - ); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - imageDrawable.detach(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - imageDrawable.attach(); - } - } - - private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; - public void showSelectStatusDialog(SetReplyIconCell cell) { - if (selectAnimatedEmojiDialog != null || cell == null) { - return; - } - final SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[] popup = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow[1]; - int xoff = 0, yoff = 0; - - AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable = null; - View scrimDrawableParent = null; - final int popupHeight = (int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f); - final int popupWidth = (int) Math.min(dp(340 - 16), AndroidUtilities.displaySize.x * .95f); - if (cell != null) { - scrimDrawable = cell.imageDrawable; - scrimDrawableParent = cell; - if (cell.imageDrawable != null) { - cell.imageDrawable.play(); - cell.updateImageBounds(); - AndroidUtilities.rectTmp2.set(cell.imageDrawable.getBounds()); - yoff = -AndroidUtilities.rectTmp2.centerY() + dp(12) - popupHeight; - xoff = AndroidUtilities.rectTmp2.centerX() - (AndroidUtilities.displaySize.x - popupWidth); - } - } - SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, xoff, SelectAnimatedEmojiDialog.TYPE_SET_REPLY_ICON, true, getResourceProvider(), 24, cell.getColor()) { - @Override - protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - selectedEmoji = documentId == null ? 0 : documentId; - if (cell != null) { - cell.update(true); - } - updateMessages(); - if (popup[0] != null) { - selectAnimatedEmojiDialog = null; - popup[0].dismiss(); - } - } - - @Override - protected float getScrimDrawableTranslationY() { - return 0; - } - }; - popupLayout.useAccentForPlus = true; - popupLayout.setSelected(selectedEmoji == 0 ? null : selectedEmoji); - popupLayout.setSaveState(3); - popupLayout.setScrimDrawable(scrimDrawable, scrimDrawableParent); - popup[0] = selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { - @Override - public void dismiss() { - super.dismiss(); - selectAnimatedEmojiDialog = null; - } - }; - popup[0].showAsDropDown(cell, 0, yoff, Gravity.TOP | Gravity.RIGHT); - popup[0].dimBehind(); - } - - private void updateRows() { - rowCount = 0; - previewRow = rowCount++; - colorPickerRow = rowCount++; - iconRow = rowCount++; - infoRow = rowCount++; - buttonRow = rowCount++; - } - @Override public void onFragmentDestroy() { super.onFragmentDestroy(); @@ -786,8 +1264,16 @@ public ArrayList getThemeDescriptions() { @SuppressLint("NotifyDataSetChanged") private void updateColors() { - contentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); - listAdapter.notifyDataSetChanged(); + contentView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + if (titleView != null) { + titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + } + namePage.updateColors(); + profilePage.updateColors(); + if (colorBar != null) { + colorBar.updateColors(); + } + setNavigationBarColor(getNavigationBarColor()); } @SuppressLint("NotifyDataSetChanged") @@ -795,287 +1281,134 @@ private void updateColors() { public void didReceivedNotification(int id, int account, Object... args) { if (account != currentAccount) return; if (id == NotificationCenter.currentUserPremiumStatusChanged) { -// updateRows(); -// listAdapter.notifyDataSetChanged(); - - if (button != null) { - button.setText(isChannel ? buttonUnlocked : (!getUserConfig().isPremium() ? buttonLocked : buttonUnlocked), true); - } + namePage.premiumChanged(); + profilePage.premiumChanged(); } } - private static class PeerColorPicker extends RecyclerListView { - private final Theme.ResourcesProvider resourcesProvider; - public final LinearLayoutManager layoutManager; - public final Adapter adapter; - private final int currentAccount; - - private static final int[] order = { // key_avatar_nameInMessageRed, key_avatar_nameInMessageOrange, key_avatar_nameInMessageViolet, key_avatar_nameInMessageGreen, key_avatar_nameInMessageCyan, key_avatar_nameInMessageBlue, key_avatar_nameInMessagePink - 5, // blue - 3, // green - 1, // orange - 0, // red - 2, // violet - 4, // cyan - 6 // pink - }; + public static class LevelLock extends Drawable { - @Override - public boolean onInterceptTouchEvent(MotionEvent e) { - if (getParent() != null && getParent().getParent() != null) { - getParent().getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1) || canScrollHorizontally(1)); - getParent().requestDisallowInterceptTouchEvent(true); - } - return super.onInterceptTouchEvent(e); - } + private final Theme.ResourcesProvider resourcesProvider; + private final Text text; + private final float lockScale = .875f; + private final Drawable lock; + private final PremiumGradient.PremiumGradientTools gradientTools; - @Override - public Integer getSelectorColor(int position) { - return 0; + public LevelLock(Context context, int lvl, Theme.ResourcesProvider resourcesProvider) { + this(context, false, lvl, resourcesProvider); } - public PeerColorPicker(Context context, final int currentAccount, Theme.ResourcesProvider resourcesProvider) { - super(context); - this.currentAccount = currentAccount; + public LevelLock(Context context, boolean plus, int lvl, Theme.ResourcesProvider resourcesProvider) { this.resourcesProvider = resourcesProvider; - - setPadding(dp(8), dp(8), dp(8), dp(8)); - setClipToPadding(false); - - setAdapter(adapter = new SelectionAdapter() { - @Override - public boolean isEnabled(ViewHolder holder) { - return true; - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new Holder(new ColorCell(context)); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - ColorCell cell = (ColorCell) holder.itemView; - cell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); - cell.setSelected(position == selectedPosition, false); - if (position >= 0 && position < Theme.keys_avatar_nameInMessage.length) { - cell.set( - Theme.getColor(Theme.keys_avatar_nameInMessage[order[position]], resourcesProvider) - ); - } else { - position -= Theme.keys_avatar_nameInMessage.length; - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors != null && position >= 0 && position < peerColors.colors.size()) { - cell.set(peerColors.colors.get(position)); - } - } - } - - @Override - public int getItemCount() { - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - return 7 + (peerColors == null ? 0 : peerColors.colors.size()); - } - }); - layoutManager = new LinearLayoutManager(context); - layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); - setLayoutManager(layoutManager); - } - - private int selectedPosition; - public void setSelected(int color) { - setSelectedPosition(toPosition(color)); + 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); } - public void setSelectedPosition(int position) { - if (position != selectedPosition) { - selectedPosition = position; - AndroidUtilities.forEachViews(this, child -> ((ColorCell) child).setSelected(getChildAdapterPosition(child) == selectedPosition, true)); - } - } + @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); - public int getColorId() { - return toColorId(selectedPosition); + text.draw(canvas, left + dp(3.66f) + lock.getIntrinsicWidth() * lockScale, cy, Color.WHITE, 1f); } - public int toPosition(final int colorId) { - if (colorId >= 0 && colorId < Theme.keys_avatar_nameInMessage.length) { - for (int i = 0; i < order.length; ++i) { - if (order[i] == colorId) { - return i; - } - } - } - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors == null) { - return 0; - } - for (int i = 0; i < peerColors.colors.size(); ++i) { - if (peerColors.colors.get(i).id == colorId) { - return 7 + i; - } - } - return 0; - } + @Override + public void setAlpha(int alpha) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} - public int toColorId(int position) { - if (position >= 0 && position < 7) { - return order[position]; - } - position -= 7; - MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - if (peerColors == null || position < 0 || position >= peerColors.colors.size()) { - return 0; - } - return peerColors.colors.get(position).id; + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; } - private static class ColorCell extends View { - private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Paint paint3 = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Path circlePath = new Path(); - private final Path color2Path = new Path(); - private boolean hasColor2, hasColor3; - - private final ButtonBounce bounce = new ButtonBounce(this); - - public ColorCell(Context context) { - super(context); - backgroundPaint.setStyle(Paint.Style.STROKE); - } - - public void setBackgroundColor(int backgroundColor) { - backgroundPaint.setColor(backgroundColor); - } - - public void set(int color) { - hasColor2 = hasColor3 = false; - paint1.setColor(color); - } - - public void set(int color1, int color2) { - hasColor2 = true; - hasColor3 = false; - paint1.setColor(color1); - paint2.setColor(color2); - } - - public void set(MessagesController.PeerColor color) { - if (Theme.isCurrentThemeDark() && color.hasColor2() && !color.hasColor3()) { - paint1.setColor(color.getColor2()); - paint2.setColor(color.getColor1()); - } else { - paint1.setColor(color.getColor1()); - paint2.setColor(color.getColor2()); - } - paint3.setColor(color.getColor3()); - hasColor2 = color.hasColor2(); - hasColor3 = color.hasColor3(); - } - - private boolean selected; - private final AnimatedFloat selectedT = new AnimatedFloat(this, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); - public void setSelected(boolean selected, boolean animated) { - this.selected = selected; - if (!animated) { - selectedT.set(selected, true); - } - invalidate(); - } - - private static final int VIEW_SIZE_DP = 56; - private static final int CIRCLE_RADIUS_DP = 20; - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(dp(VIEW_SIZE_DP), dp(VIEW_SIZE_DP)); - - circlePath.rewind(); - circlePath.addCircle(getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, dp(CIRCLE_RADIUS_DP), Path.Direction.CW); - - color2Path.rewind(); - color2Path.moveTo(getMeasuredWidth(), 0); - color2Path.lineTo(getMeasuredWidth(), getMeasuredHeight()); - color2Path.lineTo(0, getMeasuredHeight()); - color2Path.close(); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - canvas.save(); - final float s = bounce.getScale(.05f); - canvas.scale(s, s, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); - - canvas.save(); - canvas.clipPath(circlePath); - canvas.drawPaint(paint1); - if (hasColor2) { - canvas.drawPath(color2Path, paint2); - } - canvas.restore(); - - if (hasColor3) { - canvas.save(); - AndroidUtilities.rectTmp.set( - (getMeasuredWidth() - dp(12.4f)) / 2f, - (getMeasuredHeight() - dp(12.4f)) / 2f, - (getMeasuredWidth() + dp(12.4f)) / 2f, - (getMeasuredHeight() + dp(12.4f)) / 2f - ); - canvas.rotate(45f, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); - canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2.33f), dp(2.33f), paint3); - canvas.restore(); - } - - final float selectT = selectedT.set(selected); - - if (selectT > 0) { - backgroundPaint.setStrokeWidth(dpf2(2)); - canvas.drawCircle( - getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, - AndroidUtilities.lerp( - dp(CIRCLE_RADIUS_DP) + backgroundPaint.getStrokeWidth() * .5f, - dp(CIRCLE_RADIUS_DP) - backgroundPaint.getStrokeWidth() * 2f, - selectT - ), - backgroundPaint - ); - } - - canvas.restore(); - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - bounce.setPressed(pressed); - } + @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; private final Theme.ResourcesProvider resourcesProvider; private final Drawable drawable; private final Text buttonText; + private LevelLock lock; private final Paint userTextBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Text userText; private int userTextColorKey = -1; private boolean needDivider; - public ChangeNameColorCell(boolean isChannel, Context context, Theme.ResourcesProvider resourcesProvider) { + private PeerColorDrawable color1Drawable; + private PeerColorDrawable color2Drawable; + + public ChangeNameColorCell(int currentAccount, long dialogId, Context context, Theme.ResourcesProvider resourcesProvider) { super(context); - this.isChannel = isChannel; + + this.currentAccount = currentAccount; + 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(); } @@ -1099,7 +1432,7 @@ public void set(TLRPC.Chat chat, boolean divider) { text = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), false); userText = new Text(text, 13, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); final int color; - int colorId = chat != null && (chat.flags2 & 64) != 0 ? chat.color : (int) (chat.id % 7); + int colorId = ChatObject.getColorId(chat); if (colorId < 7) { color = Theme.getColor(userTextColorKey = Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { @@ -1114,6 +1447,9 @@ public void set(TLRPC.Chat chat, boolean divider) { } userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); + + 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) { @@ -1129,7 +1465,7 @@ public void set(TLRPC.User user) { text = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), false); userText = new Text(text, 13, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); final int color; - int colorId = user != null && (user.flags2 & 128) != 0 ? user.color : (int) (user.id % 7); + int colorId = UserObject.getColorId(user); if (colorId < 7) { color = Theme.getColor(userTextColorKey = Theme.keys_avatar_nameInMessage[colorId], resourcesProvider); } else { @@ -1144,6 +1480,9 @@ public void set(TLRPC.User user) { } userText.setColor(color); userTextBackgroundPaint.setColor(Theme.multAlpha(color, .10f)); + + color1Drawable = PeerColorDrawable.from(currentAccount, colorId).setRadius(dp(11)); + color2Drawable = UserObject.getProfileColorId(user) >= 0 ? PeerColorDrawable.fromProfile(currentAccount, UserObject.getProfileColorId(user)).setRadius(dp(11)) : null; } @Override @@ -1167,12 +1506,29 @@ protected void dispatchDraw(Canvas canvas) { 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 = 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); + + x -= dp(18); + color1Drawable.setBounds(x - dp(11), (getMeasuredHeight() - dp(11)) / 2, x, (getMeasuredHeight() + dp(11)) / 2); + color1Drawable.stroke(dpf2(3), Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)); + color1Drawable.draw(canvas); - if (userText != null) { - final int maxWidth = (int) (getMeasuredWidth() - dp(64 + 7 + 15 + 9 + 9 + 12) - Math.min(buttonText.getWidth(), getMeasuredWidth() - dp(64 + 100))); + } else if (userText != null) { + 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( @@ -1184,8 +1540,8 @@ protected void dispatchDraw(Canvas canvas) { canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(12), dp(12), userTextBackgroundPaint); userText - .ellipsize(maxWidth) - .draw(canvas, LocaleController.isRTL ? dp(15 + 9) : getMeasuredWidth() - dp(15 + 9) - w, getMeasuredHeight() / 2f); + .ellipsize(maxWidth) + .draw(canvas, LocaleController.isRTL ? dp(15 + 9) : getMeasuredWidth() - dp(15 + 9) - w, getMeasuredHeight() / 2f); } if (needDivider) { @@ -1199,9 +1555,11 @@ protected void dispatchDraw(Canvas canvas) { } 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); } public class ColorButton { - private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint paint3 = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -1211,13 +1569,7 @@ public class ColorButton { private final ButtonBounce bounce = new ButtonBounce(PeerColorGrid.this); - public ColorButton() { - backgroundPaint.setStyle(Paint.Style.STROKE); - } - - public void setBackgroundColor(int backgroundColor) { - backgroundPaint.setColor(backgroundColor); - } + public ColorButton() {} public void set(int color) { hasColor2 = hasColor3 = false; @@ -1235,16 +1587,24 @@ public void set(MessagesController.PeerColor color) { if (color == null) { return; } - if (Theme.isCurrentThemeDark() && color.hasColor2() && !color.hasColor3()) { - paint1.setColor(color.getColor2()); - paint2.setColor(color.getColor1()); + final boolean dark = resourcesProvider == null ? Theme.isCurrentThemeDark() : resourcesProvider.isDark(); + if (type == PAGE_NAME) { + if (dark && 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(dark); + hasColor3 = color.hasColor3(dark); } else { - paint1.setColor(color.getColor1()); - paint2.setColor(color.getColor2()); + 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; } - paint3.setColor(color.getColor3()); - hasColor2 = color.hasColor2(); - hasColor3 = color.hasColor3(); } private boolean selected; @@ -1257,14 +1617,10 @@ public void setSelected(boolean selected, boolean animated) { invalidate(); } - private static final int VIEW_SIZE_DP = 56; - private static final int CIRCLE_RADIUS_DP = 20; - public int id; private final RectF bounds = new RectF(); public final RectF clickBounds = new RectF(); - public void layout(int id, RectF bounds) { - this.id = id; + public void layout(RectF bounds) { this.bounds.set(bounds); } public void layoutClickBounds(RectF bounds) { @@ -1309,6 +1665,7 @@ protected void draw(Canvas canvas) { if (selectT > 0) { backgroundPaint.setStrokeWidth(dpf2(2)); + 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), @@ -1329,26 +1686,50 @@ public void setPressed(boolean pressed) { } } - private int currentAccount; + private final int type; + private final int currentAccount; private ColorButton[] buttons; - public PeerColorGrid(Context context, int currentAccount) { + public PeerColorGrid(Context context, int type, int currentAccount, Theme.ResourcesProvider resourcesProvider) { super(context); + this.type = type; this.currentAccount = currentAccount; + this.resourcesProvider = resourcesProvider; + } + + public void updateColors() { + if (buttons == null) return; + final MessagesController mc = MessagesController.getInstance(currentAccount); + final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; + for (int i = 0; i < buttons.length; ++i) { + if (i < 7 && type == PAGE_NAME) { + buttons[i].id = order[i]; + buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[order[i]], resourcesProvider)); + } else { + 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)); + } + } + } + invalidate(); } + final int[] order = new int[] { 5, 3, 1, 0, 2, 4, 6 }; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); - final MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; - final int colorsCount = 7 + (peerColors == null ? 0 : peerColors.colors.size()); - final int columns = 7; + final MessagesController mc = MessagesController.getInstance(currentAccount); + final MessagesController.PeerColors peerColors = type == PAGE_NAME ? mc.peerColors : mc.profilePeerColors; + 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)); - final float horizontalSeparator = iconSize * .28947f; - final float verticalSeparator = iconSize * .315789474f; + final float horizontalSeparator = Math.min(iconSize * .28947f, dp(8)); + final float verticalSeparator = Math.min(iconSize * .315789474f, dp(11.33f)); final int rows = colorsCount / columns; final int height = (int) (iconSize * rows + verticalSeparator * (rows + 1)); @@ -1359,11 +1740,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { buttons = new ColorButton[colorsCount]; for (int i = 0; i < colorsCount; ++i) { buttons[i] = new ColorButton(); - buttons[i].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - if (i < 7) { - buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[i])); - } else if (peerColors != null) { - buttons[i].set(peerColors.getColor(i)); + if (peerColors != null && i >= 0 && i < peerColors.colors.size()) { + buttons[i].id = peerColors.colors.get(i).id; + buttons[i].set(peerColors.colors.get(i)); } } } @@ -1373,10 +1752,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { float x = startX, y = verticalSeparator; for (int i = 0; i < buttons.length; ++i) { AndroidUtilities.rectTmp.set(x, y, x + iconSize, y + iconSize); - buttons[i].layout(i, AndroidUtilities.rectTmp); + buttons[i].layout(AndroidUtilities.rectTmp); AndroidUtilities.rectTmp.inset(-horizontalSeparator / 2, -verticalSeparator / 2); buttons[i].layoutClickBounds(AndroidUtilities.rectTmp); - buttons[i].setSelected(i == selectedColorId, false); + buttons[i].setSelected(buttons[i].id == selectedColorId, false); if (i % columns == (columns - 1)) { x = startX; @@ -1388,6 +1767,13 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } + 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) { if (buttons != null) { @@ -1395,15 +1781,18 @@ protected void dispatchDraw(Canvas canvas) { buttons[i].draw(canvas); } } - canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), Theme.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(i == colorId, true); + buttons[i].setSelected(buttons[i].id == colorId, animated); } } } @@ -1468,6 +1857,37 @@ public boolean dispatchTouchEvent(MotionEvent event) { } } + 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) { @@ -1476,20 +1896,42 @@ public static PeerColorDrawable from(int currentAccount, int colorId) { } MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors; MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); - return from(peerColor); + return from(peerColor, false); + } + + public static PeerColorDrawable fromProfile(int currentAccount, int colorId) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + return from(peerColor, true); } - public static PeerColorDrawable from(MessagesController.PeerColor peerColor) { + public static PeerColorDrawable from(MessagesController.PeerColor peerColor, boolean fromProfile) { if (peerColor == null) { return new PeerColorDrawable(0, 0, 0); } - return new PeerColorDrawable(peerColor.getColor1(), peerColor.getColor2(), peerColor.getColor3()); + return new PeerColorDrawable(peerColor.getColor1(), !fromProfile || peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor2() : peerColor.getColor1(), fromProfile ? peerColor.getColor1() : peerColor.getColor3()); + } + + private float radius = dpf2(21.333f / 2f); + + public PeerColorDrawable setRadius(float r) { + this.radius = r; + initPath(); + return this; } - private final int diameter = AndroidUtilities.dp(21.333f); - private final int radius = diameter / 2; + public PeerColorDrawable stroke(float width, int color) { + if (strokePaint == null) { + strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + strokePaint.setStyle(Paint.Style.STROKE); + } + strokePaint.setStrokeWidth(width); + strokePaint.setColor(color); + return this; + } private final boolean hasColor3; + private Paint strokePaint; private final Paint color1Paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint color2Paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint color3Paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -1502,10 +1944,16 @@ public PeerColorDrawable(int color1, int color2, int color3) { color2Paint.setColor(color2); color3Paint.setColor(color3); + initPath(); + } + + private void initPath() { + clipCirclePath.rewind(); clipCirclePath.addCircle(radius, radius, radius, Path.Direction.CW); - color2Path.moveTo(diameter, 0); - color2Path.lineTo(diameter, diameter); - color2Path.lineTo(0, diameter); + color2Path.rewind(); + color2Path.moveTo(radius * 2, 0); + color2Path.lineTo(radius * 2, radius * 2); + color2Path.lineTo(0, radius * 2); color2Path.close(); } @@ -1513,6 +1961,9 @@ public PeerColorDrawable(int color1, int color2, int color3) { public void draw(@NonNull Canvas canvas) { canvas.save(); canvas.translate(getBounds().centerX() - radius, getBounds().centerY() - radius); + if (strokePaint != null) { + canvas.drawCircle(radius, radius, radius, strokePaint); + } canvas.clipPath(clipCirclePath); canvas.drawPaint(color1Paint); canvas.drawPath(color2Path, color2Paint); @@ -1537,12 +1988,531 @@ public int getOpacity() { @Override public int getIntrinsicHeight() { - return diameter; + return (int) (radius * 2); } @Override public int getIntrinsicWidth() { - return diameter; + return (int) (radius * 2); + } + } + + public static class ColoredActionBar extends View { + + private int defaultColor; + private final Theme.ResourcesProvider resourcesProvider; + + public ColoredActionBar(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + defaultColor = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); + setColor(-1, -1, false); + } + + public void setColor(int currentAccount, int colorId, boolean animated) { + isDefault = false; + if (colorId < 0 || currentAccount < 0) { + isDefault = true; + 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 = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); + } + } + if (!animated) { + color1Animated.set(color1, true); + color2Animated.set(color2, true); + } + invalidate(); + } + + private float progressToGradient = 0; + public void setProgressToGradient(float progress) { + if (Math.abs(progressToGradient - progress) > 0.001f) { + progressToGradient = progress; + onUpdateColor(); + invalidate(); + } + } + + public boolean isDefault; + public int color1, color2; + private final AnimatedColor color1Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedColor color2Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private int backgroundGradientColor1, backgroundGradientColor2, backgroundGradientHeight; + private LinearGradient backgroundGradient; + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + protected void onUpdateColor() { + + } + + @Override + protected void dispatchDraw(Canvas canvas) { + final int color1 = color1Animated.set(this.color1); + final int color2 = color2Animated.set(this.color2); + if (backgroundGradient == null || backgroundGradientColor1 != color1 || backgroundGradientColor2 != color2 || backgroundGradientHeight != getHeight()) { + backgroundGradient = new LinearGradient(0, 0, 0, backgroundGradientHeight = getHeight(), new int[] { backgroundGradientColor2 = color2, backgroundGradientColor1 = color1 }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + backgroundPaint.setShader(backgroundGradient); + onUpdateColor(); + } + if (progressToGradient < 1) { + canvas.drawColor(defaultColor); + } + if (progressToGradient > 0) { + backgroundPaint.setAlpha((int) (0xFF * progressToGradient)); + canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint); + } + } + + protected boolean ignoreMeasure; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, ignoreMeasure ? heightMeasureSpec : MeasureSpec.makeMeasureSpec(AndroidUtilities.statusBarHeight + dp(144), MeasureSpec.EXACTLY)); + } + + public void updateColors() { + defaultColor = Theme.getColor(Theme.key_actionBarDefault, resourcesProvider); + onUpdateColor(); + invalidate(); + } + + public int getColor() { + return ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefault, resourcesProvider), ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), progressToGradient); + } + + 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(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 ? + Theme.getColor(Theme.key_windowBackgroundWhiteBlueIcon, resourcesProvider) : + Theme.adaptHSV(ColorUtils.blendARGB(color1Animated.get(), color2Animated.get(), .75f), +.08f, -.08f), + progressToGradient + ) + ); + } + } + + 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, int currentAccount, long dialogId, Theme.ResourcesProvider resourcesProvider) { + super(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)); + titleView.setScrollNonFitText(true); + addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 97, 0, 16, 50.33f)); + + subtitleView = new SimpleTextView(context); + subtitleView.setTextSize(14); + subtitleView.setTextColor(0x80FFFFFF); + subtitleView.setScrollNonFitText(true); + addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 97, 0, 16, 30.66f)); + + imageReceiver.setRoundRadius(dp(54)); + CharSequence title; + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + title = chat == null ? "" : chat.title; + + avatarDrawable.setInfo(currentAccount, chat); + imageReceiver.setForUserOrChat(chat, avatarDrawable); + } else { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + title = UserObject.getUserName(user); + + avatarDrawable.setInfo(currentAccount, user); + imageReceiver.setForUserOrChat(user, avatarDrawable); + } + try { + title = Emoji.replaceEmoji(title, null, false); + } catch (Exception ignore) {} + + titleView.setText(title); + + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); + if (chatFull != null && chatFull.participants_count > 0) { + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.formatPluralStringComma("Subscribers", chatFull.participants_count)); + } else { + subtitleView.setText(LocaleController.formatPluralStringComma("Members", chatFull.participants_count)); + } + } else if (chat != null && chat.participants_count > 0) { + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.formatPluralStringComma("Subscribers", chat.participants_count)); + } else { + subtitleView.setText(LocaleController.formatPluralStringComma("Members", chat.participants_count)); + } + } else { + final boolean isPublic = ChatObject.isPublic(chat); + if (ChatObject.isChannelAndNotMegaGroup(chat)) { + subtitleView.setText(LocaleController.getString(isPublic ? R.string.ChannelPublic : R.string.ChannelPrivate).toLowerCase()); + } else { + subtitleView.setText(LocaleController.getString(isPublic ? R.string.MegaPublic : R.string.MegaPrivate).toLowerCase()); + } + } + } else { + subtitleView.setText(LocaleController.getString(R.string.Online)); + } + + setWillNotDraw(false); + } + + public void 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 { + color1 = getThemedColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(colorId)]); + color2 = getThemedColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(colorId)]); + } + avatarDrawable.setColor(color1, color2); + invalidate(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + emoji.attach(); + imageReceiver.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + emoji.detach(); + 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); + } else { + subtitleView.setTextColor(Theme.changeColorAccent(getThemedColor(Theme.key_actionBarDefault), accentColor, getThemedColor(Theme.key_avatar_subtitleInProfileBlue), isDark, accentColor)); + } + titleView.setTextColor(Color.WHITE); + } else { + final int emojiColor; + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + emoji.setColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText)); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emoji.setColor(Theme.multAlpha(getThemedColor(Theme.key_actionBarDefaultTitle), .5f)); + } else { + emoji.setColor(adaptProfileEmojiColor(getThemedColor(Theme.key_actionBarDefault))); + } + statusEmoji.setColor(Theme.getColor(Theme.key_profile_verifiedBackground, resourcesProvider)); + subtitleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubtitle)); + titleView.setTextColor(getThemedColor(Theme.key_actionBarDefaultTitle)); + } + + storyGradient.setColorId(colorId, animated); + invalidate(); + } + + public void setEmoji(long docId, boolean animated) { + if (docId == 0) { + emoji.set((Drawable) null, animated); + } else { + emoji.set(docId, animated); + } + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(lastColorId); + 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(getThemedColor(Theme.key_windowBackgroundWhiteBlueText)); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emoji.setColor(Theme.multAlpha(Theme.getColor(Theme.key_actionBarDefaultTitle), .5f)); + } else { + 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)); + } + } + + private final RectF rectF = new RectF(); + @Override + protected void dispatchDraw(Canvas canvas) { + rectF.set(dp(20.33f), getHeight() - dp(25.33f + 53.33f), dp(20.33f) + dp(53.33f), getHeight() - dp(25.33f)); + imageReceiver.setImageCoords(rectF); + imageReceiver.draw(canvas); + + canvas.drawCircle(rectF.centerX(), rectF.centerY(), rectF.width() / 2f + dp(4), storyGradient.getPaint(rectF)); + + drawProfileIconPattern(getWidth() - dp(46), getHeight(), 1f, (x, y, sz, alpha) -> { + emoji.setAlpha((int) (0xFF * alpha)); + emoji.setBounds((int) (x - sz * .45f), (int) (y - sz * .45f), (int) (x + sz * .45f), (int) (y + sz * .45f)); + emoji.draw(canvas); + }); + + super.dispatchDraw(canvas); + } + } + + public static int adaptProfileEmojiColor(int color) { + final boolean isDark = AndroidUtilities.computePerceivedBrightness(color) < .2f; + return Theme.adaptHSV(color, +.5f, isDark ? +.28f : -.28f); + } + + public static final float PARTICLE_SIZE_DP = 24; + public static final int PARTICLES_COUNT = 15; + public static final float GOLDEN_RATIO_ANGLE = 139f; + public static final float FILL_SCALE = 1; + + public static void drawSunflowerPattern(float cx, float cy, Utilities.Callback3 draw) { + drawSunflowerPattern(PARTICLES_COUNT, cx, cy, 30, dp(PARTICLE_SIZE_DP) * .7f, 1.4f, GOLDEN_RATIO_ANGLE, draw); + } + + public static void drawSunflowerPattern(int count, float cx, float cy, float anglestart, float scale, float scale2, float angle, Utilities.Callback3 draw) { + for (int i = 1; i <= count; ++i) { + final float a = anglestart + i * angle; + final float r = (float) (Math.sqrt(i * scale2) * scale); + final float x = (float) (cx + Math.cos(a / 180f * Math.PI) * r) + (i == 3 ? .3f * scale : 0); + final float y = (float) (cy + Math.sin(a / 180f * Math.PI) * r) + (i == 3 ? -.5f * scale : 0); + draw.run(x, y, (float) Math.sqrt(1f - (float) i / count)); + } + } + + private final static float[] particles = { + -18, -24.66f, 24, .4f, + 5.33f, -53, 28, .38f, + -4, -86, 19, .18f, + 31, -30, 21, .35f, + 12, -3, 24, .18f, + 30, -73, 19, .3f, + 43, -101, 16, .1f, + -50, 1.33f, 20, .22f, + -58, -33, 24, .22f, + -35, -62, 25, .22f, + -59, -88, 19, .18f, + -86, -61, 19, .1f, + -90, -14.33f, 19.66f, .18f + }; + public static void drawProfileIconPattern(float cx, float cy, float scale, Utilities.Callback4 draw) { + for (int i = 0; i < particles.length; i += 4) { + draw.run( + cx + dp(particles[i]) * scale, + cy + dp(particles[i + 1]) * scale, + dpf2(particles[i + 2]), + particles[i + 3] + ); + } + } + + private View changeDayNightView; + private float changeDayNightViewProgress; + private ValueAnimator changeDayNightViewAnimator; + + @SuppressLint("NotifyDataSetChanged") + public void toggleTheme() { + FrameLayout decorView1 = (FrameLayout) getParentActivity().getWindow().getDecorView(); + Bitmap bitmap = Bitmap.createBitmap(decorView1.getWidth(), decorView1.getHeight(), Bitmap.Config.ARGB_8888); + Canvas bitmapCanvas = new Canvas(bitmap); + dayNightItem.setAlpha(0f); + decorView1.draw(bitmapCanvas); + dayNightItem.setAlpha(1f); + + Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + + Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapPaint.setFilterBitmap(true); + int[] position = new int[2]; + dayNightItem.getLocationInWindow(position); + float x = position[0]; + float y = position[1]; + float cx = x + dayNightItem.getMeasuredWidth() / 2f; + float cy = y + dayNightItem.getMeasuredHeight() / 2f; + + float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) + AndroidUtilities.navigationBarHeight; + + Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapPaint.setShader(bitmapShader); + changeDayNightView = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (isDark) { + if (changeDayNightViewProgress > 0f) { + bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint); + } + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } else { + canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint); + } + canvas.save(); + canvas.translate(x, y); + dayNightItem.draw(canvas); + canvas.restore(); + } + }; + changeDayNightView.setOnTouchListener((v, event) -> true); + changeDayNightViewProgress = 0f; + changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f); + changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean changedNavigationBarColor = false; + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue(); + changeDayNightView.invalidate(); + if (!changedNavigationBarColor && changeDayNightViewProgress > .5f) { + changedNavigationBarColor = true; + } + } + }); + changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (changeDayNightView != null) { + if (changeDayNightView.getParent() != null) { + ((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView); + } + changeDayNightView = null; + } + changeDayNightViewAnimator = null; + super.onAnimationEnd(animation); + } + }); + changeDayNightViewAnimator.setDuration(400); + changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad); + changeDayNightViewAnimator.start(); + + decorView1.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + AndroidUtilities.runOnUIThread(() -> { + isDark = !isDark; + updateThemeColors(); + setForceDark(isDark, true); + updateColors(); + }); + } + + @Override + public boolean isLightStatusBar() { + if (colorBar == null) { + return super.isLightStatusBar(); + } + return ColorUtils.calculateLuminance(colorBar.getColor()) > 0.7f; + } + + public void updateLightStatusBar() { + if (getParentActivity() == null) return; + AndroidUtilities.setLightStatusBar(getParentActivity().getWindow(), isLightStatusBar()); + } + + private boolean forceDark = isDark; + public void setForceDark(boolean isDark, boolean playAnimation) { + if (forceDark == isDark) { + return; + } + forceDark = isDark; + if (playAnimation) { + sunDrawable.setCustomEndFrame(isDark ? sunDrawable.getFramesCount() : 0); + if (sunDrawable != null) { + sunDrawable.start(); + } + } else { + int frame = isDark ? sunDrawable.getFramesCount() - 1 : 0; + sunDrawable.setCurrentFrame(frame, false, true); + sunDrawable.setCustomEndFrame(frame); + if (dayNightItem != null) { + dayNightItem.invalidate(); + } } } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index b4c0b0fee4..c0dc7f9b47 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -6169,7 +6169,7 @@ protected boolean customBlur() { } @Override - protected boolean ignoreTouches() { + protected boolean ignoreTouches(float x, float y) { return !keyboardShown && currentEditMode != EDIT_MODE_NONE; } @@ -6284,7 +6284,7 @@ public void setTranslationY(float translationY) { 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; @@ -7212,7 +7212,7 @@ private void showShareAlert(ArrayList messages) { parentChatActivity.getFragmentView().requestLayout(); } final boolean finalOpenKeyboardOnShareAlertClose = openKeyboardOnShareAlertClose; - ShareAlert alert = new ShareAlert(parentActivity, parentChatActivity, messages, null, null, false, null, null, false, true, null) { + ShareAlert alert = new ShareAlert(parentActivity, parentChatActivity, messages, null, null, false, null, null, false, true, false, null) { @Override protected void onSend(LongSparseArray dids, int count, TLRPC.TL_forumTopic topic) { AndroidUtilities.runOnUIThread(() -> { @@ -11079,6 +11079,10 @@ public void onAnimationEnd(Animator animation) { updateMinMax(scale); padImageForHorizontalInsets = true; containerView.invalidate(); + + if (placeProvider == null || !placeProvider.closeKeyboard()) { + makeFocusable(); + } } }); imageMoveAnimation.start(); @@ -12177,7 +12181,7 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogPhotosUpdate, dialogPhotos); } } - if (currentMessageObject != null && (currentMessageObject.isVideo() || currentMessageObject.isGif()) || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document)) || (pageBlocksAdapter != null && (pageBlocksAdapter.isVideo(index) || pageBlocksAdapter.isHardwarePlayer(index))) || (sendPhotoType == SELECT_TYPE_NO_SELECT && ((MediaController.PhotoEntry)imagesArrLocals.get(index)).isVideo)) { + if (currentMessageObject != null && (currentMessageObject.isVideo() || (currentMessageObject.isGif() && NekoConfig.takeGIFasVideo.Bool())) || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document)) || (pageBlocksAdapter != null && (pageBlocksAdapter.isVideo(index) || pageBlocksAdapter.isHardwarePlayer(index))) || (sendPhotoType == SELECT_TYPE_NO_SELECT && ((MediaController.PhotoEntry)imagesArrLocals.get(index)).isVideo)) { playerAutoStarted = true; onActionClick(false); } else if (!imagesArrLocals.isEmpty()) { @@ -13795,8 +13799,10 @@ private void checkProgress(int a, boolean scroll, boolean animated) { return; } ImageLocation location = imagesArrLocationsVideo.get(index); - f1 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), false); - f2 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), true); + if (location != null) { + f1 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), false); + f2 = FileLoader.getInstance(currentAccount).getPathToAttach(location.location, getFileLocationExt(location), true); + } } else if (currentSecureDocument != null) { if (index < 0 || index >= secureDocuments.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index ef274bc2a6..5a44d25ce3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -397,7 +397,7 @@ public void didPressAttachButton() { } @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 cf4ad88ec5..a830ebba72 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -154,6 +154,8 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING = 19; public static final int PREMIUM_FEATURE_STORIES_PRIORITY_ORDER = 20; public static final int PREMIUM_FEATURE_STORIES_CAPTION = 21; + public final static int PREMIUM_FEATURE_WALLPAPER = 22; + public final static int PREMIUM_FEATURE_NAME_COLOR = 23; private int statusBarHeight; private int firstViewHeight; @@ -223,6 +225,10 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_STORIES_PRIORITY_ORDER; case "stories__caption": return PREMIUM_FEATURE_STORIES_CAPTION; + case "wallpapers": + return PREMIUM_FEATURE_WALLPAPER; + case "peer_colors": + return PREMIUM_FEATURE_NAME_COLOR; } return -1; } @@ -273,6 +279,10 @@ public static String featureTypeToServerString(int type) { return "stories__priority_order"; case PREMIUM_FEATURE_STORIES_CAPTION: return "stories__caption"; + case PREMIUM_FEATURE_WALLPAPER: + return "wallpapers"; + case PREMIUM_FEATURE_NAME_COLOR: + return "peer_colors"; } return null; } @@ -347,7 +357,7 @@ public View createView(Context context) { public boolean dispatchTouchEvent(MotionEvent ev) { float iconX = backgroundView.getX() + backgroundView.imageFrameLayout.getX(); float iconY = backgroundView.getY() + backgroundView.imageFrameLayout.getY(); - AndroidUtilities.rectTmp.set(iconX, iconY, iconX + backgroundView.imageView.getMeasuredWidth(), iconY + backgroundView.imageView.getMeasuredHeight()); + AndroidUtilities.rectTmp.set(iconX, iconY, iconX + (backgroundView.imageView == null ? 0 : backgroundView.imageView.getMeasuredWidth()), iconY + (backgroundView.imageView == null ? 0 : backgroundView.imageView.getMeasuredHeight())); if ((AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY()) || iconInterceptedTouch) && !listView.scrollingByUser) { ev.offsetLocation(-iconX, -iconY); if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) { @@ -632,24 +642,26 @@ public static void fillPremiumFeaturesList(ArrayList premium MessagesController messagesController = MessagesController.getInstance(currentAccount); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_LIMITS, R.drawable.msg_premium_limits, LocaleController.getString("PremiumPreviewLimits", R.string.PremiumPreviewLimits), LocaleController.formatString("PremiumPreviewLimitsDescription", R.string.PremiumPreviewLimitsDescription, messagesController.channelsLimitPremium, messagesController.dialogFiltersLimitPremium, messagesController.dialogFiltersPinnedLimitPremium, messagesController.publicLinksLimitPremium, 4))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, applyNewSpan(LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories)), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_UPLOAD_LIMIT, R.drawable.msg_premium_uploads, LocaleController.getString("PremiumPreviewUploads", R.string.PremiumPreviewUploads), LocaleController.getString("PremiumPreviewUploadsDescription", R.string.PremiumPreviewUploadsDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_DOWNLOAD_SPEED, R.drawable.msg_premium_speed, LocaleController.getString("PremiumPreviewDownloadSpeed", R.string.PremiumPreviewDownloadSpeed), LocaleController.getString("PremiumPreviewDownloadSpeedDescription", R.string.PremiumPreviewDownloadSpeedDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_VOICE_TO_TEXT, R.drawable.msg_premium_voice, LocaleController.getString("PremiumPreviewVoiceToText", R.string.PremiumPreviewVoiceToText), LocaleController.getString("PremiumPreviewVoiceToTextDescription", R.string.PremiumPreviewVoiceToTextDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADS, R.drawable.msg_premium_ads, LocaleController.getString("PremiumPreviewNoAds", R.string.PremiumPreviewNoAds), LocaleController.getString("PremiumPreviewNoAdsDescription", R.string.PremiumPreviewNoAdsDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_REACTIONS, R.drawable.msg_premium_reactions, LocaleController.getString("PremiumPreviewReactions2", R.string.PremiumPreviewReactions2), LocaleController.getString("PremiumPreviewReactions2Description", R.string.PremiumPreviewReactions2Description))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STICKERS, R.drawable.msg_premium_stickers, LocaleController.getString("PremiumPreviewStickers", R.string.PremiumPreviewStickers), LocaleController.getString("PremiumPreviewStickersDescription", R.string.PremiumPreviewStickersDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_EMOJI, R.drawable.msg_premium_emoji, LocaleController.getString("PremiumPreviewEmoji", R.string.PremiumPreviewEmoji), LocaleController.getString("PremiumPreviewEmojiDescription", R.string.PremiumPreviewEmojiDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT, R.drawable.msg_premium_tools, LocaleController.getString("PremiumPreviewAdvancedChatManagement", R.string.PremiumPreviewAdvancedChatManagement), LocaleController.getString("PremiumPreviewAdvancedChatManagementDescription", R.string.PremiumPreviewAdvancedChatManagementDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_PROFILE_BADGE, R.drawable.msg_premium_badge, LocaleController.getString("PremiumPreviewProfileBadge", R.string.PremiumPreviewProfileBadge), LocaleController.getString("PremiumPreviewProfileBadgeDescription", R.string.PremiumPreviewProfileBadgeDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString("PremiumPreviewAnimatedProfiles", R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString("PremiumPreviewAnimatedProfilesDescription", R.string.PremiumPreviewAnimatedProfilesDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString("PremiumPreviewAppIcon", R.string.PremiumPreviewAppIcon), LocaleController.getString("PremiumPreviewAppIconDescription", R.string.PremiumPreviewAppIconDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.msg_premium_status, LocaleController.getString("PremiumPreviewEmojiStatus", R.string.PremiumPreviewEmojiStatus), LocaleController.getString("PremiumPreviewEmojiStatusDescription", R.string.PremiumPreviewEmojiStatusDescription))); - premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString("PremiumPreviewTranslations", R.string.PremiumPreviewTranslations), LocaleController.getString("PremiumPreviewTranslationsDescription", R.string.PremiumPreviewTranslationsDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_REACTIONS, R.drawable.msg_premium_reactions, LocaleController.getString(R.string.PremiumPreviewReactions2), LocaleController.getString(R.string.PremiumPreviewReactions2Description))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STICKERS, R.drawable.msg_premium_stickers, LocaleController.getString(R.string.PremiumPreviewStickers), LocaleController.getString(R.string.PremiumPreviewStickersDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_EMOJI, R.drawable.msg_premium_emoji, LocaleController.getString(R.string.PremiumPreviewEmoji), LocaleController.getString(R.string.PremiumPreviewEmojiDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT, R.drawable.msg_premium_tools, LocaleController.getString(R.string.PremiumPreviewAdvancedChatManagement), LocaleController.getString(R.string.PremiumPreviewAdvancedChatManagementDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_PROFILE_BADGE, R.drawable.msg_premium_badge, LocaleController.getString(R.string.PremiumPreviewProfileBadge), LocaleController.getString(R.string.PremiumPreviewProfileBadgeDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString(R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString(R.string.PremiumPreviewAnimatedProfilesDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString(R.string.PremiumPreviewAppIcon), LocaleController.getString(R.string.PremiumPreviewAppIconDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.premium_status, LocaleController.getString(R.string.PremiumPreviewEmojiStatus), LocaleController.getString(R.string.PremiumPreviewEmojiStatusDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString(R.string.PremiumPreviewTranslations), LocaleController.getString(R.string.PremiumPreviewTranslationsDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_WALLPAPER, R.drawable.premium_wallpaper, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewWallpaper)), LocaleController.getString(R.string.PremiumPreviewWallpaperDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_NAME_COLOR, R.drawable.premium_colors, applyNewSpan(LocaleController.getString(R.string.PremiumPreviewProfileColor)), LocaleController.getString(R.string.PremiumPreviewProfileColorDescription))); if (messagesController.premiumFeaturesTypesToPosition.size() > 0) { for (int i = 0; i < premiumFeatures.size(); i++) { - if (messagesController.premiumFeaturesTypesToPosition.get(premiumFeatures.get(i).type, -1) == -1) { + if (messagesController.premiumFeaturesTypesToPosition.get(premiumFeatures.get(i).type, -1) == -1 && !BuildVars.DEBUG_PRIVATE_VERSION) { premiumFeatures.remove(i); i--; } @@ -673,7 +685,7 @@ public static CharSequence applyNewSpan(String str) { } private void updateBackgroundImage() { - if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0) { + if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0 || backgroundView == null || backgroundView.imageView == null) { return; } gradientTools.gradientMatrix(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight(), 0, 0); @@ -760,7 +772,7 @@ public boolean isSwipeBackEnabled(MotionEvent event) { @Override public boolean onFragmentCreate() { - if (getMessagesController().premiumLocked) { + if (getMessagesController().premiumFeaturesBlocked()) { return false; } NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.billingProductDetailsUpdated); @@ -1346,21 +1358,27 @@ public boolean isLightStatusBar() { @Override public void onResume() { super.onResume(); - backgroundView.imageView.setPaused(false); - backgroundView.imageView.setDialogVisible(false); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setPaused(false); + backgroundView.imageView.setDialogVisible(false); + } particlesView.setPaused(false); } @Override public void onPause() { super.onPause(); - backgroundView.imageView.setDialogVisible(true); - particlesView.setPaused(true); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setDialogVisible(true); + } + if (particlesView != null) { + particlesView.setPaused(true); + } } @Override public boolean canBeginSlide() { - return !backgroundView.imageView.touched; + return backgroundView == null || backgroundView.imageView == null || !backgroundView.imageView.touched; } @Override @@ -1378,11 +1396,13 @@ private void updateColors() { } actionBar.setItemsColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), false); actionBar.setItemsBackgroundColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay), 60), false); - backgroundView.titleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); - backgroundView.subtitleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); particlesView.drawable.updateColors(); - if (backgroundView.imageView.mRenderer != null) { - backgroundView.imageView.mRenderer.updateColors(); + if (backgroundView != null) { + backgroundView.titleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + backgroundView.subtitleView.setTextColor(Theme.getColor(Theme.key_premiumGradientBackgroundOverlay)); + if (backgroundView.imageView != null && backgroundView.imageView.mRenderer != null) { + backgroundView.imageView.mRenderer.updateColors(); + } } updateBackgroundImage(); } @@ -1423,7 +1443,9 @@ protected void onDialogDismiss(Dialog dialog) { private void updateDialogVisibility(boolean isVisible) { if (isVisible != isDialogVisible) { isDialogVisible = isVisible; - backgroundView.imageView.setDialogVisible(isVisible); + if (backgroundView != null && backgroundView.imageView != null) { + backgroundView.imageView.setDialogVisible(isVisible); + } particlesView.setPaused(isVisible); contentView.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index 3e6221e2bb..64e9e1e4cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -651,7 +651,7 @@ private void updateRows(boolean notify) { 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 b692c67efa..f27dc2e8e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -9,6 +9,7 @@ package org.telegram.ui; import static androidx.core.view.ViewCompat.TYPE_TOUCH; +import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.ContactsController.PRIVACY_RULES_TYPE_ADDED_BY_PHONE; import android.Manifest; @@ -35,6 +36,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -43,7 +45,9 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -178,8 +182,10 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioPlayerAlert; import org.telegram.ui.Components.AutoDeletePopupWrapper; @@ -218,6 +224,7 @@ 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; @@ -301,6 +308,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 SimpleTextView idTextView; @@ -308,12 +316,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private AnimatorSet writeButtonAnimation; // private AnimatorSet qrItemAnimation; private Drawable lockIconDrawable; - private Drawable verifiedDrawable; - private Drawable premiumStarDrawable; + private final Drawable[] verifiedDrawable = new Drawable[2]; + private final Drawable[] premiumStarDrawable = new Drawable[2]; private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable[] emojiStatusDrawable = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable[2]; - private Drawable verifiedCheckDrawable; - private CrossfadeDrawable verifiedCrossfadeDrawable; - private CrossfadeDrawable premiumCrossfadeDrawable; + private final Drawable[] verifiedCheckDrawable = new Drawable[2]; + private final CrossfadeDrawable[] verifiedCrossfadeDrawable = new CrossfadeDrawable[2]; + private final CrossfadeDrawable[] premiumCrossfadeDrawable = new CrossfadeDrawable[2]; private ScamDrawable scamDrawable; private UndoView undoView; private OverlaysView overlaysView; @@ -321,6 +329,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private StickerEmptyView emptyView; private boolean sharedMediaLayoutAttached; private SharedMediaLayout.SharedMediaPreloader sharedMediaPreloader; + private boolean preloadedChannelEmojiStatuses; + + private View blurredView; private RLottieDrawable cameraDrawable; private RLottieDrawable cellCameraDrawable; @@ -398,6 +409,7 @@ public void setAlpha(int a) { private boolean needSendMessage; private boolean hasVoiceChatItem; private boolean isTopic; + private boolean openSimilar; private boolean scrolling; @@ -503,6 +515,7 @@ public void setAlpha(int a) { private final static int qr_button = 37; // private final static int gift_premium = 38; private final static int channel_stories = 39; + private final static int edit_color = 40; private Rect rect = new Rect(); @@ -565,6 +578,7 @@ public void setAlpha(int a) { private int addToGroupButtonRow; private int addToGroupInfoRow; private int premiumRow; + private int premiumGiftingRow; private int premiumSectionsRow; private int settingsTimerRow; @@ -578,6 +592,7 @@ public void setAlpha(int a) { private int subscribersRow; private int subscribersRequestsRow; private int administratorsRow; + private int settingsRow; private int blockedUsersRow; private int membersSectionRow; @@ -895,6 +910,78 @@ public void setBackgroundColor(int color) { } } + private boolean hasColorById; + private final AnimatedFloat hasColorAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + public int color1, color2; + private final AnimatedColor color1Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedColor color2Animated = new AnimatedColor(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private int backgroundGradientColor1, backgroundGradientColor2, backgroundGradientHeight; + private LinearGradient backgroundGradient; + private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public void setBackgroundColorId(MessagesController.PeerColor peerColor, boolean animated) { + if (peerColor != null) { + hasColorById = true; + color1 = peerColor.getBgColor1(Theme.isCurrentThemeDark()); + color2 = peerColor.getBgColor2(Theme.isCurrentThemeDark()); + emojiColor = PeerColorActivity.adaptProfileEmojiColor(color1); + } else { + hasColorById = false; + if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) > .8f) { + emojiColor = getThemedColor(Theme.key_windowBackgroundWhiteBlueText); + } else if (AndroidUtilities.computePerceivedBrightness(getThemedColor(Theme.key_actionBarDefault)) < .2f) { + emojiColor = Theme.multAlpha(getThemedColor(Theme.key_actionBarDefaultTitle), .5f); + } else { + emojiColor = PeerColorActivity.adaptProfileEmojiColor(getThemedColor(Theme.key_actionBarDefault)); + } + } + if (!animated) { + color1Animated.set(color1, true); + color2Animated.set(color2, true); + } + invalidate(); + } + + private int emojiColor; + private final AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji = new AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable(this, false, dp(20), AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + emoji.attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + emoji.detach(); + } + + public final AnimatedFloat emojiLoadedT = new AnimatedFloat(this, 0, 440, CubicBezierInterpolator.EASE_OUT_QUINT); + + private boolean hasEmoji; + public void setBackgroundEmojiId(long emojiId, boolean animated) { + emoji.set(emojiId, animated); + emoji.setColor(emojiColor); + hasEmoji = hasEmoji || emojiId != 0 && emojiId != -1; + invalidate(); + } + + private boolean emojiLoaded; + private boolean isEmojiLoaded() { + if (emojiLoaded) { + return true; + } + if (emoji != null && emoji.getDrawable() instanceof AnimatedEmojiDrawable) { + AnimatedEmojiDrawable drawable = (AnimatedEmojiDrawable) emoji.getDrawable(); + if (drawable.getImageReceiver() != null && drawable.getImageReceiver().hasImageLoaded()) { + return emojiLoaded = true; + } + } + return false; + } + @Override protected void onDraw(Canvas canvas) { final int height = ActionBar.getCurrentActionBarHeight() + (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0); @@ -913,7 +1000,36 @@ protected void onDraw(Canvas canvas) { } } paint.setColor(currentColor); - canvas.drawRect(0, 0, getMeasuredWidth(), y1, paint); + final int color1 = color1Animated.set(this.color1); + final int color2 = color2Animated.set(this.color2); + final int gradientHeight = AndroidUtilities.statusBarHeight + AndroidUtilities.dp(144); + if (backgroundGradient == null || backgroundGradientColor1 != color1 || backgroundGradientColor2 != color2 || backgroundGradientHeight != gradientHeight) { + backgroundGradient = new LinearGradient(0, 0, 0, backgroundGradientHeight = gradientHeight, new int[] { backgroundGradientColor2 = color2, backgroundGradientColor1 = color1 }, new float[] { 0, 1 }, Shader.TileMode.CLAMP); + backgroundPaint.setShader(backgroundGradient); + } + final float progressToGradient = (playProfileAnimation == 0 ? 1f : avatarAnimationProgress) * hasColorAnimated.set(hasColorById); + if (progressToGradient < 1) { + canvas.drawRect(0, 0, getMeasuredWidth(), y1, paint); + } + if (progressToGradient > 0) { + backgroundPaint.setAlpha((int) (0xFF * progressToGradient)); + canvas.drawRect(0, 0, getMeasuredWidth(), y1, backgroundPaint); + } + if (hasEmoji) { + final float loadedScale = emojiLoadedT.set(isEmojiLoaded()); + if (loadedScale > 0) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), y1); + final float cx = getMeasuredWidth() - dp(46); + final float cy = ((actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + dp(144)) - (1f - extraHeight / dp(88)) * dp(33); + PeerColorActivity.drawProfileIconPattern(cx, cy, 1f + (extraHeight / dp(88) - 1f) * .2f, (x, y, sz, alpha) -> { + emoji.setAlpha((int) (0xFF * alpha * Math.min(1f, extraHeight / dp(88)))); + emoji.setBounds((int) (x - sz * .45f), (int) (y - sz * .45f), (int) (x + sz * .45f), (int) (y + sz * .45f)); + emoji.draw(canvas); + }); + canvas.restore(); + } + } if (previousTransitionFragment != null) { ActionBar actionBar = previousTransitionFragment.getActionBar(); ActionBarMenu menu = actionBar.menu; @@ -1647,6 +1763,7 @@ public boolean onFragmentCreate() { userId = arguments.getLong("user_id", 0); chatId = arguments.getLong("chat_id", 0); topicId = arguments.getInt("topic_id", 0); + openSimilar = arguments.getBoolean("similar", false); isTopic = topicId != 0; banFromGroup = arguments.getLong("ban_chat_id", 0); reportReactionMessageId = arguments.getInt("report_reaction_message_id", 0); @@ -1925,7 +2042,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto actionBar.setColorFilterMode(PorterDuff.Mode.SRC_IN); actionBar.setForceSkipTouches(true); actionBar.setBackgroundColor(Color.TRANSPARENT); - actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); actionBar.setBackButtonDrawable(new BackDrawable(false)); actionBar.setCastShadows(false); @@ -2352,6 +2469,8 @@ public void didChangeOwner(TLRPC.User user) { } } else if (id == edit_name) { presentFragment(new ChangeNameActivity(resourcesProvider)); + } else if (id == edit_color) { + presentFragment(new PeerColorActivity(0).startOnProfile().setOnApplied(ProfileActivity.this)); } else if (id == logout) { presentFragment(new LogoutActivity()); } else if (id == set_as_main) { @@ -2624,14 +2743,20 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (lockIconDrawable != null) { lockIconDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(1f); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(1f); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(1f); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(1f); + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(1f); + } + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(1f); } updateEmojiStatusDrawableColor(1f); - onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); + onlineTextView[1].setTextColor(0xB3FFFFFF); idTextView.setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); actionBar.setItemsColor(Color.WHITE, false); @@ -2733,7 +2858,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { top = view.getTop(); } boolean layout = false; - if (actionBar.isSearchFieldVisible() && sharedMediaRow >= 0) { + if ((actionBar.isSearchFieldVisible() || openSimilar) && sharedMediaRow >= 0) { layoutManager.scrollToPositionWithOffset(sharedMediaRow, -paddingTop); layout = true; } else if (invalidateScroll || currentPaddingTop != paddingTop) { @@ -2916,6 +3041,18 @@ protected void dispatchDraw(Canvas canvas) { scrimView.draw(canvas); canvas.restoreToCount(c); } + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (blurredView.getAlpha() != 1f) { + if (blurredView.getAlpha() != 0) { + canvas.saveLayerAlpha(blurredView.getLeft(), blurredView.getTop(), blurredView.getRight(), blurredView.getBottom(), (int) (255 * blurredView.getAlpha()), Canvas.ALL_SAVE_FLAG); + canvas.translate(blurredView.getLeft(), blurredView.getTop()); + blurredView.draw(canvas); + canvas.restore(); + } + } else { + blurredView.draw(canvas); + } + } } @Override @@ -2923,6 +3060,9 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (pinchToZoomHelper.isInOverlayMode() && (child == avatarContainer2 || child == actionBar || child == writeButton)) { return true; } + if (child == blurredView) { + return true; + } return super.drawChild(canvas, child, drawingTime); } @@ -2950,7 +3090,12 @@ protected void onDetachedFromWindow() { }; ArrayList users = chatInfo != null && chatInfo.participants != null && chatInfo.participants.participants.size() > 5 ? sortedUsers : null; - sharedMediaLayout = new SharedMediaLayout(context, did, sharedMediaPreloader, userInfo != null ? userInfo.common_chats_count : 0, sortedUsers, chatInfo, userInfo, users != null, this, this, SharedMediaLayout.VIEW_TYPE_PROFILE_ACTIVITY, resourcesProvider) { + sharedMediaLayout = new SharedMediaLayout(context, did, sharedMediaPreloader, userInfo != null ? userInfo.common_chats_count : 0, sortedUsers, chatInfo, userInfo, openSimilar ? SharedMediaLayout.TAB_RECOMMENDED_CHANNELS : users != null ? SharedMediaLayout.TAB_GROUPUSERS : -1, this, this, SharedMediaLayout.VIEW_TYPE_PROFILE_ACTIVITY, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + @Override protected void onSelectedTabChanged() { updateSelectedMediaTabText(); @@ -3528,6 +3673,8 @@ public void openExceptions() { ChatUsersActivity fragment = new ChatUsersActivity(args); fragment.setInfo(chatInfo); presentFragment(fragment); + } else if (position == settingsRow) { + editItem.performClick(); } else if (position == blockedUsersRow) { Bundle args = new Bundle(); args.putLong("chat_id", chatId); @@ -3807,6 +3954,8 @@ public void openExceptions() { builder.show(); } else if (position == premiumRow) { presentFragment(new PremiumPreviewFragment("settings")); + } else if (position == premiumGiftingRow) { + UserSelectorBottomSheet.open(); } else { ProfileActivity.this.processOnClickOrPress(position, view, x, y); } @@ -3858,7 +4007,8 @@ public boolean onItemClick(View view, int position) { 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) -> { @@ -3877,13 +4027,22 @@ public boolean onItemClick(View view, int position) { SharedPreferences sharedPreferences = ApplicationLoader.applicationContext.getSharedPreferences("systemConfig", Context.MODE_PRIVATE); sharedPreferences.edit().putBoolean("logsEnabled", BuildVars.LOGS_ENABLED).apply(); updateListAnimated(false); + 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; @@ -3898,10 +4057,12 @@ public boolean onItemClick(View view, int position) { SharedConfig.updateStealthModeSendMessageConfirm(2); SharedConfig.setStoriesReactionsLongPressHintUsed(false); SharedConfig.setStoriesIntroShown(false); + SharedConfig.setMultipleReactionsPromoShowed(false); ChatThemeController.getInstance(currentAccount).clearCache(); getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); RestrictedLanguagesSelectActivity.cleanup(); 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) { @@ -4138,6 +4299,8 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo 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); @@ -4164,6 +4327,14 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } }); + if (openSimilar) { + updateRowsIds(); + scrollToSharedMedia(); + savedScrollToSharedMedia = true; + savedScrollPosition = sharedMediaRow; + savedScrollOffset = 0; + } + if (searchItem != null) { searchListView = new RecyclerListView(context); searchListView.setVerticalScrollBarEnabled(false); @@ -4306,6 +4477,7 @@ public void didChangeOwner(TLRPC.User user) { } topView = new TopView(context); + topView.setBackgroundColorId(peerColor, false); topView.setBackgroundColor(getThemedColor(Theme.key_avatar_backgroundActionBarBlue)); frameLayout.addView(topView); contentView.blurBehindViews.add(topView); @@ -4427,7 +4599,7 @@ protected void dispatchDraw(Canvas canvas) { 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; @@ -4551,8 +4723,17 @@ protected void setCustomAvatarProgress(float progress) { @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); } } }; @@ -4631,7 +4812,7 @@ public void setTextColor(int color) { } onlineTextView[a].setEllipsizeByGradient(true); - onlineTextView[a].setTextColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue)); + onlineTextView[a].setTextColor(applyPeerColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), true)); onlineTextView[a].setTextSize(14); onlineTextView[a].setGravity(Gravity.LEFT); onlineTextView[a].setAlpha(a == 0 ? 0.0f : 1.0f); @@ -4660,7 +4841,7 @@ public void setTextColor(int color) { 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); @@ -4668,7 +4849,7 @@ protected TextView createTextView() { } }; 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) { @@ -4703,14 +4884,7 @@ protected void onLongPress() { updateProfileData(true); writeButton = new RLottieImageView(context); - - Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN)); - CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, - Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_profile_actionBackground), getThemedColor(Theme.key_profile_actionPressedBackground)), - 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); - writeButton.setBackground(combinedDrawable); + writeButtonSetBackground(); if (userId != 0) { if (imageUpdater != null) { cameraDrawable = new RLottieDrawable(R.raw.camera_outline, String.valueOf(R.raw.camera_outline), AndroidUtilities.dp(56), AndroidUtilities.dp(56), false, null); @@ -4818,12 +4992,18 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, value), PorterDuff.Mode.SRC_IN); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(value); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(value); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(value); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(value); + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(value); + } + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(value); } updateEmojiStatusDrawableColor(value); @@ -4897,7 +5077,7 @@ public void onAnimationStart(Animator animation) { @Override public void onAnimationEnd(Animator animation) { - actionBar.setItemsBackgroundColor(isPulledDown ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsBackgroundColor(isPulledDown ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); avatarImage.clearForeground(); doNotSetForeground = false; updateStoriesViewBounds(false); @@ -4996,6 +5176,27 @@ public void onZoomStarted(MessageObject messageObject) { BackButtonMenuRecent.addToRecentDialogs(currentAccount, userId != 0 ? userId : -chatId); + blurredView = new View(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (fragmentView != null) { + fragmentView.invalidate(); + } + } + }; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + blurredView.setForeground(new ColorDrawable(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_windowBackgroundWhite), 100))); + } + blurredView.setFocusable(false); + blurredView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + blurredView.setOnClickListener(e -> { + finishPreviewFragment(); + }); + blurredView.setVisibility(View.GONE); + blurredView.setFitsSystemWindows(true); + contentView.addView(blurredView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + createFloatingActionButton(getContext()); return fragmentView; } @@ -5130,7 +5331,7 @@ private void updateFloatingButtonColor() { } Drawable drawable; if (floatingButtonContainer != null) { - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); + drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), applyPeerColor(Theme.getColor(Theme.key_chats_actionBackground), false), applyPeerColor(Theme.getColor(Theme.key_chats_actionPressedBackground), false)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -5229,12 +5430,18 @@ private void setAvatarExpandProgress(float animatedFracture) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, value), PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(value); + if (verifiedCrossfadeDrawable[0] != null) { + verifiedCrossfadeDrawable[0].setProgress(value); + } + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(value); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(value); + if (premiumCrossfadeDrawable[0] != null) { + premiumCrossfadeDrawable[0].setProgress(value); + } + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(value); } updateEmojiStatusDrawableColor(value); @@ -5263,12 +5470,14 @@ private void setAvatarExpandProgress(float animatedFracture) { mediaCounterTextView.setTranslationY(onlineTextViewY); final Object onlineTextViewTag = onlineTextView[1].getTag(); int statusColor; + boolean online = false; if (onlineTextViewTag instanceof Integer) { statusColor = getThemedColor((Integer) onlineTextViewTag); + online = (Integer) onlineTextViewTag == Theme.key_profile_status; } else { statusColor = getThemedColor(Theme.key_avatar_subtitleInProfileBlue); } - onlineTextView[1].setTextColor(ColorUtils.blendARGB(statusColor, Color.argb(179, 255, 255, 255), value)); + onlineTextView[1].setTextColor(ColorUtils.blendARGB(applyPeerColor(statusColor, true, online), 0xB3FFFFFF, value)); if (extraHeight > AndroidUtilities.dp(88f)) { nameTextView[1].setPivotY(AndroidUtilities.lerp(0, nameTextView[1].getMeasuredHeight(), value)); nameTextView[1].setScaleX(AndroidUtilities.lerp(1.12f, 1.67f, value)); @@ -5277,8 +5486,8 @@ private void setAvatarExpandProgress(float animatedFracture) { needLayoutText(Math.min(1f, extraHeight / AndroidUtilities.dp(88f))); - nameTextView[1].setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_profile_title), Color.WHITE, value)); - actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); + nameTextView[1].setTextColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_profile_title), Color.WHITE, currentExpandAnimatorValue)); + actionBar.setItemsColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); actionBar.setMenuOffsetSuppressed(true); avatarImage.setForegroundAlpha(value); @@ -5372,7 +5581,7 @@ public void goToForum() { Bundle args = new Bundle(); args.putLong("chat_id", chatId); - presentFragment(new TopicsFragment(args)); + presentFragment(TopicsFragment.getTopicsOrChat(this, args)); } private SelectAnimatedEmojiDialog.SelectAnimatedEmojiDialogWindow selectAnimatedEmojiDialog; @@ -5390,32 +5599,57 @@ public void showStatusSelect() { 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) { - emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(), true); - } else { + if (documentId == null && currentChat == null) { + emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(a), true); + } else if (documentId != null) { emojiStatusDrawable[a].set(documentId, true); + } else { + emojiStatusDrawable[a].set((Drawable) null, true); } } } @@ -5424,11 +5658,7 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } 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(); @@ -5436,8 +5666,8 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } }; 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); @@ -5511,7 +5741,38 @@ private void openAvatar() { private void onWriteButtonClick() { if (userId != 0) { if (imageUpdater != null) { - presentFragment(new ChangeNameActivity(resourcesProvider)); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + if (user == null) { + user = UserConfig.getInstance(currentAccount).getCurrentUser(); + } + if (user == null) { + return; + } + imageUpdater.openMenu(user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty), () -> { + MessagesController.getInstance(currentAccount).deleteUserPhoto(null); + cameraDrawable.setCurrentFrame(0); + cellCameraDrawable.setCurrentFrame(0); + }, dialog -> { + if (!imageUpdater.isUploadingImage()) { + cameraDrawable.setCustomEndFrame(86); + cellCameraDrawable.setCustomEndFrame(86); + writeButton.playAnimation(); + if (setAvatarCell != null) { + setAvatarCell.getImageView().playAnimation(); + } + } else { + cameraDrawable.setCurrentFrame(0, false); + cellCameraDrawable.setCurrentFrame(0, false); + } + }, 0); + cameraDrawable.setCurrentFrame(0); + cameraDrawable.setCustomEndFrame(43); + cellCameraDrawable.setCurrentFrame(0); + cellCameraDrawable.setCustomEndFrame(43); + writeButton.playAnimation(); + if (setAvatarCell != null) { + setAvatarCell.getImageView().playAnimation(); + } } else { if (playProfileAnimation != 0 && parentLayout.getFragmentStack().get(parentLayout.getFragmentStack().size() - 2) instanceof ChatActivity) { finishFragment(); @@ -6162,37 +6423,53 @@ public void setValue(ActionBar object, float value) { scamDrawable.setColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f)); } - color1 = getThemedColor(Theme.key_actionBarDefaultIcon); + color1 = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); color2 = getThemedColor(Theme.key_actionBarActionModeDefaultIcon); actionBar.setItemsColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), false); - color1 = getThemedColor(Theme.key_avatar_actionBarSelectorBlue); + color1 = peerColor != null ? Theme.ACTION_BAR_WHITE_SELECTOR_COLOR : peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue); color2 = getThemedColor(Theme.key_actionBarActionModeDefaultSelector); actionBar.setItemsBackgroundColor(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), false); topView.invalidate(); - otherItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - callItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - videoCallItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - editItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); - eventLogItem.setIconColor(getThemedColor(Theme.key_actionBarDefaultIcon)); + otherItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + callItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + videoCallItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + editItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); + eventLogItem.setIconColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon)); - if (verifiedDrawable != null) { + if (verifiedDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedBackground); color2 = getThemedColor(Theme.key_player_actionBarTitle); - verifiedDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.SRC_IN); + verifiedDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (verifiedDrawable[1] != null) { + color1 = 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); } - if (verifiedCheckDrawable != null) { + if (verifiedCheckDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedCheck); color2 = getThemedColor(Theme.key_windowBackgroundWhite); - verifiedCheckDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.SRC_IN); + verifiedCheckDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (verifiedCheckDrawable[1] != null) { + color1 = 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); } - if (premiumStarDrawable != null) { + + if (premiumStarDrawable[0] != null) { color1 = getThemedColor(Theme.key_profile_verifiedBackground); color2 = getThemedColor(Theme.key_player_actionBarTitle); - premiumStarDrawable.setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + premiumStarDrawable[0].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); + } + if (premiumStarDrawable[1] != null) { + color1 = applyPeerColor(getThemedColor(Theme.key_profile_verifiedBackground)); + color2 = applyPeerColor(getThemedColor(Theme.key_player_actionBarTitle)); + premiumStarDrawable[1].setColorFilter(AndroidUtilities.getOffsetColor(color1, color2, value, 1.0f), PorterDuff.Mode.MULTIPLY); } updateEmojiStatusDrawableColor(); @@ -6501,6 +6778,9 @@ public void updateSelectedMediaTabText() { mediaCounterTextView.setText(onlineTextView[1].getText()); } else if (id == SharedMediaLayout.TAB_STORIES) { mediaCounterTextView.setText(LocaleController.formatPluralString("ProfileStoriesCount", sharedMediaLayout.getStoriesCount(id))); + } else if (id == SharedMediaLayout.TAB_RECOMMENDED_CHANNELS) { + MessagesController.ChannelRecommendations rec = MessagesController.getInstance(currentAccount).getChannelRecommendations(chatId); + mediaCounterTextView.setText(LocaleController.formatPluralString("Channels", rec == null ? 0 : rec.chats.size() + rec.more)); } } @@ -6772,7 +7052,7 @@ public void onAnimationEnd(Animator animation) { avatarContainer.setScaleY(avatarScale); overlaysView.setAlphaValue(avatarAnimationProgress, false); - actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, avatarAnimationProgress), false); + actionBar.setItemsColor(ColorUtils.blendARGB(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, avatarAnimationProgress), false); if (scamDrawable != null) { scamDrawable.setColor(ColorUtils.blendARGB(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), Color.argb(179, 255, 255, 255), avatarAnimationProgress)); @@ -6780,12 +7060,12 @@ public void onAnimationEnd(Animator animation) { if (lockIconDrawable != null) { lockIconDrawable.setColorFilter(ColorUtils.blendARGB(getThemedColor(Theme.key_chat_lockIcon), Color.WHITE, avatarAnimationProgress), PorterDuff.Mode.MULTIPLY); } - if (verifiedCrossfadeDrawable != null) { - verifiedCrossfadeDrawable.setProgress(avatarAnimationProgress); + if (verifiedCrossfadeDrawable[1] != null) { + verifiedCrossfadeDrawable[1].setProgress(avatarAnimationProgress); nameTextView[1].invalidate(); } - if (premiumCrossfadeDrawable != null) { - premiumCrossfadeDrawable.setProgress(avatarAnimationProgress); + if (premiumCrossfadeDrawable[1] != null) { + premiumCrossfadeDrawable[1].setProgress(avatarAnimationProgress); nameTextView[1].invalidate(); } updateEmojiStatusDrawableColor(avatarAnimationProgress); @@ -7033,7 +7313,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } } } 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 { @@ -7336,6 +7616,10 @@ public void onResume() { firstLayout = true; listAdapter.notifyDataSetChanged(); } + if (!parentLayout.isInPreviewMode() && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } if (imageUpdater != null) { imageUpdater.onResume(); @@ -7385,7 +7669,7 @@ public void onPause() { public boolean isSwipeBackEnabled(MotionEvent event) { if (avatarsViewPager != null && avatarsViewPager.getVisibility() == View.VISIBLE && avatarsViewPager.getRealCount() > 1) { avatarsViewPager.getHitRect(rect); - if (rect.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { + if (event != null && rect.contains((int) event.getX(), (int) event.getY() - actionBar.getMeasuredHeight())) { return false; } } @@ -7496,6 +7780,11 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { } } getNotificationCenter().onAnimationFinish(transitionIndex); + + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } } transitionAnimationInProress = false; checkPhotoDescriptionAlpha(); @@ -7536,8 +7825,8 @@ public void setAvatarAnimationProgress(float progress) { timerDrawable.setBackgroundColor(ColorUtils.blendARGB(actionBarColor2, color, progress)); color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); - int iconColor = getThemedColor(Theme.key_actionBarDefaultIcon); - actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, progress), false); + int iconColor = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); + actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, avatarAnimationProgress), false); color = getThemedColor(Theme.key_profile_title); int titleColor = getThemedColor(Theme.key_actionBarDefaultTitle); @@ -7550,12 +7839,11 @@ public void setAvatarAnimationProgress(float progress) { color = isOnline[0] ? getThemedColor(Theme.key_profile_status) : AvatarDrawable.getProfileTextColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); int subtitleColor = getThemedColor(isOnline[0] ? Theme.key_chat_status : Theme.key_actionBarDefaultSubtitle); - for (int i = 0; i < 3; i++) { if (onlineTextView[i] == null || i == 1 || i == 2 && playProfileAnimation == 2) { continue; } - onlineTextView[i].setTextColor(ColorUtils.blendARGB(subtitleColor, color, progress)); + onlineTextView[i].setTextColor(ColorUtils.blendARGB(i == 0 ? subtitleColor : applyPeerColor(subtitleColor, true, isOnline[0]), i == 0 ? color : applyPeerColor(color, true, isOnline[0]), progress)); } extraHeight = initialAnimationExtraHeight * progress; color = AvatarDrawable.getProfileColorForId(userId != 0 ? userId : chatId, resourcesProvider); @@ -7663,7 +7951,7 @@ public AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runna if (playProfileAnimation == 2) { avatarColor = getAverageColor(avatarImage.getImageReceiver()); nameTextView[1].setTextColor(Color.WHITE); - onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); + onlineTextView[1].setTextColor(0xB3FFFFFF); idTextView.setAlpha(0); idTextView.setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); @@ -8008,6 +8296,7 @@ private void updateRowsIds() { nekoRow = -1; languageRow = -1; premiumRow = -1; + premiumGiftingRow = -1; premiumSectionsRow = -1; privacyRow = -1; dataRow = -1; @@ -8063,6 +8352,7 @@ private void updateRowsIds() { membersSectionRow = -1; sharedMediaRow = -1; notificationsSimpleRow = -1; + settingsRow = -1; unblockRow = -1; joinRow = -1; @@ -8086,6 +8376,11 @@ private void updateRowsIds() { if (!hasMedia && chatInfo != null) { hasMedia = chatInfo.stories_pinned_available; } + if (!hasMedia) { + if (MessagesController.ChannelRecommendations.hasRecommendations(currentAccount, chatId)) { + hasMedia = true; + } + } if (userId != 0) { if (LocaleController.isRTL) { @@ -8131,8 +8426,13 @@ private void updateRowsIds() { nekoRow = 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++; @@ -8268,6 +8568,7 @@ private void updateRowsIds() { if (chatInfo.banned_count != 0 || chatInfo.kicked_count != 0) { blockedUsersRow = rowCount++; } + settingsRow = rowCount++; membersSectionRow = rowCount++; } } @@ -8387,22 +8688,35 @@ private Drawable getLockIconDrawable() { return lockIconDrawable; } - private Drawable getVerifiedCrossfadeDrawable() { - if (verifiedCrossfadeDrawable == null) { - verifiedDrawable = Theme.profile_verifiedDrawable.getConstantState().newDrawable().mutate(); - verifiedCheckDrawable = Theme.profile_verifiedCheckDrawable.getConstantState().newDrawable().mutate(); - verifiedCrossfadeDrawable = new CrossfadeDrawable(new CombinedDrawable(verifiedDrawable, verifiedCheckDrawable), ContextCompat.getDrawable(getParentActivity(), R.drawable.verified_profile)); + private Drawable getVerifiedCrossfadeDrawable(int a) { + if (verifiedCrossfadeDrawable[a] == null) { + verifiedDrawable[a] = Theme.profile_verifiedDrawable.getConstantState().newDrawable().mutate(); + verifiedCheckDrawable[a] = Theme.profile_verifiedCheckDrawable.getConstantState().newDrawable().mutate(); + 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) + ); } - return verifiedCrossfadeDrawable; + return verifiedCrossfadeDrawable[a]; } - private Drawable getPremiumCrossfadeDrawable() { - if (premiumCrossfadeDrawable == null) { - premiumStarDrawable = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate(); - premiumStarDrawable.setColorFilter(getThemedColor(Theme.key_profile_verifiedBackground), PorterDuff.Mode.MULTIPLY); - premiumCrossfadeDrawable = new CrossfadeDrawable(premiumStarDrawable, ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_prolfilestar).mutate()); + private Drawable getPremiumCrossfadeDrawable(int a) { + if (premiumCrossfadeDrawable[a] == null) { + premiumStarDrawable[a] = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate(); + int color = getThemedColor(Theme.key_profile_verifiedBackground); + if (a == 1) { + color = applyPeerColor(color); + } + premiumStarDrawable[a].setColorFilter(color, PorterDuff.Mode.MULTIPLY); + premiumCrossfadeDrawable[a] = new CrossfadeDrawable(premiumStarDrawable[a], ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_prolfilestar).mutate()); } - return premiumCrossfadeDrawable; + return premiumCrossfadeDrawable[a]; } private Drawable getEmojiStatusDrawable(TLRPC.EmojiStatus emojiStatus, boolean switchable, boolean animated, int a) { @@ -8417,7 +8731,7 @@ private Drawable getEmojiStatusDrawable(TLRPC.EmojiStatus emojiStatus, boolean s } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000) && !reportSpam) { emojiStatusDrawable[a].set(((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id, animated); } else { - emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(), animated); + emojiStatusDrawable[a].set(getPremiumCrossfadeDrawable(a), animated); } updateEmojiStatusDrawableColor(); return emojiStatusDrawable[a]; @@ -8428,18 +8742,25 @@ private void updateEmojiStatusDrawableColor() { updateEmojiStatusDrawableColor(lastEmojiStatusProgress); } private void updateEmojiStatusDrawableColor(float progress) { - final int color = - ColorUtils.blendARGB( - AndroidUtilities.getOffsetColor(getThemedColor(Theme.key_profile_verifiedBackground), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f), - 0xffffffff, - progress - ); for (int a = 0; a < 2; ++a) { + final int fromColor; + if (peerColor != null && a == 1) { + fromColor = ColorUtils.blendARGB( + peerColor.getColor2(), + peerColor.hasColor6(Theme.isCurrentThemeDark()) ? peerColor.getColor5() : peerColor.getColor3(), + .5f + ); + } else { + fromColor = AndroidUtilities.getOffsetColor(getThemedColor(Theme.key_profile_verifiedBackground), getThemedColor(Theme.key_player_actionBarTitle), mediaHeaderAnimationProgress, 1.0f); + } + final int color = ColorUtils.blendARGB(fromColor, 0xffffffff, progress); if (emojiStatusDrawable[a] != null) { emojiStatusDrawable[a].setColor(color); } + if (a == 1) { + animatedStatusView.setColor(color); + } } - animatedStatusView.setColor(color); lastEmojiStatusProgress = progress; } @@ -8452,6 +8773,8 @@ private void updateEmojiStatusEffectPosition() { ); } + private MessagesController.PeerColor peerColor; + private void updateProfileData(boolean reload) { if (avatarContainer == null || nameTextView == null || getParentActivity() == null) { return; @@ -8487,7 +8810,18 @@ private void updateProfileData(boolean reload) { if (user.photo != null) { photoBig = user.photo.photo_big; } - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); + + final int colorId = UserObject.getProfileColorId(user); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + final MessagesController.PeerColor wasPeerColor = peerColor; + peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (wasPeerColor != peerColor) { + updatedPeerColor(); + } + if (topView != null) { + topView.setBackgroundEmojiId(UserObject.getProfileEmojiId(user), true); + } final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); @@ -8547,10 +8881,10 @@ private void updateProfileData(boolean reload) { isOnline[0] = false; newString2 = LocaleController.formatUserStatus(currentAccount, user, isOnline, shortStatus ? new boolean[1] : null); if (onlineTextView[1] != null && !mediaHeaderVisible) { - int key = isOnline[0] ? Theme.key_profile_status : Theme.key_avatar_subtitleInProfileBlue; + int key = isOnline[0] && peerColor == null ? Theme.key_profile_status : Theme.key_avatar_subtitleInProfileBlue; onlineTextView[1].setTag(key); if (!isPulledDown) { - onlineTextView[1].setTextColor(getThemedColor(key)); + onlineTextView[1].setTextColor(applyPeerColor(getThemedColor(key), true, isOnline[0])); } } } @@ -8576,55 +8910,61 @@ private void updateProfileData(boolean reload) { 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(); - 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.verifiedExtended()) { - rightIcon = getVerifiedCrossfadeDrawable(); - } 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(); }); @@ -8731,6 +9071,17 @@ private void updateProfileData(boolean reload) { flagSecure.invalidate(); } + final int colorId = ChatObject.getProfileColorId(chat); + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + final MessagesController.PeerColor wasPeerColor = peerColor; + peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (wasPeerColor != peerColor) { + updatedPeerColor(); + } + if (topView != null) { + topView.setBackgroundEmojiId(ChatObject.getProfileEmojiId(chat), true); + } + if (isTopic) { topic = getMessagesController().getTopicsController().findTopic(chatId, topicId); } @@ -8838,24 +9189,45 @@ private void updateProfileData(boolean reload) { } 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.verifiedExtended()) { - nameTextView[a].setRightDrawable(getVerifiedCrossfadeDrawable()); + 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()); + 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); } @@ -8916,7 +9288,7 @@ private void updateProfileData(boolean reload) { videoLocation = null; ForumUtilities.setTopicIcon(avatarImage, topic, true, true, resourcesProvider); } else { - avatarDrawable.setInfo(chat); + avatarDrawable.setInfo(currentAccount, chat); imageLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_BIG); thumbLocation = ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL); videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); @@ -9001,6 +9373,90 @@ private void updateProfileData(boolean reload) { AndroidUtilities.runOnUIThread(this::updateEmojiStatusEffectPosition); } + private void updatedPeerColor() { + if (topView != null) { + topView.setBackgroundColorId(peerColor, true); + } + if (onlineTextView[1] != null) { + int statusColor; + if (onlineTextView[1].getTag() instanceof Integer) { + statusColor = getThemedColor((Integer) onlineTextView[1].getTag()); + } else { + statusColor = getThemedColor(Theme.key_avatar_subtitleInProfileBlue); + } + onlineTextView[1].setTextColor(ColorUtils.blendARGB(applyPeerColor(statusColor, true, isOnline[0]), 0xB3FFFFFF, currentExpandAnimatorValue)); + } + if (actionBar != null) { + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + + final int color = AvatarDrawable.getIconColorForId(userId != 0 || ChatObject.isChannel(chatId, currentAccount) && !currentChat.megagroup ? 5 : chatId, resourcesProvider); + final int iconColor = peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon); + actionBar.setItemsColor(ColorUtils.blendARGB(iconColor, color, avatarAnimationProgress), false); + } + if (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)); + } + if (autoDeletePopupWrapper != null && autoDeletePopupWrapper.textView != null) { + autoDeletePopupWrapper.textView.invalidate(); + } + AndroidUtilities.forEachViews(listView, view -> { + if (view instanceof HeaderCell) { + ((HeaderCell) view).setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueHeader), false)); + } else if (view instanceof TextDetailCell) { + ((TextDetailCell) view).valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2), false)); + } else if (view instanceof TextCell) { + ((TextCell) view).updateColors(); + } else if (view instanceof NotificationsCheckCell) { + ((NotificationsCheckCell) view).getCheckBox().invalidate(); + } + }); + if (sharedMediaLayout != null && sharedMediaLayout.scrollSlidingTextTabStrip != null) { + sharedMediaLayout.scrollSlidingTextTabStrip.updateColors(); + } + writeButtonSetBackground(); + updateEmojiStatusDrawableColor(); + } + + private int applyPeerColor(int color) { + return applyPeerColor(color, true, null); + } + + private int applyPeerColor(int color, boolean actionBar) { + return applyPeerColor(color, actionBar, null); + } + + private int applyPeerColor(int color, boolean actionBar, Boolean online) { + if (!actionBar) return color; + if (peerColor != null) { + final int baseColor = getThemedColor(actionBar ? Theme.key_actionBarDefault : Theme.key_windowBackgroundWhiteBlueIcon); + final int storyColor = ColorUtils.blendARGB(peerColor.getStoryColor1(Theme.isCurrentThemeDark()), peerColor.getStoryColor2(Theme.isCurrentThemeDark()), .5f); + int accentColor = actionBar ? storyColor : peerColor.getBgColor1(Theme.isCurrentThemeDark()); + if (!Theme.hasHue(baseColor)) { + return online != null && !online ? Theme.adaptHSV(Theme.multAlpha(storyColor, .7f), -.2f, +.2f) : storyColor; + } + return Theme.changeColorAccent(baseColor, accentColor, color, Theme.isCurrentThemeDark(), online != null && !online ? Theme.multAlpha(storyColor, .7f) : storyColor); + } + return color; + } + + private int applyPeerColor2(int color) { + if (peerColor != null) { + int accentColor = peerColor.getBgColor2(Theme.isCurrentThemeDark()); + return Theme.changeColorAccent(getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon), accentColor, color, Theme.isCurrentThemeDark(), accentColor); + } + return color; + } + private void createActionBarMenu(boolean animated) { if (actionBar == null || otherItem == null) { return; @@ -9021,7 +9477,8 @@ private void createActionBarMenu(boolean animated) { return; } if (UserObject.isUserSelf(user)) { - otherItem.addSubItem(edit_name, R.drawable.msg_edit, LocaleController.getString("EditName", R.string.EditName)); + otherItem.addSubItem(edit_name, R.drawable.msg_edit, LocaleController.getString(R.string.EditName)); + otherItem.addSubItem(edit_color, R.drawable.msg_colors, LocaleController.getString(R.string.EditProfileColor)); selfUser = true; } else { if (user.bot && user.bot_can_edit) { @@ -9077,10 +9534,10 @@ private void createActionBarMenu(boolean animated) { 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.menu_secret, LocaleController.getString("StartEncryptedChat", R.string.StartEncryptedChat)); + otherItem.addSubItem(start_secret_chat, R.drawable.msg_secret, LocaleController.getString("StartEncryptedChat", R.string.StartEncryptedChat)); } if (StrUtil.isNotBlank(user.username)) { otherItem.addSubItem(qr_code, R.drawable.msg_qrcode, LocaleController.getString("ShareQRCode", R.string.ShareQRCode)); @@ -9311,7 +9768,8 @@ public void showGlobalAutoDeleteScreen() { } }, false, 0, resourcesProvider); if (dialogId > 0 || userId > 0) { - autoDeletePopupWrapper.allowExtenededHint(); + int linkColor = applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText), false); + autoDeletePopupWrapper.allowExtendedHint(linkColor); } int ttl = 0; if (userInfo != null || chatInfo != null) { @@ -9953,7 +10411,12 @@ protected void didResizeStart() { break; } case VIEW_TYPE_TEXT: { - view = new TextCell(mContext, resourcesProvider); + view = new TextCell(mContext, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + }; break; } case VIEW_TYPE_DIVIDER: { @@ -9962,7 +10425,12 @@ protected void didResizeStart() { break; } case VIEW_TYPE_NOTIFICATIONS_CHECK: { - view = new NotificationsCheckCell(mContext, 23, 70, false, resourcesProvider); + view = new NotificationsCheckCell(mContext, 23, 70, false, resourcesProvider) { + @Override + protected int processColor(int color) { + return applyPeerColor(color, false); + } + }; break; } case VIEW_TYPE_NOTIFICATIONS_CHECK_SIMPLE: { @@ -10121,6 +10589,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == debugHeaderRow) { headerCell.setText(LocaleController.getString("SettingsDebug", R.string.SettingsDebug)); } + headerCell.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueHeader), false)); break; case VIEW_TYPE_TEXT_DETAIL_MULTILINE: case VIEW_TYPE_TEXT_DETAIL: @@ -10260,7 +10729,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } if (containsQr) { Drawable drawable = ContextCompat.getDrawable(detailCell.getContext(), R.drawable.msg_qr_mini); - drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_switch2TrackChecked), PorterDuff.Mode.MULTIPLY)); + drawable.setColorFilter(new PorterDuffColorFilter(applyPeerColor(getThemedColor(Theme.key_switch2TrackChecked), false), PorterDuff.Mode.MULTIPLY)); detailCell.setImage(drawable, LocaleController.getString("GetQRCode", R.string.GetQRCode)); detailCell.setImageClickListener(ProfileActivity.this::onTextDetailCellImageClicked); } else { @@ -10268,6 +10737,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { detailCell.setImageClickListener(null); } detailCell.setTag(position); + detailCell.valueTextView.setTextColor(applyPeerColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText2), false)); break; case VIEW_TYPE_ABOUT_LINK: AboutLinkCell aboutLinkCell = (AboutLinkCell) holder.itemView; @@ -10346,6 +10816,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { textCell.setTextAndIcon(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), R.drawable.msg_admins, position != membersSectionRow - 1); } + } else if (position == settingsRow) { + textCell.setTextAndIcon(LocaleController.getString("ChannelAdminSettings", R.string.ChannelAdminSettings), R.drawable.msg_customize, position != membersSectionRow - 1); } else if (position == blockedUsersRow) { if (chatInfo != null) { textCell.setTextAndValueAndIcon(LocaleController.getString("ChannelBlacklist", R.string.ChannelBlacklist), String.format("%d", Math.max(chatInfo.banned_count, chatInfo.kicked_count)), R.drawable.msg_user_remove, position != membersSectionRow - 1); @@ -10411,7 +10883,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == setAvatarRow) { cellCameraDrawable.setCustomEndFrame(86); cellCameraDrawable.setCurrentFrame(85, false); - textCell.setTextAndIcon(LocaleController.getString("EditName", R.string.EditName), R.drawable.msg_edit, false); + textCell.setTextAndIcon(LocaleController.getString("SetProfilePhoto", R.string.SetProfilePhoto), cellCameraDrawable, false); textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); textCell.getImageView().setPadding(0, 0, 0, AndroidUtilities.dp(8)); textCell.setImageLeft(12); @@ -10420,9 +10892,13 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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)); break; case VIEW_TYPE_NOTIFICATIONS_CHECK: NotificationsCheckCell checkCell = (NotificationsCheckCell) holder.itemView; @@ -10590,7 +11066,7 @@ public void updateDrawState(@NonNull TextPaint ds) { ds.setUnderlineText(false); } }, 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - username.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_chat_messageLinkIn)), 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + username.setSpan(new ForegroundColorSpan(applyPeerColor(getThemedColor(Theme.key_chat_messageLinkIn), false)), 0, username.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); usernames.append(username); if (i < alsoUsernames.size() - 1) { usernames.append(", "); @@ -10626,7 +11102,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { 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; @@ -10661,14 +11137,14 @@ public int getItemViewType(int position) { } else if (position == userInfoRow || position == channelInfoRow || position == bioRow) { return VIEW_TYPE_ABOUT_LINK; } else if (position == settingsTimerRow || position == settingsKeyRow || position == reportRow || position == reportReactionRow || - position == subscribersRow || position == subscribersRequestsRow || position == administratorsRow || position == blockedUsersRow || + position == subscribersRow || position == subscribersRequestsRow || position == administratorsRow || position == settingsRow || position == blockedUsersRow || position == addMemberRow || position == joinRow || position == unblockRow || position == sendMessageRow || position == notificationRow || position == privacyRow || position == languageRow || position == dataRow || position == chatRow || 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; @@ -11103,7 +11579,7 @@ private SearchResult[] onCreateSearchArray() { } private boolean isPremiumFeatureAvailable(int feature) { - if (getMessagesController().premiumLocked && !getUserConfig().isPremium()) { + if (getMessagesController().premiumFeaturesBlocked() && !getUserConfig().isPremium()) { return false; } @@ -11543,9 +12019,9 @@ public ArrayList getThemeDescriptions() { final Object onlineTextViewTag = onlineTextView[1].getTag(); for (int i = 0; i < 2; i++) { if (onlineTextViewTag instanceof Integer) { - onlineTextView[i + 1].setTextColor(getThemedColor((Integer) onlineTextViewTag)); + onlineTextView[i + 1].setTextColor(applyPeerColor(getThemedColor((Integer) onlineTextViewTag), true, isOnline[0])); } else { - onlineTextView[i + 1].setTextColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue)); + onlineTextView[i + 1].setTextColor(applyPeerColor(getThemedColor(Theme.key_avatar_subtitleInProfileBlue), true, true)); } } } @@ -11560,8 +12036,8 @@ public ArrayList getThemeDescriptions() { idTextView.setTextColor(Theme.getColor(Theme.key_avatar_subtitleInProfileBlue)); } if (actionBar != null) { - actionBar.setItemsColor(getThemedColor(Theme.key_actionBarDefaultIcon), false); - actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); + actionBar.setItemsColor(peerColor != null ? Color.WHITE : getThemedColor(Theme.key_actionBarDefaultIcon), false); + actionBar.setItemsBackgroundColor(peerColor != null ? 0x20ffffff : getThemedColor(Theme.key_avatar_actionBarSelectorBlue), false); } } updateEmojiStatusDrawableColor(); @@ -11672,11 +12148,11 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(searchListView, 0, new Class[]{SettingsSearchCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); if (mediaHeaderVisible) { - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedCheckDrawable}, null, Theme.key_player_actionBarTitle)); - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedDrawable}, null, Theme.key_windowBackgroundWhite)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedCheckDrawable, null, Theme.key_player_actionBarTitle)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedDrawable, null, Theme.key_windowBackgroundWhite)); } else { - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedCheckDrawable}, null, Theme.key_profile_verifiedCheck)); - arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, new Drawable[]{verifiedDrawable}, null, Theme.key_profile_verifiedBackground)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedCheckDrawable, null, Theme.key_profile_verifiedCheck)); + arrayList.add(new ThemeDescription(nameTextView[1], 0, null, null, verifiedDrawable, null, Theme.key_profile_verifiedBackground)); } return arrayList; @@ -11719,9 +12195,10 @@ public void updateListAnimated(boolean updateOnlineCount) { int savedScrollPosition = -1; int savedScrollOffset; + boolean savedScrollToSharedMedia; private void saveScrollPosition() { - if (listView != null && layoutManager != null && listView.getChildCount() > 0) { + if (listView != null && layoutManager != null && listView.getChildCount() > 0 && !savedScrollToSharedMedia) { View view = null; int position = -1; int top = Integer.MAX_VALUE; @@ -11763,15 +12240,28 @@ private void onTextDetailCellImageClicked(View view) { @Override public void onBecomeFullyVisible() { super.onBecomeFullyVisible(); + writeButtonSetBackground(); + } + private void writeButtonSetBackground() { + if (writeButton == null) return; try { Drawable shadowDrawable = fragmentView.getContext().getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY)); + int color1 = getThemedColor(Theme.key_profile_actionBackground); + int color2 = getThemedColor(Theme.key_profile_actionPressedBackground); + int iconColor = getThemedColor(Theme.key_profile_actionIcon); + if (peerColor != null && Theme.hasHue(color1)) { + color1 = Theme.adaptHSV(peerColor.getBgColor1(false), +.05f, -.04f); + color2 = applyPeerColor2(color2); + iconColor = Color.WHITE; + } CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, - Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_profile_actionBackground), getThemedColor(Theme.key_profile_actionPressedBackground)), + Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), color1, color2), 0, 0); combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); writeButton.setBackground(combinedDrawable); + writeButton.setColorFilter(new PorterDuffColorFilter(iconColor, PorterDuff.Mode.MULTIPLY)); } catch (Exception e) {} } @@ -11891,6 +12381,7 @@ public void fillPositions(SparseIntArray sparseIntArray) { 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); @@ -11935,6 +12426,7 @@ public void fillPositions(SparseIntArray sparseIntArray) { put(++pointer, subscribersRow, sparseIntArray); put(++pointer, subscribersRequestsRow, sparseIntArray); put(++pointer, administratorsRow, sparseIntArray); + put(++pointer, settingsRow, sparseIntArray); put(++pointer, blockedUsersRow, sparseIntArray); put(++pointer, membersSectionRow, sparseIntArray); put(++pointer, sharedMediaRow, sparseIntArray); @@ -11963,6 +12455,8 @@ public boolean isLightStatusBar() { color = getThemedColor(Theme.key_actionBarActionModeDefault); } else if (mediaHeaderVisible) { color = getThemedColor(Theme.key_windowBackgroundWhite); + } else if (peerColor != null) { + color = peerColor.getBgColor2(Theme.isCurrentThemeDark()); } else { color = getThemedColor(Theme.key_actionBarDefault); } @@ -12139,4 +12633,33 @@ private void listCodecs(String type, StringBuilder info) { info.append("\n"); } catch (Exception ignore) {} } + + @Override + public void onTransitionAnimationProgress(boolean isOpen, float progress) { + super.onTransitionAnimationProgress(isOpen, progress); + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (isOpen) { + blurredView.setAlpha(1.0f - progress); + } else { + blurredView.setAlpha(progress); + } + } + } + + public void prepareBlurBitmap() { + if (blurredView == null) { + return; + } + int w = (int) (fragmentView.getMeasuredWidth() / 6.0f); + int h = (int) (fragmentView.getMeasuredHeight() / 6.0f); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.scale(1.0f / 6.0f, 1.0f / 6.0f); + fragmentView.draw(canvas); + Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(w, h) / 180)); + blurredView.setBackground(new BitmapDrawable(bitmap)); + blurredView.setAlpha(0.0f); + blurredView.setVisibility(View.VISIBLE); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java index 0d41c1e0f1..7dcebf5466 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretMediaViewer.java @@ -156,7 +156,6 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child != aspectRatioFrameLayout && super.drawChild(canvas, child, drawingTime); } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -1393,9 +1392,7 @@ private void showSecretHint() { 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 0000000000..31b0ec364b --- /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 e1c0a4bdff..53458fb50f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -33,7 +33,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -49,6 +48,7 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.view.animation.OvershootInterpolator; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; @@ -144,9 +144,14 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public static final int TYPE_TOPIC_ICON = 3; public static final int TYPE_AVATAR_CONSTRUCTOR = 4; public final static int TYPE_SET_REPLY_ICON = 5; + public static final int TYPE_CHAT_REACTIONS = 6; + public final static int TYPE_SET_REPLY_ICON_BOTTOM = 7; + public final static int TYPE_EXPANDABLE_REACTIONS = 8; + public 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; @@ -431,7 +436,7 @@ public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boo 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)); @@ -444,7 +449,7 @@ public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boo setFocusableInTouchMode(true); - if (type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_EMOJI_STATUS || type == TYPE_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) -> { @@ -557,12 +562,12 @@ public void getOutline(View view, Outline outline) { } } - 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 ? 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) { @@ -579,7 +584,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { addView(bubble2View, LayoutHelper.createFrame(17, 9, (isBottom() ? Gravity.BOTTOM : Gravity.TOP) | Gravity.LEFT, bubbleX / AndroidUtilities.density + (bubbleRight ? -25 : 10), isBottom() ? 0 : 5 + topMarginDp, 0, isBottom() ? 5 + topMarginDp + 9 : 0)); } - boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_SET_REPLY_ICON && type != TYPE_AVATAR_CONSTRUCTOR && shouldDrawBackground; + boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_AVATAR_CONSTRUCTOR && 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); @@ -651,8 +656,10 @@ protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); } emojiTabs.animateAppear = bubbleX == null; - emojiTabs.setPaddingLeft(5); - contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + emojiTabs.setPaddingLeft(type == TYPE_CHAT_REACTIONS ? 10 : 5); + if (type != TYPE_EXPANDABLE_REACTIONS) { + contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + } cachedEmojiTabs[i] = emojiTabs; } @@ -669,7 +676,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } }; emojiTabsShadow.setBackgroundColor(Theme.getColor(Theme.key_divider, resourcesProvider)); - contentView.addView(emojiTabsShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.TOP, 0, 36, 0, 0)); + if (type != TYPE_EXPANDABLE_REACTIONS) { + contentView.addView(emojiTabsShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.TOP, 0, 36, 0, 0)); + } AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, true, 1f, false); emojiGridView = new EmojiListView(context) { @Override @@ -680,7 +689,7 @@ public void onScrolled(int dx, int dy) { updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_REACTIONS || type == TYPE_CHAT_REACTIONS, 1f, true); invalidateParent(); } @@ -708,7 +717,7 @@ protected float animateByScale(View view) { emojiItemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); emojiItemAnimator.setDelayAnimations(false); emojiGridView.setItemAnimator(emojiItemAnimator); - emojiGridView.setPadding(dp(5), dp(2), dp(5), dp(2 + 36)); + emojiGridView.setPadding(dp(5), dp(type == TYPE_CHAT_REACTIONS ? 8 : 2), dp(5), dp(2 + 36)); adapter = new Adapter(); emojiGridView.setAdapter(adapter); @@ -814,7 +823,7 @@ public void onScrolled(int dx, int dy) { 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)); @@ -866,8 +875,8 @@ public int getSpanSize(int position) { }); emojiSearchGridView.setVisibility(View.GONE); gridViewContainer.addView(emojiSearchGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 0)); - contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 36 + (1 / AndroidUtilities.density), 0, 0)); - + contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, type == TYPE_EXPANDABLE_REACTIONS ? 0 : 36 + (1 / AndroidUtilities.density), 0, 0)); + scrollHelper = new RecyclerAnimationScrollHelper(emojiGridView, layoutManager); scrollHelper.setAnimationCallback(new RecyclerAnimationScrollHelper.AnimationCallback() { @Override @@ -887,7 +896,7 @@ public void onEndAnimation() { RecyclerListView.OnItemLongClickListenerExtended onItemLongClick = new RecyclerListView.OnItemLongClickListenerExtended() { @Override public boolean onItemClick(View view, int position, float x, float y) { - if (view instanceof ImageViewEmoji && type == TYPE_REACTIONS) { + if (view instanceof ImageViewEmoji && (type == TYPE_REACTIONS || type == TYPE_EXPANDABLE_REACTIONS)) { incrementHintUse(); if (!NekoConfig.disableVibration.Bool()) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -916,7 +925,7 @@ public boolean onItemClick(View view, int position, float x, float y) { 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) { @@ -1086,7 +1095,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } private void onStickerClick(ImageViewEmoji viewEmoji, TLRPC.Document document) { - onEmojiSelected(viewEmoji, null, document, null); + if (type == TYPE_CHAT_REACTIONS) { + onEmojiSelected(viewEmoji, document.id, document, null); + } else { + onEmojiSelected(viewEmoji, null, document, null); + } } protected void onSettings() { @@ -1094,6 +1107,7 @@ protected void onSettings() { } public void setExpireDateHint(int date) { + if (date <= 0) return; includeHint = true; hintExpireDate = date; updateRows(true, false); @@ -1224,7 +1238,7 @@ private void updateSearchBox() { private Drawable getPremiumStar() { if (premiumStar == null) { - if (type == TYPE_SET_REPLY_ICON) { + 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(); @@ -1917,7 +1931,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; if (viewType == VIEW_TYPE_HEADER) { - view = new HeaderView(getContext()); + view = new HeaderView(getContext(), type == TYPE_CHAT_REACTIONS); } else if (viewType == VIEW_TYPE_SEARCH) { view = new View(getContext()) { @Override @@ -2192,7 +2206,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; if (viewType == VIEW_TYPE_HEADER) { - view = new HeaderView(getContext()); + view = new HeaderView(getContext(), type == TYPE_CHAT_REACTIONS); } else if (viewType == VIEW_TYPE_IMAGE) { view = new ImageView(getContext()); } else if (viewType == VIEW_TYPE_EMOJI || viewType == VIEW_TYPE_REACTION || viewType == VIEW_TYPE_TOPIC_ICON) { @@ -2219,7 +2233,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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)); @@ -2312,7 +2326,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi int index = positionToSection.get(position); if (index >= 0) { EmojiView.EmojiPack pack = packs.get(index); - header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON); + header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS); } else { header.setText(null, false); } @@ -2436,7 +2450,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; int recentSize; - if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers || type == TYPE_CHAT_REACTIONS) { recentSize = recentStickers.size(); } else if (type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_TOPIC_ICON) { recentSize = recent.size(); @@ -2460,6 +2474,10 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { TLRPC.Document document = recentStickers.get(resentPosition); imageView.setSticker(document, emojiGridView); + } else if (type == TYPE_CHAT_REACTIONS) { + TLRPC.Document document = recentStickers.get(resentPosition); + imageView.setSticker(document, emojiGridView); + selected = document != null && selectedDocumentIds.contains(document.id); } else { imageView.span = recent.get(resentPosition); imageView.document = imageView.span == null ? null : imageView.span.document; @@ -2547,12 +2565,12 @@ private class HeaderView extends FrameLayout { private RLottieImageView lockView; ImageView closeIcon; - public HeaderView(Context context) { + public HeaderView(Context context, boolean leftGravity) { super(context); layoutView = new LinearLayout(context); layoutView.setOrientation(LinearLayout.HORIZONTAL); - addView(layoutView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + addView(layoutView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, leftGravity ? Gravity.LEFT : Gravity.CENTER)); lockView = new RLottieImageView(context); lockView.setAnimation(R.raw.unlock_icon, 20, 20); @@ -2826,6 +2844,7 @@ public class ImageViewEmoji extends View { ValueAnimator backAnimator; PremiumLockIconView premiumLockIconView; public boolean selected; + private boolean shouldSelected; private float pressedProgress; public float skewAlpha; public int skewIndex; @@ -2912,6 +2931,66 @@ public void update(long time) { } } + private void cancelBackAnimator() { + if (backAnimator != null) { + backAnimator.removeAllListeners(); + backAnimator.cancel(); + } + } + + public void unselectWithScale() { + if (selected) { + cancelBackAnimator(); + pressedProgress = 1f; + backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + emojiGridView.invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + backAnimator = null; + } + }); + backAnimator.setInterpolator(new OvershootInterpolator(5.0f)); + backAnimator.setDuration(350); + backAnimator.start(); + setViewSelected(false, true); + } + } + + public void setViewSelectedWithScale(boolean selected, boolean animated) { + boolean wasSelected = this.selected; + if (!wasSelected && selected && animated) { + shouldSelected = true; + selectedProgress = 1f; + cancelBackAnimator(); + backAnimator = ValueAnimator.ofFloat(pressedProgress, 1.6f, 0.7f); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + emojiGridView.invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + pressedProgress = 0; + backAnimator = null; + shouldSelected = false; + setViewSelected(true, false); + } + }); + backAnimator.setInterpolator(new LinearInterpolator()); + backAnimator.setDuration(200); + backAnimator.start(); + } else { + shouldSelected = false; + setViewSelected(selected, animated); + } + } + public void setViewSelected(boolean selected, boolean animated) { if (this.selected != selected) { this.selected = selected; @@ -2922,23 +3001,24 @@ public void setViewSelected(boolean selected, boolean animated) { } public void drawSelected(Canvas canvas, View view) { - if ((selected || selectedProgress > 0) && !notDraw) { - if (selected && selectedProgress < 1f) { + if ((selected || shouldSelected || selectedProgress > 0) && !notDraw) { + if (((selected || shouldSelected) && selectedProgress < 1f)) { selectedProgress += 16 / 300f; view.invalidate(); } - if (!selected && selectedProgress > 0) { + if ((!selected && !shouldSelected && selectedProgress > 0)) { selectedProgress -= 16 / 300f; view.invalidate(); } selectedProgress = Utilities.clamp(selectedProgress, 1f, 0f); - + int inset = AndroidUtilities.dp(type == TYPE_CHAT_REACTIONS ? 1.5f : 1f); + int round = AndroidUtilities.dp(type == TYPE_CHAT_REACTIONS ? 6f : 4f); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - AndroidUtilities.rectTmp.inset(AndroidUtilities.dp(1), AndroidUtilities.dp(1)); + AndroidUtilities.rectTmp.inset(inset, inset); Paint paint = empty || drawable instanceof AnimatedEmojiDrawable && ((AnimatedEmojiDrawable) drawable).canOverrideColor() ? selectorAccentPaint : selectorPaint; int wasAlpha = paint.getAlpha(); paint.setAlpha((int) (wasAlpha * getAlpha() * selectedProgress)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, round, round, paint); paint.setAlpha(wasAlpha); } } @@ -2992,7 +3072,13 @@ public void setSticker(TLRPC.Document document, View parent) { this.document = document; createImageReceiver(parent); SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + if (type == TYPE_CHAT_REACTIONS) { + TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); + ImageLocation thumbLocation = ImageLocation.getForDocument(thumb, document); + imageReceiver.setImage(ImageLocation.getForDocument(document), !LiteMode.isEnabled(LiteMode.FLAG_ANIMATED_EMOJI_KEYBOARD) ? "34_34_firstframe" : "34_34", thumbLocation, null, svgThumb, document.size, null, document, 0); + } else { + imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + } isStaticIcon = true; span = null; } @@ -3038,7 +3124,7 @@ public void createPremiumLockView() { 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(); @@ -3046,10 +3132,10 @@ public void onEmojiClick(View view, AnimatedEmojiSpan span) { 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); }); @@ -3066,7 +3152,7 @@ private void incrementHintUse() { 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(); @@ -3086,15 +3172,23 @@ public void preload(int type, int account) { return; } MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_EMOJIPACKS); - if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { + if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION || type == TYPE_CHAT_REACTIONS) { MediaDataController.getInstance(account).checkReactions(); + } else if (type == TYPE_EMOJI_STATUS_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); } } @@ -3158,14 +3252,14 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff stickerSets.clear(); recentStickers.clear(); - if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON) { + if ((!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS && type != TYPE_EMOJI_STATUS_CHANNEL && type != TYPE_EMOJI_STATUS_CHANNEL_TOP) { searchRow = totalCount++; rowHashCodes.add(9L); } else { searchRow = -1; } - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { if (includeEmpty) { totalCount++; rowHashCodes.add(2L); @@ -3199,6 +3293,20 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } + } else if (type == TYPE_CHAT_REACTIONS) { + if (includeEmpty) { + totalCount++; + rowHashCodes.add(2L); + } + List enabledReactions = MediaDataController.getInstance(currentAccount).getEnabledReactionsList(); + for (int i = 0; i < enabledReactions.size(); ++i) { + TLRPC.TL_availableReaction reaction = enabledReactions.get(i); + recentStickers.add(reaction.activate_animation); + } + for (int i = 0; i < recentStickers.size(); ++i) { + rowHashCodes.add(62425L + 13L * recentStickers.get(i).id); + totalCount++; + } } else if (type == TYPE_TOPIC_ICON) { topicEmojiHeaderRow = totalCount++; rowHashCodes.add(12L); @@ -3235,17 +3343,29 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } - if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON) { + if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_CHAT_REACTIONS && type != TYPE_EXPANDABLE_REACTIONS && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM) { longtapHintRow = totalCount++; rowHashCodes.add(6L); } + 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); - for (int i = 0; i < 16; i++) { - if (!tmp.isEmpty()) { - topReactions.add(tmp.remove(0)); + if (type == TYPE_EXPANDABLE_REACTIONS) { + topReactions.addAll(tmp); + } else { + for (int i = 0; i < 16; i++) { + if (!tmp.isEmpty()) { + topReactions.add(tmp.remove(0)); + } } } for (int i = 0; i < topReactions.size(); ++i) { @@ -3254,7 +3374,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff totalCount += topReactions.size(); topReactionsEndRow = totalCount; - if (!tmp.isEmpty()) { + if (!tmp.isEmpty() && type != TYPE_EXPANDABLE_REACTIONS) { boolean allRecentReactionsIsDefault = true; for (int i = 0; i < tmp.size(); i++) { if (tmp.get(i).documentId != 0) { @@ -3280,9 +3400,9 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff 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 { @@ -3290,7 +3410,12 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff 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) { @@ -3300,7 +3425,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - 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) { @@ -3364,13 +3489,16 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - if (installedEmojipacks != null) { + if (installedEmojipacks != null && type != TYPE_EXPANDABLE_REACTIONS) { for (int i = 0, j = 0; i < installedEmojipacks.size(); ++i) { TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); if (set == null || set.set == null) { continue; } - if (type == TYPE_SET_REPLY_ICON && !MessageObject.isTextColorSet(set)) { + if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && !MessageObject.isTextColorSet(set)) { + continue; + } + if ((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)) { @@ -3385,7 +3513,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff 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(); @@ -3396,7 +3524,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } } - if (featuredEmojiPacks != null && !showStickers) { + if (featuredEmojiPacks != null && !showStickers && type != TYPE_EXPANDABLE_REACTIONS) { final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < featuredEmojiPacks.size(); ++i) { TLRPC.StickerSetCovered set1 = featuredEmojiPacks.get(i); @@ -3429,7 +3557,10 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff continue; } - if (type == TYPE_SET_REPLY_ICON && (documents.isEmpty() || !MessageObject.isTextColorEmoji(documents.get(0)))) { + if ((type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) && (documents.isEmpty() || !MessageObject.isTextColorEmoji(documents.get(0)))) { + continue; + } + if ((type == TYPE_EMOJI_STATUS_CHANNEL_TOP || type == TYPE_EMOJI_STATUS_CHANNEL) && !set.channel_emoji_status) { continue; } @@ -3443,7 +3574,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff 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); @@ -3461,7 +3592,7 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } - if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON) { + if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_SET_REPLY_ICON && type != TYPE_SET_REPLY_ICON_BOTTOM && type != TYPE_CHAT_REACTIONS) { positionToButton.put(totalCount, packs.size()); totalCount++; rowHashCodes.add(3321 + 13L * set.id); @@ -3471,7 +3602,9 @@ private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff } } - emojiTabs.updateEmojiPacks(packs); + if (type != TYPE_EXPANDABLE_REACTIONS) { + emojiTabs.updateEmojiPacks(packs); + } if (animated) { emojiGridView.setItemAnimator(emojiItemAnimator); @@ -3509,6 +3642,12 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { } } + public void notifyDataSetChanged() { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + public void expand(int position, View expandButton) { int index = positionToExpand.get(position); Integer from = null, count = null; @@ -3583,19 +3722,36 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(340 - 16), AndroidUtilities.displaySize.x * .95f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f), MeasureSpec.AT_MOST) ); + } else if (type == TYPE_CHAT_REACTIONS) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec((int) (AndroidUtilities.displaySize.y * .35f), MeasureSpec.AT_MOST)); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed && type == TYPE_CHAT_REACTIONS) { + int items = getMeasuredWidth() / AndroidUtilities.dp(42); + int spanCount = items * 5; + layoutManager.setSpanCount(spanCount); + } + } + private int getCacheType() { - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_SET_REPLY_ICON_BOTTOM) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } + + if (type == TYPE_CHAT_REACTIONS) { + return AnimatedEmojiDrawable.getCacheTypeForEnterView(); + } + if (type == TYPE_TOPIC_ICON || type == TYPE_AVATAR_CONSTRUCTOR) { return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; } - 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 { @@ -3652,14 +3808,16 @@ public void dispatchDraw(Canvas canvas) { invalidated = false; int restoreTo = canvas.getSaveCount(); - if (!selectorRect.isEmpty()) { - selectorDrawable.setBounds(selectorRect); - canvas.save(); - if (selectorTransformer != null) { - selectorTransformer.accept(canvas); + if (type != TYPE_CHAT_REACTIONS) { + if (!selectorRect.isEmpty()) { + selectorDrawable.setBounds(selectorRect); + canvas.save(); + if (selectorTransformer != null) { + selectorTransformer.accept(canvas); + } + selectorDrawable.draw(canvas); + canvas.restore(); } - selectorDrawable.draw(canvas); - canvas.restore(); } for (int i = 0; i < viewsGroupedByLines.size(); i++) { @@ -3824,7 +3982,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { skewAlpha = .25f + .75f * skewAlpha; } } - boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || !lite || enterAnimationInProgress() || type == TYPE_AVATAR_CONSTRUCTOR; + boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || !lite || enterAnimationInProgress() || type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_CHAT_REACTIONS; if (!drawInUi) { boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); for (int i = 0; i < imageViewEmojis.size(); i++) { @@ -3898,7 +4056,7 @@ public void prepareDraw(long time) { ImageReceiver imageReceiver; if (imageView.empty) { Drawable drawable = getPremiumStar(); - float scale = type == TYPE_SET_REPLY_ICON ? 1.3f : 1f; + float scale = type == TYPE_SET_REPLY_ICON || type == TYPE_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)); } @@ -4061,7 +4219,7 @@ protected void drawInUiThread(Canvas canvas, float alpha) { Drawable drawable = null; if (imageView.empty) { drawable = getPremiumStar(); - if (type == TYPE_SET_REPLY_ICON) { + if (type == TYPE_SET_REPLY_ICON || type == TYPE_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); @@ -4087,11 +4245,15 @@ protected void drawInUiThread(Canvas canvas, float alpha) { imageView.skewIndex = i; if (scale != 1 || skewAlpha < 1) { canvas.save(); - if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { + if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_CHAT_REACTIONS) { //scale here only selected emoji canvas.scale(0.85f, 0.85f, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); } - skew(canvas, i, imageView.getHeight()); + if (type == TYPE_CHAT_REACTIONS) { + canvas.scale(scale, scale, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); + } else { + skew(canvas, i, imageView.getHeight()); + } drawImage(canvas, drawable, imageView, alpha); canvas.restore(); } else { @@ -4261,7 +4423,7 @@ public void didReceivedNotification(int id, int account, Object... args) { private AnimationNotificationsLocker notificationsLocker = new AnimationNotificationsLocker(); private boolean isAnimatedShow() { - return type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; + return type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_CHAT_REACTIONS; } public void onShow(Runnable dismiss) { @@ -4336,7 +4498,7 @@ public void onAnimationEnd(Animator animation) { } }); - if (isFirstOpen && type != TYPE_SET_REPLY_ICON) { + 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(); @@ -4912,6 +5074,67 @@ public void setSelected(Long documentId) { } } + public void setMultiSelected(Long documentId, boolean animated) { + boolean isSelected; + if (!selectedDocumentIds.contains(documentId)) { + isSelected = true; + selectedDocumentIds.add(documentId); + } else { + isSelected = false; + selectedDocumentIds.remove(documentId); + } + if (emojiGridView != null) { + for (int i = 0; i < emojiGridView.getChildCount(); i++) { + if (emojiGridView.getChildAt(i) instanceof ImageViewEmoji) { + ImageViewEmoji imageViewEmoji = (ImageViewEmoji) emojiGridView.getChildAt(i); + if (imageViewEmoji.span != null && imageViewEmoji.span.getDocumentId() == documentId) { + imageViewEmoji.setViewSelectedWithScale(isSelected, animated); + } else if (imageViewEmoji.document != null && imageViewEmoji.document.id == documentId) { + imageViewEmoji.setViewSelectedWithScale(isSelected, animated); + } + } + } + emojiGridView.invalidate(); + } + } + + public boolean unselect(Long documentId) { + selectedDocumentIds.remove(documentId); + boolean found = false; + if (emojiGridView != null) { + for (int i = 0; i < emojiGridView.getChildCount(); i++) { + if (emojiGridView.getChildAt(i) instanceof ImageViewEmoji) { + ImageViewEmoji imageViewEmoji = (ImageViewEmoji) emojiGridView.getChildAt(i); + if (imageViewEmoji.span != null && imageViewEmoji.span.getDocumentId() == documentId) { + imageViewEmoji.unselectWithScale(); + found = true; + } else if (imageViewEmoji.document != null && imageViewEmoji.document.id == documentId) { + imageViewEmoji.unselectWithScale(); + found = true; + } + } + } + emojiGridView.invalidate(); + if (!found) { + for (int i = 0; i < rowHashCodes.size(); i++) { + long hash = rowHashCodes.get(i); + if (hash == 62425L + 13L * documentId || hash == 3212 + 13L * documentId) { + if (adapter != null) { + adapter.notifyItemChanged(i); + } + found = true; + break; + } + } + } + } + return found; + } + + public void clearSelectedDocuments() { + selectedDocumentIds.clear(); + } + public void setScrimDrawable(AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable scrimDrawable, View drawableParent) { this.scrimColor = scrimDrawable == null || scrimDrawable.getColor() == null ? 0 : scrimDrawable.getColor(); this.scrimDrawable = scrimDrawable; @@ -5586,4 +5809,16 @@ public SetTitleDocument(String title) { 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/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 72475b6f03..536b08afc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -50,7 +50,6 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BackDrawable; @@ -89,9 +88,13 @@ import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.Stories.StoriesController; +import org.telegram.ui.Stories.StoriesListPlaceProvider; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Locale; @@ -113,6 +116,9 @@ public class StatisticActivity extends BaseFragment implements NotificationCente private ChartViewData newFollowersBySourceData; private ChartViewData languagesData; private ChartViewData notificationsData; + private ChartViewData reactionsByEmotionData; + private ChartViewData storyInteractionsData; + private ChartViewData storyReactionsByEmotionData; //chats private OverviewChatData overviewChatData; @@ -162,11 +168,17 @@ public StatisticActivity(Bundle args) { private int loadFromId = -1; private final SparseIntArray recentPostIdtoIndexMap = new SparseIntArray(); + private final SparseIntArray recentStoriesIdtoIndexMap = new SparseIntArray(); private final ArrayList recentPostsAll = new ArrayList<>(); private final ArrayList recentPostsLoaded = new ArrayList<>(); + private final ArrayList recentStoriesAll = new ArrayList<>(); + private final ArrayList recentStoriesLoaded = new ArrayList<>(); + private final ArrayList recentAllSortedDataLoaded = new ArrayList<>(); private boolean messagesIsLoading; private boolean initialLoading = true; private DiffUtilsCallback diffUtilsCallback; + private StoriesController.StoriesList storiesList; + private int storiesListId; private final Runnable showProgressbar = new Runnable() { @Override @@ -180,6 +192,12 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messagesDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.chatInfoDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.boostByChannelCreated); + getNotificationCenter().addObserver(this, NotificationCenter.storiesListUpdated); + StoriesController storiesController = getMessagesController().getStoriesController(); + storiesList = storiesController.getStoriesList(-chatId, StoriesController.StoriesList.TYPE_STATISTICS); + if (storiesList != null) { + storiesListId = storiesList.link(); + } if (chat != null) { loadStatistic(); } else { @@ -188,6 +206,13 @@ public boolean onFragmentCreate() { return super.onFragmentCreate(); } + private void sortAllLoadedData() { + recentAllSortedDataLoaded.clear(); + recentAllSortedDataLoaded.addAll(recentPostsLoaded); + recentAllSortedDataLoaded.addAll(recentStoriesLoaded); + Collections.sort(recentAllSortedDataLoaded, Collections.reverseOrder(Comparator.comparingLong(RecentPostInfo::getDate))); + } + private void loadStatistic() { if (onlyBoostsStat) { return; @@ -203,21 +228,23 @@ private void loadStatistic() { getBroadcastStats.channel = MessagesController.getInstance(currentAccount).getInputChannel(chatId); } - int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response instanceof TLRPC.TL_stats_broadcastStats) { - final ChartViewData[] chartsViewData = new ChartViewData[9]; + final ChartViewData[] chartsViewData = new ChartViewData[12]; TLRPC.TL_stats_broadcastStats stats = (TLRPC.TL_stats_broadcastStats) response; chartsViewData[0] = createViewData(stats.iv_interactions_graph, LocaleController.getString("IVInteractionsChartTitle", R.string.IVInteractionsChartTitle), 1); chartsViewData[1] = createViewData(stats.followers_graph, LocaleController.getString("FollowersChartTitle", R.string.FollowersChartTitle), 0); chartsViewData[2] = createViewData(stats.top_hours_graph, LocaleController.getString("TopHoursChartTitle", R.string.TopHoursChartTitle), 0); - chartsViewData[3] = createViewData(stats.interactions_graph, LocaleController.getString("InteractionsChartTitle", R.string.InteractionsChartTitle), 1); + chartsViewData[3] = createViewData(stats.interactions_graph, LocaleController.getString("ViewsAndSharesChartTitle", R.string.ViewsAndSharesChartTitle), 1); chartsViewData[4] = createViewData(stats.growth_graph, LocaleController.getString("GrowthChartTitle", R.string.GrowthChartTitle), 0); chartsViewData[5] = createViewData(stats.views_by_source_graph, LocaleController.getString("ViewsBySourceChartTitle", R.string.ViewsBySourceChartTitle), 2); chartsViewData[6] = createViewData(stats.new_followers_by_source_graph, LocaleController.getString("NewFollowersBySourceChartTitle", R.string.NewFollowersBySourceChartTitle), 2); chartsViewData[7] = createViewData(stats.languages_graph, LocaleController.getString("LanguagesChartTitle", R.string.LanguagesChartTitle), 4, true); chartsViewData[8] = createViewData(stats.mute_graph, LocaleController.getString("NotificationsChartTitle", R.string.NotificationsChartTitle), 0); + chartsViewData[9] = createViewData(stats.reactions_by_emotion_graph, LocaleController.getString("ReactionsByEmotionChartTitle", R.string.ReactionsByEmotionChartTitle), 2); + chartsViewData[10] = createViewData(stats.story_interactions_graph, LocaleController.getString("StoryInteractionsChartTitle", R.string.StoryInteractionsChartTitle), 1); + chartsViewData[11] = createViewData(stats.story_reactions_by_emotion_graph, LocaleController.getString("StoryReactionsByEmotionChartTitle", R.string.StoryReactionsByEmotionChartTitle), 2); if (chartsViewData[2] != null) { chartsViewData[2].useHourFormat = true; @@ -229,15 +256,35 @@ private void loadStatistic() { recentPostsAll.clear(); - for (int i = 0; i < stats.recent_message_interactions.size(); i++) { + int msgPos = 0; + int storiesPos = 0; + List storiesIds = new ArrayList<>(); + for (TLRPC.PostInteractionCounters interactionCounters : stats.recent_posts_interactions) { RecentPostInfo recentPostInfo = new RecentPostInfo(); - recentPostInfo.counters = stats.recent_message_interactions.get(i); - recentPostsAll.add(recentPostInfo); - recentPostIdtoIndexMap.put(recentPostInfo.counters.msg_id, i); + recentPostInfo.counters = interactionCounters; + + if (interactionCounters instanceof TLRPC.TL_postInteractionCountersMessage) { + recentPostsAll.add(recentPostInfo); + recentPostIdtoIndexMap.put(recentPostInfo.getId(), msgPos); + msgPos++; + } + if (interactionCounters instanceof TLRPC.TL_postInteractionCountersStory) { + storiesIds.add(recentPostInfo.getId()); + recentStoriesAll.add(recentPostInfo); + recentStoriesIdtoIndexMap.put(recentPostInfo.getId(), storiesPos); + storiesPos++; + } } + AndroidUtilities.runOnUIThread(() -> { + if (!storiesList.load(storiesIds)) { + prepareStoriesLoadedItems(); + sortAllLoadedData(); + } + }); + if (recentPostsAll.size() > 0) { - int lastPostId = recentPostsAll.get(0).counters.msg_id; + int lastPostId = recentPostsAll.get(0).getId(); int count = recentPostsAll.size(); getMessagesStorage().getMessages(-chatId, 0, false, count, lastPostId, 0, 0, classGuid, 0, false, 0, 0, true, false, null); } @@ -254,6 +301,10 @@ private void loadStatistic() { languagesData = chartsViewData[7]; notificationsData = chartsViewData[8]; + reactionsByEmotionData = chartsViewData[9]; + storyInteractionsData = chartsViewData[10]; + storyReactionsByEmotionData = chartsViewData[11]; + dataLoaded(chartsViewData); }); @@ -359,17 +410,45 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.boostByChannelCreated); getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.storiesListUpdated); + if (progressDialog[0] != null) { progressDialog[0].dismiss(); progressDialog[0] = null; } + if (storiesList != null) { + storiesList.unlink(storiesListId); + } super.onFragmentDestroy(); } + private void prepareStoriesLoadedItems() { + recentStoriesLoaded.clear(); + for (RecentPostInfo recentPostInfo : recentStoriesAll) { + MessageObject messageObject = storiesList.findMessageObject(recentPostInfo.getId()); + if (messageObject != null) { + recentPostInfo.message = messageObject; + recentStoriesLoaded.add(recentPostInfo); + } + } + recentStoriesIdtoIndexMap.clear(); + recentStoriesAll.clear(); + } + @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.boostByChannelCreated) { + if (id == NotificationCenter.storiesListUpdated) { + StoriesController.StoriesList list = (StoriesController.StoriesList) args[0]; + if (list == storiesList) { + prepareStoriesLoadedItems(); + sortAllLoadedData(); + if (adapter != null) { + recyclerListView.setItemAnimator(null); + diffUtilsCallback.update(); + } + } + } else if (id == NotificationCenter.boostByChannelCreated) { TLRPC.Chat chat = (TLRPC.Chat) args[0]; boolean isGiveaway = (boolean) args[1]; List fragmentStack = getParentLayout().getFragmentStack(); @@ -403,7 +482,7 @@ public void didReceivedNotification(int id, int account, Object... args) { for (int i = 0; i < n; i++) { MessageObject messageObjectFormCache = messArr.get(i); int index = recentPostIdtoIndexMap.get(messageObjectFormCache.getId(), -1); - if (index >= 0 && recentPostsAll.get(index).counters.msg_id == messageObjectFormCache.getId()) { + if (index >= 0 && recentPostsAll.get(index).getId() == messageObjectFormCache.getId()) { if (messageObjectFormCache.deleted) { deletedMessages.add(recentPostsAll.get(index)); } else { @@ -419,7 +498,7 @@ public void didReceivedNotification(int id, int account, Object... args) { for (int i = 0; i < n; i++) { RecentPostInfo postInfo = recentPostsAll.get(i); if (postInfo.message == null) { - loadFromId = postInfo.counters.msg_id; + loadFromId = postInfo.getId(); break; } else { recentPostsLoaded.add(postInfo); @@ -429,6 +508,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (recentPostsLoaded.size() < 20) { loadMessages(); } + sortAllLoadedData(); if (adapter != null) { recyclerListView.setItemAnimator(null); diffUtilsCallback.update(); @@ -450,13 +530,15 @@ public View createView(Context context) { sharedUi = new BaseChartView.SharedUiComponents(); boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chatId, currentAccount); BottomPagerTabs storiesTabsView = new BottomPagerTabs(context, getResourceProvider()) { - @Override public Tab[] createTabs() { Tab[] tabs = new Tab[]{ new Tab(0, R.raw.stats, LocaleController.getString("Statistics", R.string.Statistics)), new Tab(1, R.raw.boosts, LocaleController.getString("Boosts", R.string.Boosts)) }; + tabs[0].customFrameInvert = true; + tabs[0].customEndFrameMid = 25; + tabs[0].customEndFrameEnd = 49; tabs[1].customEndFrameMid = 25; tabs[1].customEndFrameEnd = 49; return tabs; @@ -600,8 +682,8 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { recyclerListView.setOnItemClickListener((view, position) -> { if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { - MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; - MessageStatisticActivity activity = new MessageStatisticActivity(messageObject); + RecentPostInfo recentPostInfo = recentAllSortedDataLoaded.get(position - adapter.recentPostsStartRow); + MessageStatisticActivity activity = new MessageStatisticActivity(recentPostInfo, chatId, true); presentFragment(activity); } else if (position >= adapter.topAdminsStartRow && position <= adapter.topAdminsEndRow) { int i = position - adapter.topAdminsStartRow; @@ -628,7 +710,11 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { recyclerListView.setOnItemLongClickListener((view, position) -> { if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { - MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; + MessageObject messageObject = recentAllSortedDataLoaded.get(position - adapter.recentPostsStartRow).message; + + if (messageObject.isStory()) { + return false; + } final ArrayList items = new ArrayList<>(); final ArrayList actions = new ArrayList<>(); @@ -680,12 +766,15 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { avatarContainer = new ChatAvatarContainer(context, null, false); avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet()); - actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + avatarContainer.getAvatarImageView().setScaleX(0.9f); + avatarContainer.getAvatarImageView().setScaleY(0.9f); + avatarContainer.setRightAvatarPadding(-AndroidUtilities.dp(3)); + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 50 : 0, 0, 40, 0)); TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); avatarContainer.setChatAvatar(chatLocal); - avatarContainer.setTitle(chatLocal.title); + avatarContainer.setTitle(chatLocal == null ? "" : chatLocal.title); avatarContainer.hideSubtitle(); actionBar.setBackButtonDrawable(new BackDrawable(false)); @@ -703,7 +792,6 @@ public void onItemClick(final int id) { actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - if (initialLoading) { progressLayout.setAlpha(0f); AndroidUtilities.runOnUIThread(showProgressbar, 500); @@ -783,6 +871,9 @@ class Adapter extends RecyclerListView.SelectionAdapter { int newFollowersBySourceCell = -1; int languagesCell = -1; int notificationsCell = -1; + int reactionsByEmotionCell = -1; + int storyInteractionsCell = -1; + int storyReactionsByEmotionCell = -1; int recentPostsHeaderCell = -1; int recentPostsStartRow = -1; @@ -816,9 +907,9 @@ class Adapter extends RecyclerListView.SelectionAdapter { public int getItemViewType(int position) { if (position == growCell || position == folowersCell || position == topHourseCell || position == notificationsCell || position == actionsCell || position == groupMembersCell) { return 0; - } else if (position == interactionsCell || position == ivInteractionsCell) { + } else if (position == interactionsCell || position == ivInteractionsCell || position == storyInteractionsCell) { return 1; - } else if (position == viewsBySourceCell || position == newFollowersBySourceCell || position == newMembersBySourceCell || position == messagesCell) { + } else if (position == viewsBySourceCell || position == newFollowersBySourceCell || position == newMembersBySourceCell || position == messagesCell || position == reactionsByEmotionCell || position == storyReactionsByEmotionCell) { return 2; } else if (position == languagesCell || position == membersLanguageCell || position == topDayOfWeeksCell) { return 4; @@ -847,7 +938,7 @@ public int getItemViewType(int position) { @Override public long getItemId(int position) { if (position >= recentPostsStartRow && position < recentPostsEndRow) { - return recentPostsLoaded.get(position - recentPostsStartRow).counters.msg_id; + return recentAllSortedDataLoaded.get(position - recentPostsStartRow).getId(); } if (position == growCell) { return 1; @@ -879,6 +970,12 @@ public long getItemId(int position) { return 14; } else if (position == topDayOfWeeksCell) { return 15; + } else if (position == reactionsByEmotionCell) { + return 16; + } else if (position == storyInteractionsCell) { + return 17; + } else if (position == storyReactionsByEmotionCell) { + return 18; } return super.getItemId(position); } @@ -898,7 +995,7 @@ protected void onDraw(Canvas canvas) { }; v.setWillNotDraw(false); } else if (viewType == 9) { - v = new StatisticPostInfoCell(parent.getContext(), chat) { + v = new StatisticPostInfoCell(parent.getContext(), chat, getResourceProvider()) { @Override protected void onDraw(Canvas canvas) { if (getTranslationY() != 0) { @@ -927,7 +1024,7 @@ protected void onDraw(Canvas canvas) { headerCell.setPadding(headerCell.getPaddingLeft(), AndroidUtilities.dp(16), headerCell.getRight(), AndroidUtilities.dp(16)); v = headerCell; } else if (viewType == 14) { - v = new OverviewCell(parent.getContext()); + v = new OverviewCell(parent.getContext(), isMegagroup ? 2 : 4); } else if (viewType == 15) { v = new ManageChatTextCell(parent.getContext()); v.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -960,6 +1057,12 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi data = topHoursData; } else if (notificationsCell == position) { data = notificationsData; + } else if (reactionsByEmotionCell == position) { + data = reactionsByEmotionData; + } else if (storyInteractionsCell == position) { + data = storyInteractionsData; + } else if (storyReactionsByEmotionCell == position) { + data = storyReactionsByEmotionData; } else if (groupMembersCell == position) { data = groupMembersData; } else if (newMembersBySourceCell == position) { @@ -990,11 +1093,20 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } } else { int i = position - recentPostsStartRow; - ((StatisticPostInfoCell) holder.itemView).setData(recentPostsLoaded.get(i)); + RecentPostInfo recentPostInfo = recentAllSortedDataLoaded.get(i); + StatisticPostInfoCell cell = ((StatisticPostInfoCell) holder.itemView); + cell.setData(recentPostInfo, i == recentAllSortedDataLoaded.size() - 1); + if (recentPostInfo.isStory()) { + cell.setImageViewAction(v -> getOrCreateStoryViewer().open(getContext(), recentPostInfo.getId(), storiesList, StoriesListPlaceProvider.of(recyclerListView))); + } else { + cell.setImageViewAction(null); + } } } else if (type == 13) { ChartHeaderView headerCell = (ChartHeaderView) holder.itemView; + headerCell.showDate(true); headerCell.setDates(minDateOverview, maxDateOverview); + headerCell.setPadding(0, AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16)); if (position == overviewHeaderCell) { headerCell.setTitle(LocaleController.getString("StatisticOverview", R.string.StatisticOverview)); } else if (position == topAdminsHeaderCell) { @@ -1004,14 +1116,16 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } else if (position == topMembersHeaderCell) { headerCell.setTitle(LocaleController.getString("TopMembers", R.string.TopMembers)); } else { - headerCell.setTitle(LocaleController.getString("RecentPosts", R.string.RecentPosts)); + headerCell.showDate(false); + headerCell.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(15), AndroidUtilities.dp(2), AndroidUtilities.dp(6)); + headerCell.setTitle(LocaleController.getString("RecentPostsCapitalize", R.string.RecentPostsCapitalize)); } } else if (type == 14) { OverviewCell overviewCell = (OverviewCell) holder.itemView; if (isMegagroup) { overviewCell.setData(overviewChatData); } else { - overviewCell.setData(overviewChannelData); + overviewCell.setData(overviewChannelData, chat); } } else if (type == 15) { ManageChatTextCell manageChatTextCell = (ManageChatTextCell) holder.itemView; @@ -1038,6 +1152,9 @@ public void update() { ivInteractionsCell = -1; topHourseCell = -1; notificationsCell = -1; + storyReactionsByEmotionCell = -1; + storyInteractionsCell = -1; + reactionsByEmotionCell = -1; groupMembersCell = -1; newMembersBySourceCell = -1; membersLanguageCell = -1; @@ -1216,13 +1333,31 @@ public void update() { } ivInteractionsCell = count++; } + if (reactionsByEmotionData != null && !reactionsByEmotionData.isEmpty && !reactionsByEmotionData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + reactionsByEmotionCell = count++; + } + if (storyInteractionsData != null && !storyInteractionsData.isEmpty && !storyInteractionsData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + storyInteractionsCell = count++; + } + if (storyReactionsByEmotionData != null && !storyReactionsByEmotionData.isEmpty && !storyReactionsByEmotionData.isError) { + if (count > 0) { + shadowDivideCells.add(count++); + } + storyReactionsByEmotionCell = count++; + } shadowDivideCells.add(count++); - if (recentPostsAll.size() > 0) { + if (recentAllSortedDataLoaded.size() > 0) { recentPostsHeaderCell = count++; recentPostsStartRow = count++; - count = recentPostsEndRow = recentPostsStartRow + recentPostsLoaded.size() - 1; + count = recentPostsEndRow = recentPostsStartRow + recentAllSortedDataLoaded.size() - 1; count++; if (recentPostsLoaded.size() != recentPostsAll.size()) { @@ -1348,6 +1483,11 @@ public static abstract class BaseChartCell extends FrameLayout { @SuppressLint("ClickableViewAccessibility") public BaseChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi) { + this(context, type, sharedUi, null); + } + + @SuppressLint("ClickableViewAccessibility") + public BaseChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi, Theme.ResourcesProvider resourcesProvider) { super(context); setWillNotDraw(false); chartType = type; @@ -1389,19 +1529,19 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } } }; - chartHeaderView = new ChartHeaderView(getContext()); + chartHeaderView = new ChartHeaderView(getContext(), resourcesProvider); chartHeaderView.back.setOnTouchListener(new RecyclerListView.FoucsableOnTouchListener()); chartHeaderView.back.setOnClickListener(v -> zoomOut(true)); switch (type) { case 1: - chartView = new DoubleLinearChartView(getContext()); - zoomedChartView = new DoubleLinearChartView(getContext()); + chartView = new DoubleLinearChartView(getContext(), resourcesProvider); + zoomedChartView = new DoubleLinearChartView(getContext(), resourcesProvider); zoomedChartView.legendSignatureView.useHour = true; break; case 2: - chartView = new StackBarChartView(getContext()); - zoomedChartView = new StackBarChartView(getContext()); + chartView = new StackBarChartView(getContext(), resourcesProvider); + zoomedChartView = new StackBarChartView(getContext(), resourcesProvider); zoomedChartView.legendSignatureView.useHour = true; break; case 3: @@ -1437,7 +1577,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto frameLayout.addView(errorTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); progressView.setVisibility(View.GONE); - errorTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray4)); + errorTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray4, resourcesProvider)); chartView.setDateSelectionListener(date -> { @@ -1705,6 +1845,8 @@ public void updateData(ChartViewData viewData, boolean enterTransition) { } errorTextView.setVisibility(View.VISIBLE); } + checkboxContainer.removeAllViews(); + checkBoxes.clear(); chartView.setData(null); return; } @@ -1989,8 +2131,59 @@ public void load(int accountId, int classGuid, int dc, RecyclerListView recycler } public static class RecentPostInfo { - public TLRPC.TL_messageInteractionCounters counters; + public TLRPC.PostInteractionCounters counters; public MessageObject message; + + public long getDate() { + if (message == null) { + return 0; + } + return message.messageOwner.date; + } + + public boolean isStory() { + return counters instanceof TLRPC.TL_postInteractionCountersStory; + } + + public int getViews() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).views; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).views; + } + return 0; + } + + public int getReactions() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).reactions; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).reactions; + } + return 0; + } + + public int getForwards() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).forwards; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).forwards; + } + return 0; + } + + public int getId() { + if (counters instanceof TLRPC.TL_postInteractionCountersMessage) { + return ((TLRPC.TL_postInteractionCountersMessage) counters).msg_id; + } + if (counters instanceof TLRPC.TL_postInteractionCountersStory) { + return ((TLRPC.TL_postInteractionCountersStory) counters).story_id; + } + return 0; + } } private void loadMessages() { @@ -2001,7 +2194,7 @@ private void loadMessages() { int count = 0; for (int i = index; i < n; i++) { if (recentPostsAll.get(i).message == null) { - req.id.add(recentPostsAll.get(i).counters.msg_id); + req.id.add(recentPostsAll.get(i).getId()); count++; if (count > 50) { break; @@ -2031,7 +2224,7 @@ private void loadMessages() { for (int i = 0; i < size; i++) { MessageObject messageObjectFormCache = messageObjects.get(i); int localIndex = recentPostIdtoIndexMap.get(messageObjectFormCache.getId(), -1); - if (localIndex >= 0 && recentPostsAll.get(localIndex).counters.msg_id == messageObjectFormCache.getId()) { + if (localIndex >= 0 && recentPostsAll.get(localIndex).getId() == messageObjectFormCache.getId()) { recentPostsAll.get(localIndex).message = messageObjectFormCache; } } @@ -2041,12 +2234,13 @@ private void loadMessages() { for (int i = 0; i < size; i++) { RecentPostInfo postInfo = recentPostsAll.get(i); if (postInfo.message == null) { - loadFromId = postInfo.counters.msg_id; + loadFromId = postInfo.getId(); break; } else { recentPostsLoaded.add(postInfo); } } + sortAllLoadedData(); recyclerListView.setItemAnimator(null); diffUtilsCallback.update(); }); @@ -2085,6 +2279,9 @@ private static class DiffUtilsCallback extends DiffUtil.Callback { int languagesCell = -1; int topHourseCell = -1; int notificationsCell = -1; + int reactionsByEmotionCell = -1; + int storyInteractionsCell = -1; + int storyReactionsByEmotionCell = -1; int groupMembersCell = -1; int newMembersBySourceCell = -1; @@ -2118,6 +2315,9 @@ public void saveOldState() { notificationsCell = adapter.notificationsCell; startPosts = adapter.recentPostsStartRow; endPosts = adapter.recentPostsEndRow; + reactionsByEmotionCell = adapter.reactionsByEmotionCell; + storyInteractionsCell = adapter.storyInteractionsCell; + storyReactionsByEmotionCell = adapter.storyReactionsByEmotionCell; groupMembersCell = adapter.groupMembersCell; newMembersBySourceCell = adapter.newMembersBySourceCell; @@ -2178,6 +2378,12 @@ public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return true; } else if (oldItemPosition == topDayOfWeeksCell && newItemPosition == adapter.topDayOfWeeksCell) { return true; + } else if (oldItemPosition == reactionsByEmotionCell && newItemPosition == adapter.reactionsByEmotionCell) { + return true; + } else if (oldItemPosition == storyInteractionsCell && newItemPosition == adapter.storyInteractionsCell) { + return true; + } else if (oldItemPosition == storyReactionsByEmotionCell && newItemPosition == adapter.storyReactionsByEmotionCell) { + return true; } return false; } @@ -2256,6 +2462,7 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"message"}, null, null, null, Theme.key_dialogTextBlack)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"views"}, null, null, null, Theme.key_dialogTextBlack)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"shares"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); + arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"likes"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{StatisticPostInfoCell.class}, new String[]{"date"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); arrayList.add(new ThemeDescription(recyclerListView, 0, new Class[]{ChartHeaderView.class}, new String[]{"textView"}, null, null, null, Theme.key_dialogTextBlack)); @@ -2307,7 +2514,7 @@ public ArrayList getThemeDescriptions() { putColorFromData(chartViewData, arrayList, themeDelegate); } } else { - for (int i = 0; i < 9; i++) { + for (int i = 0; i < 12; i++) { ChartViewData chartViewData; if (i == 0) { chartViewData = growthData; @@ -2325,9 +2532,16 @@ public ArrayList getThemeDescriptions() { chartViewData = notificationsData; } else if (i == 7) { chartViewData = topHoursData; - } else { + } else if (i == 8) { chartViewData = languagesData; + } else if (i == 9) { + chartViewData = reactionsByEmotionData; + } else if (i == 10) { + chartViewData = storyInteractionsData; + } else { + chartViewData = storyReactionsByEmotionData; } + putColorFromData(chartViewData, arrayList, themeDelegate); } } @@ -2369,7 +2583,90 @@ public static class OverviewChannelData { String notificationsTitle; String notificationsPrimary; + String reactionsPerPostTitle; + String reactionsPerPostPrimary; + String reactionsPerPostSecondary; + boolean reactionsPerPostUp; + boolean reactionsPerPostVisible; + + String reactionsPerStoryTitle; + String reactionsPerStoryPrimary; + String reactionsPerStorySecondary; + boolean reactionsPerStoryUp; + boolean reactionsPerStoryVisible; + + String viewsPerStoryTitle; + String viewsPerStoryPrimary; + String viewsPerStorySecondary; + boolean viewsPerStoryUp; + boolean viewsPerStoryVisible; + + String sharesPerStoryTitle; + String sharesPerStoryPrimary; + String sharesPerStorySecondary; + boolean sharesPerStoryUp; + boolean sharesPerStoryVisible; + + public static class Quadruple { + public Quadruple(A fist, B second, C third, D fourth) { + this.fist = fist; + this.second = second; + this.third = third; + this.fourth = fourth; + } + + public A fist; + public B second; + public C third; + public D fourth; + } + + private Quadruple prepare(TLRPC.TL_statsAbsValueAndPrev valueAndPrev) { + int dif = (int) (valueAndPrev.current - valueAndPrev.previous); + float difPercent = valueAndPrev.previous == 0 ? 0 : Math.abs(dif / (float) valueAndPrev.previous * 100f); + String primary = AndroidUtilities.formatWholeNumber((int) valueAndPrev.current, 0); + String secondary; + if (dif == 0 || difPercent == 0) { + secondary = ""; + } else if (difPercent == (int) difPercent) { + secondary = String.format(Locale.ENGLISH, "%s (%d%s)", (dif > 0 ? "+" : "") + AndroidUtilities.formatWholeNumber(dif, 0), (int) difPercent, "%"); + } else { + secondary = String.format(Locale.ENGLISH, "%s (%.1f%s)", (dif > 0 ? "+" : "") + AndroidUtilities.formatWholeNumber(dif, 0), difPercent, "%"); + } + boolean up = dif >= 0; + boolean isSectionVisible = dif != 0 || valueAndPrev.current != 0; + return new Quadruple<>(primary, secondary, up, isSectionVisible); + } + public OverviewChannelData(TLRPC.TL_stats_broadcastStats stats) { + Quadruple quadrupleData = prepare(stats.reactions_per_post); + reactionsPerPostTitle = LocaleController.getString("ReactionsPerPost", R.string.ReactionsPerPost); + reactionsPerPostPrimary = quadrupleData.fist; + reactionsPerPostSecondary = quadrupleData.second; + reactionsPerPostUp = quadrupleData.third; + reactionsPerPostVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.reactions_per_story); + reactionsPerStoryTitle = LocaleController.getString("ReactionsPerStory", R.string.ReactionsPerStory); + reactionsPerStoryPrimary = quadrupleData.fist; + reactionsPerStorySecondary = quadrupleData.second; + reactionsPerStoryUp = quadrupleData.third; + reactionsPerStoryVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.views_per_story); + viewsPerStoryTitle = LocaleController.getString("ViewsPerStory", R.string.ViewsPerStory); + viewsPerStoryPrimary = quadrupleData.fist; + viewsPerStorySecondary = quadrupleData.second; + viewsPerStoryUp = quadrupleData.third; + viewsPerStoryVisible = quadrupleData.fourth; + + quadrupleData = prepare(stats.shares_per_story); + sharesPerStoryTitle = LocaleController.getString("SharesPerStory", R.string.SharesPerStory); + sharesPerStoryPrimary = quadrupleData.fist; + sharesPerStorySecondary = quadrupleData.second; + sharesPerStoryUp = quadrupleData.third; + sharesPerStoryVisible = quadrupleData.fourth; + int dif = (int) (stats.followers.current - stats.followers.previous); float difPercent = stats.followers.previous == 0 ? 0 : Math.abs(dif / (float) stats.followers.previous * 100f); followersTitle = LocaleController.getString("FollowersChartTitle", R.string.FollowersChartTitle); @@ -2497,16 +2794,22 @@ public OverviewChatData(TLRPC.TL_stats_megagroupStats stats) { public static class OverviewCell extends LinearLayout { - TextView[] primary = new TextView[4]; - TextView[] secondary = new TextView[4]; - TextView[] title = new TextView[4]; - + TextView[] primary; + TextView[] secondary; + TextView[] title; public OverviewCell(Context context) { + this(context, 2); + } + + public OverviewCell(Context context, int maxRows) { super(context); + primary = new TextView[maxRows * 2]; + secondary = new TextView[maxRows * 2]; + title = new TextView[maxRows * 2]; setOrientation(VERTICAL); - setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(16)); - for (int i = 0; i < 2; i++) { + setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + for (int i = 0; i < maxRows; i++) { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(HORIZONTAL); @@ -2520,9 +2823,10 @@ public OverviewCell(Context context) { secondary[i * 2 + j] = new TextView(context); title[i * 2 + j] = new TextView(context); - primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + primary[i * 2 + j].setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); primary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); title[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + title[i * 2 + j].setGravity(Gravity.LEFT); secondary[i * 2 + j].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); secondary[i * 2 + j].setPadding(AndroidUtilities.dp(4), 0, 0, 0); @@ -2534,29 +2838,88 @@ public OverviewCell(Context context) { contentCell.addView(title[i * 2 + j]); linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); } - addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, i == 0 ? 16 : 0)); + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 16)); } } - public void setData(OverviewChannelData data) { - primary[0].setText(data.followersPrimary); - primary[1].setText(data.notificationsPrimary); - primary[2].setText(data.viewsPrimary); - primary[3].setText(data.sharesPrimary); - - secondary[0].setText(data.followersSecondary); - secondary[0].setTag(data.followersUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - secondary[1].setText(""); - secondary[2].setText(data.viewsSecondary); - secondary[2].setTag(data.viewsUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - secondary[3].setText(data.sharesSecondary); - secondary[3].setTag(data.sharesUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); - - title[0].setText(data.followersTitle); - title[1].setText(data.notificationsTitle); - title[2].setText(data.viewsTitle); - title[3].setText(data.sharesTitle); - + public void setData(OverviewChannelData data, TLRPC.ChatFull chatFull) { + int k = 0; + for (int i = 0; i < primary.length; i++) { + switch (i) { + case 0: + primary[k].setText(data.followersPrimary); + secondary[k].setText(data.followersSecondary); + secondary[k].setTag(data.followersUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.followersTitle); + k++; + break; + case 1: + primary[k].setText(data.notificationsPrimary); + secondary[k].setText(""); + title[k].setText(data.notificationsTitle); + k++; + break; + case 2: + primary[k].setText(data.viewsPrimary); + secondary[k].setText(data.viewsSecondary); + secondary[k].setTag(data.viewsUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.viewsTitle); + k++; + break; + case 3: + primary[k].setText(data.viewsPerStoryPrimary); + secondary[k].setText(data.viewsPerStorySecondary); + secondary[k].setTag(data.viewsPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.viewsPerStoryTitle); + if (data.viewsPerStoryVisible) { + k++; + } + break; + case 4: + primary[k].setText(data.sharesPrimary); + secondary[k].setText(data.sharesSecondary); + secondary[k].setTag(data.sharesUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.sharesTitle); + k++; + break; + case 5: + primary[k].setText(data.sharesPerStoryPrimary); + secondary[k].setText(data.sharesPerStorySecondary); + secondary[k].setTag(data.sharesPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.sharesPerStoryTitle); + if (data.sharesPerStoryVisible) { + k++; + } + break; + case 6: + primary[k].setText(data.reactionsPerPostPrimary); + secondary[k].setText(data.reactionsPerPostSecondary); + secondary[k].setTag(data.reactionsPerPostUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.reactionsPerPostTitle); + if (data.reactionsPerPostVisible) { + k++; + } + break; + case 7: + primary[k].setText(data.reactionsPerStoryPrimary); + secondary[k].setText(data.reactionsPerStorySecondary); + secondary[k].setTag(data.reactionsPerStoryUp ? Theme.key_windowBackgroundWhiteGreenText2 : Theme.key_text_RedRegular); + title[k].setText(data.reactionsPerStoryTitle); + if (data.reactionsPerStoryVisible) { + k++; + } + break; + } + } + for (int i = k; i < primary.length; i++) { + ((ViewGroup) title[i].getParent()).setVisibility(GONE); + } + for (int i = 0; i < getChildCount(); i++) { + ViewGroup viewGroup = (ViewGroup) getChildAt(i); + if (viewGroup.getChildAt(0).getVisibility() == GONE && viewGroup.getChildAt(1).getVisibility() == GONE) { + viewGroup.setVisibility(GONE); + } + } updateColors(); } @@ -2594,7 +2957,7 @@ public void setData(int index, String primary, String secondary, String title) { } private void updateColors() { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < primary.length; i++) { primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java index 2eb82b3b92..2c76eab601 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java @@ -10,11 +10,7 @@ import androidx.core.graphics.ColorUtils; -import com.google.android.exoplayer2.util.Log; - -import org.checkerframework.checker.units.qual.C; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ActionBar.ThemeColors; import java.util.HashSet; import java.util.Objects; @@ -29,7 +25,13 @@ public class DarkThemeResourceProvider implements Theme.ResourcesProvider { ColorFilter animatedEmojiColorFilter; public DarkThemeResourceProvider() { - + sparseIntArray.put(Theme.key_statisticChartSignature, -1214008894); + sparseIntArray.put(Theme.key_statisticChartSignatureAlpha, -1946157057); + sparseIntArray.put(Theme.key_statisticChartHintLine, 452984831); + sparseIntArray.put(Theme.key_statisticChartActiveLine, -665229191); + sparseIntArray.put(Theme.key_statisticChartInactivePickerChart, -667862461); + sparseIntArray.put(Theme.key_statisticChartActivePickerChart, -665229191); + sparseIntArray.put(Theme.key_player_actionBarTitle, Color.WHITE); sparseIntArray.put(Theme.key_dialogIcon, Color.WHITE); sparseIntArray.put(Theme.key_text_RedBold, 0xFFDB4646); sparseIntArray.put(Theme.key_dialogButton, -10177041); @@ -79,7 +81,6 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_chat_messageLinkOut, -5316609); sparseIntArray.put(Theme.key_chat_messagePanelText, -1); sparseIntArray.put(Theme.key_chat_messagePanelIcons, Color.WHITE); - sparseIntArray.put(Theme.key_chat_messagePanelIcons, Color.WHITE); sparseIntArray.put(Theme.key_chat_messagePanelBackground, ColorUtils.setAlphaComponent(Color.BLACK, 122)); sparseIntArray.put(Theme.key_dialogBackground, 0xFF1F1F1F); sparseIntArray.put(Theme.key_dialogBackgroundGray, 0xff000000); @@ -111,6 +112,11 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_actionBarDefaultSubmenuSeparator, 0xF2151515); sparseIntArray.put(Theme.key_chat_emojiPanelStickerSetNameHighlight, Color.WHITE); sparseIntArray.put(Theme.key_windowBackgroundWhiteGrayText4, 0xFF808080); + sparseIntArray.put(Theme.key_voipgroup_nameText, 0xffffffff); + sparseIntArray.put(Theme.key_voipgroup_inviteMembersBackground, 0xff222A33); + sparseIntArray.put(Theme.key_chats_secretName, -9316522); + sparseIntArray.put(Theme.key_chats_name, -1446156); + sparseIntArray.put(Theme.key_chat_serviceBackground, -2110438831); sparseIntArray.put(Theme.key_switchTrack, 0xFF636363); sparseIntArray.put(Theme.key_switchTrackChecked, 0xFF1A9CFF); @@ -118,6 +124,7 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_dialogRadioBackgroundChecked, 0xFF1A9CFF); sparseIntArray.put(Theme.key_dialogTextBlue2, 0xFF1A9CFF); sparseIntArray.put(Theme.key_color_red, -832444); + sparseIntArray.put(Theme.key_checkbox, -12692893); sparseIntArray.put(Theme.key_checkboxDisabled, 0xff626262); sparseIntArray.put(Theme.key_dialogRoundCheckBoxCheck, 0xffffffff); sparseIntArray.put(Theme.key_dialogButtonSelector, 436207615); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index 87556b5d14..37fd08fdc8 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 void updateItems(boolean animated, boolean force) { } if (!hasOverlayText) { - titleView.setText(currentTitle, animated); + titleView.setText(currentTitle, animated && !LocaleController.isRTL); } miniItems.clear(); @@ -911,12 +911,12 @@ public void setTitleOverlayText(String titleOverlayText, int textId) { 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); @@ -1165,7 +1165,7 @@ public void setDialogId(long dialogId) { avatarImage.clearImage(); return; } - avatarDrawable.setInfo(object); + avatarDrawable.setInfo(currentAccount, object); avatarImage.setForUserOrChat(object, avatarDrawable); if (mini) { return; @@ -1640,7 +1640,7 @@ public void setCrossfadeTo(long dialogId) { user = null; } if (object != null) { - crossfadeAvatarDrawable.setInfo(object); + crossfadeAvatarDrawable.setInfo(currentAccount, object); crossfageToAvatarImage.setForUserOrChat(object, crossfadeAvatarDrawable); } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/HwLayouts.java index 32d8b23faf..073ff79872 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 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 4b6cfe206a..758e18a71c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; import android.animation.ValueAnimator; import android.app.Activity; import android.app.Dialog; @@ -27,13 +28,13 @@ import android.os.Build; import android.os.Bundle; import android.text.Layout; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; 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; @@ -50,6 +51,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.collection.LongSparseArray; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; @@ -100,8 +102,10 @@ import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.AvatarSpan; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AlertsCreator; @@ -152,8 +156,10 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.voip.CellFlickerDrawable; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.EmojiAnimationsOverlay; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.MessageStatisticActivity; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.PinchToZoomHelper; import org.telegram.ui.PremiumPreviewFragment; @@ -174,11 +180,14 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.CountDownLatch; public class PeerStoriesView extends SizeNotifierFrameLayout implements NotificationCenter.NotificationCenterDelegate { + public static boolean DISABLE_STORY_REPOSTING = false; public static final float SHARE_BUTTON_OFFSET = 46; private final static long IMAGE_LIVE_TIME = 10_000; private final ImageView optionsIconView; @@ -198,9 +207,18 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final StoryCaptionView storyCaptionView; private CaptionContainerView storyEditCaptionView; private final ImageView shareButton; + @Nullable + private ImageView repostButton; + private final LinearLayout bottomActionsLinearLayout; + @Nullable + private FrameLayout repostButtonContainer; private AnimatedTextView.AnimatedTextDrawable reactionsCounter; + @Nullable + private AnimatedTextView.AnimatedTextDrawable repostCounter; private AnimatedFloat reactionsCounterProgress; + private AnimatedFloat repostCounterProgress; private boolean reactionsCounterVisible; + private boolean repostCounterVisible; private long currentImageTime; private long lastDrawTime; private boolean switchEventSent; @@ -212,7 +230,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final ImageReceiver imageReceiver; private final ImageReceiver leftPreloadImageReceiver; private final ImageReceiver rightPreloadImageReceiver; - private final ArrayList preloadReactionHolders = new ArrayList<>();; + private final ArrayList preloadReactionHolders = new ArrayList<>(); private Runnable onImageReceiverThumbLoaded; private StoryMediaAreasView storyAreasView; @@ -300,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; @@ -402,7 +420,7 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b 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) { @@ -430,15 +448,20 @@ public void showEffect(StoryReactionWidgetView v) { 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); @@ -453,7 +476,7 @@ protected void dispatchDraw(Canvas canvas) { 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(); @@ -475,7 +498,7 @@ protected void dispatchDraw(Canvas canvas) { canvas.drawBitmap(playerSharedScope.player.playerStubBitmap, 0, 0, playerSharedScope.player.playerStubPaint); canvas.restore(); } else { - if (!storyViewer.USE_SURFACE_VIEW || allowDrawSurface) { + if (!storyViewer.USE_SURFACE_VIEW || allowDrawSurface && storyViewer.isShown()) { playerSharedScope.renderView.draw(canvas); } } @@ -733,7 +756,7 @@ public int getTopOffset(int tag) { } public boolean clipWithGradient(int tag) { - return tag == 1 || tag == 2; + return tag == 1 || tag == 2 || tag == 3; } @Override @@ -874,6 +897,51 @@ public void onLinkLongPress(URLSpan span, View spoilersTextView, Runnable done) delegate.showDialog(sheet); } + @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)) + .setTag(3) + .show(true); + return; + } + MessagesController.getInstance(currentAccount).getStoriesController().resolveStoryLink(reply.peerId, reply.storyId, fwdStoryItem -> { + if (fwdStoryItem != null) { + BaseFragment lastFragment = LaunchActivity.getLastFragment(); + if (lastFragment == null) { + return; + } + if (lastFragment.getOrCreateOverlayStoryViewer().isShowing) { + return; + } + storyViewer.setOverlayVisible(true); + fwdStoryItem.dialogId = reply.peerId; + lastFragment.getOrCreateOverlayStoryViewer().open(getContext(), fwdStoryItem, null); + lastFragment.getOrCreateOverlayStoryViewer().setOnCloseListener(() -> { + storyViewer.setOverlayVisible(false); + }); + } else { + BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.story_bomb2, LocaleController.getString(R.string.StoryNotFound)) + .setTag(3) + .show(true); + } + }); + } + @Override public void onEmojiClick(AnimatedEmojiSpan span) { if (span == null || delegate == null) { @@ -923,7 +991,62 @@ public void onEmojiClick(AnimatedEmojiSpan span) { }); ScaleStateListAnimator.apply(shareButton); - likeButtonContainer = new FrameLayout(getContext()); + if (!DISABLE_STORY_REPOSTING) { + repostButton = new ImageView(context); + repostButton.setImageDrawable(sharedResources.repostDrawable); + repostButton.setPadding(padding, padding, padding, padding); + + repostButtonContainer = new FrameLayout(getContext()) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (isChannel && repostCounter != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - repostCounter.getCurrentWidth() - AndroidUtilities.dp(6), 0); + float repostScale = repostCounterProgress.set(repostCounterVisible ? 1f : 0); + canvas.scale(repostScale, repostScale, repostCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); + repostCounter.setAlpha(0xFF); + repostCounter.draw(canvas); + canvas.restore(); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == repostCounter || super.verifyDrawable(who); + } + }; + if (repostCounter != null) { + repostCounter.setCallback(repostButtonContainer); + } + repostButtonContainer.setWillNotDraw(false); + repostButtonContainer.setOnClickListener(v -> tryToOpenRepostStory()); + } + + likeButtonContainer = new FrameLayout(getContext()) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (isChannel && reactionsCounter != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(6), 0); + float reactionScale = reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0); + canvas.scale(reactionScale, reactionScale, reactionsCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); + reactionsCounter.setAlpha(0xFF); + reactionsCounter.draw(canvas); + canvas.restore(); + } + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == reactionsCounter || super.verifyDrawable(who); + } + }; + if (reactionsCounter != null) { + reactionsCounter.setCallback(likeButtonContainer); + } + likeButtonContainer.setWillNotDraw(false); likeButtonContainer.setOnClickListener(v -> { if (currentStory.storyItem != null && currentStory.storyItem.sent_reaction == null) { applyMessageToChat(() -> { @@ -950,7 +1073,13 @@ public void onEmojiClick(AnimatedEmojiSpan span) { storiesLikeButton = new StoriesLikeButton(context, sharedResources); storiesLikeButton.setPadding(padding, padding, padding, padding); likeButtonContainer.addView(storiesLikeButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); + if (repostButtonContainer != null) { + repostButtonContainer.addView(repostButton, LayoutHelper.createFrame(40, 40, Gravity.LEFT)); + } ScaleStateListAnimator.apply(likeButtonContainer, 0.3f, 5f); + if (repostButtonContainer != null) { + ScaleStateListAnimator.apply(repostButtonContainer, 0.3f, 5f); + } imageReceiver.setAllowLoadingOnAttachedOnly(true); imageReceiver.setParentView(storyContainer); @@ -975,15 +1104,23 @@ public void onEmojiClick(AnimatedEmojiSpan span) { storyViewer.presentFragment(ChatActivity.of(dialogId)); } } - -// LaunchActivity.getLastFragment().showAsSheet(profileActivity, params); -// profileActivity.showAsActivity(); }); storyContainer.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 17, 0, 0)); + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(150); + layoutTransition.disableTransitionType(LayoutTransition.APPEARING); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + bottomActionsLinearLayout = new LinearLayout(context); + bottomActionsLinearLayout.setOrientation(LinearLayout.HORIZONTAL); + bottomActionsLinearLayout.setLayoutTransition(layoutTransition); + bottomActionsLinearLayout.addView(shareButton, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); + if (repostButtonContainer != null) { + bottomActionsLinearLayout.addView(repostButtonContainer, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); + } + bottomActionsLinearLayout.addView(likeButtonContainer, LayoutHelper.createLinear(40, 40, Gravity.RIGHT)); - addView(shareButton, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10 + 40, 10)); - addView(likeButtonContainer, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10, 10)); + addView(bottomActionsLinearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT, 0, 0,4,0)); optionsIconView = new ImageView(context); optionsIconView.setImageDrawable(sharedResources.optionsDrawable); @@ -1002,6 +1139,41 @@ public void onEmojiClick(AnimatedEmojiSpan span) { } popupMenu = new CustomPopupMenu(getContext(), resourcesProvider, isSelf) { private boolean edit; + + private void addViewStatistics(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout, TL_stories.StoryItem storyItem) { + if (isChannel) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + if (chat != null) { + TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(chat.id); + if (chatFull == null) { + chatFull = MessagesStorage.getInstance(currentAccount).loadChatInfo(chat.id, true, new CountDownLatch(1), false, false); + } + if (chatFull != null && chatFull.can_view_stats) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_stats, LocaleController.getString("ViewStatistics", R.string.ViewStatistics), false, resourcesProvider).setOnClickListener(v -> { + if (popupMenu != null) { + popupMenu.dismiss(); + } + storyItem.dialogId = dialogId; + storyItem.messageId = storyItem.id; + MessageObject msg = new MessageObject(currentAccount, storyItem); + msg.generateThumbs(false); + storyViewer.presentFragment(new MessageStatisticActivity(msg, chat.id, false) { + @Override + public Theme.ResourcesProvider getResourceProvider() { + return new DarkThemeResourceProvider(); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + }); + }); + } + } + } + } + @Override protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { final boolean userCanEditStory = isSelf || MessagesController.getInstance(currentAccount).getStoriesController().canEditStory(currentStory.storyItem); @@ -1065,7 +1237,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay 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; } @@ -1077,7 +1249,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay editOpened = true; setActive(false); }); - editor.setOnPrepareCloseListener((t, close, sent) -> { + editor.setOnPrepareCloseListener((t, close, sent, did) -> { final long start = System.currentTimeMillis(); if (playerSharedScope.player == null) { delegate.setPopupIsVisible(false); @@ -1158,6 +1330,8 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } + addViewStatistics(popupLayout, storyItem); + if (!unsupported || true) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, str, false, resourcesProvider).setOnClickListener(v -> { saveToGallery(); @@ -1167,14 +1341,14 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } - if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !isChannel) { createStealthModeItem(popupLayout); } if (isChannel && allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { AndroidUtilities.addToClipboard(currentStory.createLink()); - onLickCopied(); + onLinkCopied(); if (popupMenu != null) { popupMenu.dismiss(); } @@ -1286,7 +1460,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay 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( @@ -1315,13 +1489,13 @@ public void setColorFilter(ColorFilter colorFilter) { } } - if (!MessagesController.getInstance(currentAccount).premiumLocked && !isChannel) { + if (!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && !isChannel) { createStealthModeItem(popupLayout); } if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { AndroidUtilities.addToClipboard(currentStory.createLink()); - onLickCopied(); + onLinkCopied(); if (popupMenu != null) { popupMenu.dismiss(); } @@ -1375,6 +1549,8 @@ public void setColorFilter(ColorFilter colorFilter) { } } + addViewStatistics(popupLayout, currentStory.storyItem); + if (!unsupported) { if (!UserObject.isService(dialogId)) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat), false, resourcesProvider).setOnClickListener(v -> { @@ -1516,6 +1692,9 @@ protected void onDismissed() { optionsIconView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); shareButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); likeButtonContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); + if (repostButtonContainer != null) { + repostButtonContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(dp(20), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100))); + } View overlay = storyCaptionView.textSelectionHelper.getOverlayView(context); if (overlay != null) { @@ -2044,13 +2223,13 @@ public void didPressAttachButton() { } @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); } @@ -2411,6 +2590,21 @@ public void startDocumentSelectActivity() { } } + private void tryToOpenRepostStory() { + if (!MessagesController.getInstance(currentAccount).storiesEnabled()) { + return; + } + File f = currentStory.getPath(); + if (f != null && f.exists()) { + if (shareAlert != null) { + shareAlert.dismiss(); + } + AndroidUtilities.runOnUIThread(PeerStoriesView.this::openRepostStory, 120); + } else { + showDownloadAlert(); + } + } + private void shareStory(boolean internal) { if (currentStory.storyItem != null && storyViewer.fragment != null) { TL_stories.StoryItem storyItem = currentStory.storyItem; @@ -2420,9 +2614,12 @@ private void shareStory(boolean internal) { @Override public void appendColors() { sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.2f)); + sparseIntArray.put(Theme.key_chat_messagePanelIcons, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.5f)); } }; - shareAlert = new ShareAlert(storyViewer.fragment.getContext(), null, link, false, link, false, shareResourceProvider) { + TLRPC.Chat chat = isChannel ? MessagesController.getInstance(currentAccount).getChat(-dialogId) : null; + final boolean canRepost = !DISABLE_STORY_REPOSTING && MessagesController.getInstance(currentAccount).storiesEnabled() && (!isChannel && !UserObject.isService(dialogId) || ChatObject.isPublic(chat)); + shareAlert = new ShareAlert(storyViewer.fragment.getContext(), null, null, link, null, false, link, null, false, false, canRepost, shareResourceProvider) { @Override public void dismissInternal() { @@ -2430,6 +2627,11 @@ public void dismissInternal() { 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); @@ -2453,13 +2655,13 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo } } }; + shareAlert.forceDarkThemeForHint = true; currentStory.storyItem.dialogId = dialogId; shareAlert.setStoryToShare(currentStory.storyItem); shareAlert.setDelegate(new ShareAlert.ShareAlertDelegate() { - @Override public boolean didCopy() { - onLickCopied(); + onLinkCopied(); return true; } }); @@ -2473,7 +2675,116 @@ public boolean didCopy() { } } - private void onLickCopied() { + private void openRepostStory() { + Activity activity = AndroidUtilities.findActivity(getContext()); + if (activity == null) { + return; + } + Runnable openRepost = () -> { + StoryRecorder editor = StoryRecorder.getInstance(activity, currentAccount); + long time = 0; + if (playerSharedScope != null && playerSharedScope.player != null) { + time = playerSharedScope.player.currentPosition; + } + StoryEntry entry = StoryEntry.repostStoryItem(currentStory.getPath(), currentStory.storyItem); + editor.openForward(StoryRecorder.SourceView.fromStoryViewer(storyViewer), entry, time, true); + editor.setOnFullyOpenListener(() -> { + editOpened = true; + setActive(false); + }); + editor.setOnPrepareCloseListener((t, close, sent, did) -> { + if (sent) { + DialogStoriesCell.StoryCell cell = null; + DialogStoriesCell storiesCell = null; + if (storyViewer.fragment != null) { + INavigationLayout layout = storyViewer.fragment.getParentLayout(); + if (layout != null) { + List fragmentList = layout.getFragmentStack(); + ArrayList toClose = new ArrayList<>(); + for (int i = fragmentList.size() - 1; i >= 0; --i) { + BaseFragment fragment = fragmentList.get(i); + if (fragment instanceof DialogsActivity) { + DialogsActivity dialogsActivity = (DialogsActivity) fragment; + dialogsActivity.closeSearching(); + storiesCell = dialogsActivity.dialogStoriesCell; + if (storiesCell != null) { + cell = storiesCell.findStoryCell(did); + } + for (int j = 0; j < toClose.size(); ++j) { + layout.removeFragmentFromStack(toClose.get(j)); + } + break; + } + toClose.add(fragment); + } + } + } + if (storyViewer.fragment != null && storyViewer.fragment.overlayStoryViewer != null) { + storyViewer.fragment.overlayStoryViewer.instantClose(); + } + if (storyViewer.fragment != null && storyViewer.fragment.storyViewer != null) { + storyViewer.fragment.storyViewer.instantClose(); + } + storyViewer.instantClose(); + editOpened = false; + final DialogStoriesCell.StoryCell finalCell = cell; + if (storiesCell != null && storiesCell.scrollTo(did)) { + final DialogStoriesCell finalStoriesCell = storiesCell; + storiesCell.afterNextLayout(() -> { + DialogStoriesCell.StoryCell cell2 = finalCell; + if (cell2 == null) { + cell2 = finalStoriesCell.findStoryCell(did); + } + editor.replaceSourceView(StoryRecorder.SourceView.fromStoryCell(cell2)); + close.run(); + }); + } else { + editor.replaceSourceView(StoryRecorder.SourceView.fromStoryCell(finalCell)); + AndroidUtilities.runOnUIThread(close, 400); + } + return; + } + final long start = System.currentTimeMillis(); + if (playerSharedScope != null && playerSharedScope.player == null) { + delegate.setPopupIsVisible(false); + setActive(true); + editOpened = false; + onImageReceiverThumbLoaded = () -> { + AndroidUtilities.cancelRunOnUIThread(close); + AndroidUtilities.runOnUIThread(close); + }; + if (sent) { + updatePosition(); + } + AndroidUtilities.runOnUIThread(close, 400); + return; + } + playerSharedScope.firstFrameRendered = playerSharedScope.player.firstFrameRendered = false; + playerSharedScope.player.setOnReadyListener(() -> { + AndroidUtilities.cancelRunOnUIThread(close); + AndroidUtilities.runOnUIThread(close, Math.max(0, 32L - (System.currentTimeMillis() - start))); + }); + delegate.setPopupIsVisible(false); + if (muteIconView != null) { + muteIconView.setAnimation(sharedResources.muteDrawable); + } + if (videoDuration > 0 && t > videoDuration - 1400) { + t = 0L; + } + setActive(t, true); + editOpened = false; + AndroidUtilities.runOnUIThread(close, 400); + if (sent) { + updatePosition(); + } + }); + }; + if (!delegate.releasePlayer(openRepost)) { + AndroidUtilities.runOnUIThread(openRepost, 80); + } + } + + private void onLinkCopied() { if (currentStory.storyItem == null) { return; } @@ -2516,7 +2827,7 @@ private void bindInternal(int startFromPosition) { if (dialogId >= 0) { isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - avatarDrawable.setInfo(user); + avatarDrawable.setInfo(currentAccount, user); headerView.backupImageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); if (isSelf) { headerView.titleView.setText(LocaleController.getString("SelfStoryTitle", R.string.SelfStoryTitle)); @@ -2544,12 +2855,11 @@ private void bindInternal(int startFromPosition) { 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(chat); + avatarDrawable.setInfo(currentAccount, chat); headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable); headerView.titleView.setText(chat.title); @@ -2580,16 +2890,21 @@ private void bindInternal(int startFromPosition) { chatActivityEnterView.setVisibility(View.GONE); } if (reactionsCounter == null) { - reactionsCounter = new AnimatedTextView.AnimatedTextDrawable() { - @Override - public void invalidateSelf() { - invalidate(); - } - }; + reactionsCounter = new AnimatedTextView.AnimatedTextDrawable(); + reactionsCounter.setCallback(likeButtonContainer); reactionsCounter.setTextColor(resourcesProvider.getColor(Theme.key_windowBackgroundWhiteBlackText)); reactionsCounter.setTextSize(AndroidUtilities.dp(14)); - reactionsCounterProgress = new AnimatedFloat(this); + reactionsCounterProgress = new AnimatedFloat(likeButtonContainer); } + + if (repostButtonContainer != null && repostCounter == null) { + repostCounter = new AnimatedTextView.AnimatedTextDrawable(); + repostCounter.setCallback(repostButtonContainer); + repostCounter.setTextColor(resourcesProvider.getColor(Theme.key_windowBackgroundWhiteBlackText)); + repostCounter.setTextSize(AndroidUtilities.dp(14)); + repostCounterProgress = new AnimatedFloat(repostButtonContainer); + } + if (startFromPosition == -1) { updateSelectedPosition(); } @@ -2817,7 +3132,7 @@ protected void dispatchDraw(Canvas canvas) { } }; selfView.setClickable(true); - addView(selfView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 0, 0, 56 + 40, 0)); + addView(selfView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP, 0, 0, 56 + 80, 0)); selfAvatarsContainer = new View(getContext()) { @@ -2925,21 +3240,13 @@ protected void dispatchDraw(Canvas canvas) { if (isChannel && reactionsCounter != null) { reactionsCounter.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(40)); } - super.dispatchDraw(canvas); - float reactionScale = 0; - if (isChannel && reactionsCounter != null) { - canvas.save(); - canvas.translate(getMeasuredWidth() - reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(12), likeButtonContainer.getY()); - reactionScale = reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0); - canvas.scale(reactionScale, reactionScale, reactionsCounter.getCurrentWidth() / 2f, AndroidUtilities.dp(20)); - reactionsCounter.setAlpha((int) (255 * likeButtonContainer.getAlpha())); - reactionsCounter.draw(canvas); - canvas.restore(); + if (isChannel && repostCounter != null) { + repostCounter.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(40)); } - updateButtonsOffsets(reactionScale); + super.dispatchDraw(canvas); if (movingReaction) { - float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; - float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + float cX = bottomActionsLinearLayout.getX() + likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = bottomActionsLinearLayout.getY() + likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; int size = AndroidUtilities.dp(24); float finalX = AndroidUtilities.lerp(movingReactionFromX, cX - size / 2f, CubicBezierInterpolator.EASE_OUT.getInterpolation(movingReactionProgress)); float finalY = AndroidUtilities.lerp(movingReactionFromY, cY - size / 2f, movingReactionProgress); @@ -2955,8 +3262,8 @@ protected void dispatchDraw(Canvas canvas) { } } if (drawReactionEffect) { - float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; - float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + float cX = bottomActionsLinearLayout.getX() + likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = bottomActionsLinearLayout.getY() + likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; int size = AndroidUtilities.dp(120); if (!drawAnimatedEmojiAsMovingReaction) { reactionEffectImageReceiver.setImageCoords(cX - size / 2f, cY - size / 2f, size, size); @@ -2984,21 +3291,6 @@ protected void dispatchDraw(Canvas canvas) { } } - private void updateButtonsOffsets(float reactionScale) { - if (isChannel) { - float x = -reactionsCounter.getCurrentWidth() - AndroidUtilities.dp(4); - x *= reactionScale; - shareButton.setTranslationX(x); - likeButtonContainer.setTranslationX(x); - } else if (isSelf) { - shareButton.setTranslationX(AndroidUtilities.dp(40)); - likeButtonContainer.setTranslationX(0); - } else { - shareButton.setTranslationX(0); - likeButtonContainer.setTranslationX(0); - } - } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -3206,7 +3498,7 @@ private void updatePosition(boolean preload) { } currentStory.set(uploadingStory); storyAreasView.set(null, StoryMediaAreasView.getMediaAreasFor(uploadingStory.entry), emojiAnimationsOverlay); - allowShare = allowShareLink = false; + allowShare = allowRepost = allowShareLink = false; } else { isUploading = false; isEditing = false; @@ -3229,9 +3521,9 @@ private void updatePosition(boolean preload) { 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); @@ -3244,7 +3536,7 @@ private void updatePosition(boolean preload) { } 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); @@ -3268,11 +3560,11 @@ private void updatePosition(boolean preload) { } 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) { @@ -3298,6 +3590,11 @@ private void updatePosition(boolean preload) { 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); @@ -3356,6 +3653,7 @@ private void updatePosition(boolean preload) { } if (storyChanged || oldUploadingStory != null && currentStory.uploadingStory == null) { + headerView.setOnSubtitleClick(null); if (currentStory.uploadingStory != null) { if (currentStory.uploadingStory.failed) { headerView.setSubtitle(LocaleController.getString("FailedToUploadStory", R.string.FailedToUploadStory), animateSubtitle); @@ -3365,6 +3663,62 @@ private void updatePosition(boolean preload) { } else if (currentStory.storyItem != null) { if (currentStory.storyItem.date == -1) { headerView.setSubtitle(LocaleController.getString("CachedStory", R.string.CachedStory)); + } else if (currentStory.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 (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(" "); + 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(-reply.peerId); + avatar.setChat(chat); + if (chat != null) { + ssb.append(chat.title); + } + } + } else if (currentStory.storyItem.fwd_from.from_name != null) { + ssb.append(currentStory.storyItem.fwd_from.from_name); + } + headerView.setOnSubtitleClick(v -> { + if (reply.peerId != null) { + Bundle args = new Bundle(); + if (reply.peerId >= 0) { + args.putLong("user_id", reply.peerId); + } else { + 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)); + } + } else { + BulletinFactory.of(storyContainer, resourcesProvider) + .createSimpleBulletin(R.raw.error, LocaleController.getString(R.string.StoryHidAccount)) + .setTag(3) + .show(true); + } + }); + + SpannableString dot = new SpannableString("."); + DotDividerSpan dotDividerSpan = new DotDividerSpan(); + dotDividerSpan.setTopPadding(AndroidUtilities.dp(1.5f)); + dotDividerSpan.setSize(5); + dot.setSpan(dotDividerSpan, 0, dot.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + ssb.append(" ").append(dot).append(" ").append(LocaleController.formatShortDate(currentStory.storyItem.date)); + headerView.setSubtitle(ssb, false); } else { CharSequence string = LocaleController.formatStoryDate(currentStory.storyItem.date); if (currentStory.storyItem.edited) { @@ -3404,7 +3758,7 @@ private void updatePosition(boolean preload) { createReplyDisabledView(); unsupportedContainer.setVisibility(View.VISIBLE); replyDisabledTextView.setVisibility(View.VISIBLE); - allowShare = allowShareLink = false; + allowShare = allowRepost = allowShareLink = false; if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); } @@ -3431,8 +3785,8 @@ private void updatePosition(boolean preload) { } } - if (currentStory.caption != null && !unsupported) { - storyCaptionView.captionTextview.setText(currentStory.caption, storyViewer.isTranslating &&!currentStory.captionTranslated && currentStory.storyItem != null && currentStory.storyItem.translated, oldStoryItem == currentStory.storyItem); + if ((currentStory.caption != null || currentStory.getReply() != null) && !unsupported) { + storyCaptionView.captionTextview.setText(currentStory.caption, currentStory.getReply(), storyViewer.isTranslating && !currentStory.captionTranslated && currentStory.storyItem != null && currentStory.storyItem.translated, oldStoryItem == currentStory.storyItem); storyCaptionView.setVisibility(View.VISIBLE); } else { if (isActive) { @@ -3446,13 +3800,20 @@ private void updatePosition(boolean preload) { delegate.onPeerSelected(dialogId, selectedPosition); } if (isChannel) { - shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + shareButton.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + if (repostButtonContainer != null) { + repostButtonContainer.setVisibility(allowRepost ? View.VISIBLE : View.GONE); + } likeButtonContainer.setVisibility(isFailed ? View.GONE : View.VISIBLE); } else { - shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + shareButton.setVisibility(allowShare ? View.VISIBLE : View.INVISIBLE); + if (repostButtonContainer != null) { + repostButtonContainer.setVisibility(View.GONE); + } likeButtonContainer.setVisibility(isSelf ? View.GONE : View.VISIBLE); + likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); } - + likeButtonContainer.requestLayout(); storyViewer.savedPositions.append(dialogId, position); @@ -3649,9 +4010,9 @@ private void updatePreloadImages() { 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); } @@ -3665,7 +4026,8 @@ private void updatePreloadImages() { "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + "&rid=" + storyItem.fileReference + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + - "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]) + + "&sid=" + storyItem.id + "&did=" + storyItem.dialogId; uriesToPrepare.add(Uri.parse("tg://" + FileLoader.getAttachFileName(document) + params)); documentsToPrepare.add(document); } catch (UnsupportedEncodingException e) { @@ -3698,7 +4060,7 @@ private void setStoryImage(TL_stories.StoryItem storyItem, ImageReceiver imageRe 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) { @@ -3711,8 +4073,8 @@ private void setStoryImage(TL_stories.StoryItem storyItem, ImageReceiver imageRe } } 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) { @@ -3765,6 +4127,12 @@ private void updateUserViews(boolean animated) { if (storyItem.views.views_count <= 0) { storyItem.views.views_count = 1; } + if (repostCounter != null && storyItem.views.forwards_count > 0) { + repostCounter.setText(Integer.toString(storyItem.views.forwards_count), animated && repostCounterVisible); + repostCounterVisible = true; + } else { + repostCounterVisible = false; + } if (storyItem.views.reactions_count > 0) { reactionsCounter.setText(Integer.toString(storyItem.views.reactions_count), animated && reactionsCounterVisible); reactionsCounterVisible = true; @@ -3773,6 +4141,9 @@ private void updateUserViews(boolean animated) { } if (!animated) { reactionsCounterProgress.set(reactionsCounterVisible ? 1f : 0, true); + if (repostCounterProgress != null) { + repostCounterProgress.set(repostCounterVisible ? 1f : 0, true); + } } if (storyItem.views.views_count > 0) { selfStatusView.setText(storyViewer.storiesList == null ? LocaleController.getString("NobodyViews", R.string.NobodyViews) : LocaleController.getString("NobodyViewsArchived", R.string.NobodyViewsArchived)); @@ -3786,13 +4157,14 @@ private void updateUserViews(boolean animated) { } else { selfStatusView.setText(""); } - if (reactionsCounterVisible) { - likeButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + reactionsCounter.getAnimateToWidth() + AndroidUtilities.dp(4)); - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10) + AndroidUtilities.dp(40) - likeButtonContainer.getLayoutParams().width; - } else { - likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); + likeButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + (reactionsCounterVisible ? (reactionsCounter.getAnimateToWidth() + AndroidUtilities.dp(4)) : 0)); + ((MarginLayoutParams) selfView.getLayoutParams()).rightMargin = AndroidUtilities.dp(40) + likeButtonContainer.getLayoutParams().width; + if (repostButtonContainer != null) { + repostButtonContainer.getLayoutParams().width = (int) (AndroidUtilities.dp(40) + (repostCounterVisible ? (repostCounter.getAnimateToWidth() + AndroidUtilities.dp(4)) : 0)); + ((MarginLayoutParams) selfView.getLayoutParams()).rightMargin += repostButtonContainer.getLayoutParams().width; + repostButtonContainer.requestLayout(); } + selfView.requestLayout(); likeButtonContainer.requestLayout(); selfAvatarsView.setVisibility(View.GONE); selfAvatarsContainer.setVisibility(View.GONE); @@ -3826,6 +4198,14 @@ private void updateUserViews(boolean animated) { spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); spannableStringBuilder.append(String.valueOf(storyItem.views.reactions_count)); } + if (storyItem.views.forwards_count > 0) { + spannableStringBuilder.append(" d "); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_repost_story); + span.setOverrideColor(0xFF27E861); + span.setTopOffset(AndroidUtilities.dp(0.2f)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); + spannableStringBuilder.append(String.valueOf(storyItem.views.forwards_count)); + } selfStatusView.setText(spannableStringBuilder); if (k == 0) { selfAvatarsView.setVisibility(View.GONE); @@ -3841,8 +4221,8 @@ private void updateUserViews(boolean animated) { selfAvatarsView.setVisibility(View.GONE); selfAvatarsContainer.setVisibility(View.GONE); } - ((LayoutParams) likeButtonContainer.getLayoutParams()).rightMargin = AndroidUtilities.dp(10); likeButtonContainer.getLayoutParams().width = AndroidUtilities.dp(40); + bottomActionsLinearLayout.requestLayout(); } } else { selfStatusView.setText(""); @@ -3862,7 +4242,7 @@ private void requestVideoPlayer(long t) { } 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); } @@ -3874,7 +4254,8 @@ private void requestVideoPlayer(long t) { "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + "&rid=" + currentStory.storyItem.fileReference + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + - "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]) + + "&sid=" + currentStory.storyItem.id + "&did=" + currentStory.storyItem.dialogId; uri = Uri.parse("tg://" + FileLoader.getAttachFileName(document) + params); videoDuration = (long) (MessageObject.getDocumentDuration(document) * 1000); } catch (Exception exception) { @@ -3922,9 +4303,9 @@ public void setDelegate(Delegate delegate) { 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); } @@ -3932,16 +4313,26 @@ public void createBlurredBitmap(Canvas canvas, Bitmap bitmap) { 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) { @@ -4155,7 +4546,7 @@ public void reset() { headerView.backupImageView.getImageReceiver().setVisible(true, true); if (changeBoundAnimator != null) { chatActivityEnterView.reset(); - chatActivityEnterView.setAlpha(1f); + chatActivityEnterView.setAlpha(1f - outT); } if (reactionsContainerLayout != null) { reactionsContainerLayout.reset(); @@ -4465,9 +4856,10 @@ protected void onDraw(Canvas canvas) { subtitleView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); subtitleView[a].setMaxLines(1); subtitleView[a].setSingleLine(true); - subtitleView[a].setEllipsize(TextUtils.TruncateAt.END); + subtitleView[a].setEllipsize(TextUtils.TruncateAt.MIDDLE); subtitleView[a].setTextColor(Color.WHITE); - addView(subtitleView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 54, 18, 86, 0)); + subtitleView[a].setPadding(dp(3), 0, dp(3), dp(1)); + addView(subtitleView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 51, 18, 83, 0)); } titleView.setTextColor(Color.WHITE); @@ -4477,6 +4869,12 @@ public void setSubtitle(CharSequence text) { setSubtitle(text, false); } + public void setOnSubtitleClick(View.OnClickListener listener) { + subtitleView[0].setOnClickListener(listener); + subtitleView[0].setClickable(listener != null); + subtitleView[0].setBackground(listener == null ? null : Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + } + private ValueAnimator subtitleAnimator; public void setSubtitle(CharSequence text, boolean animated) { if (subtitleAnimator != null) { @@ -4484,6 +4882,7 @@ public void setSubtitle(CharSequence text, boolean animated) { subtitleAnimator = null; } if (animated) { + subtitleView[1].setOnClickListener(null); subtitleView[1].setText(subtitleView[0].getText()); subtitleView[1].setVisibility(View.VISIBLE); subtitleView[1].setAlpha(1f); @@ -4662,6 +5061,19 @@ public class StoryItemHolder { public boolean captionTranslated; public CharSequence caption; + private StoryCaptionView.Reply reply; + + public StoryCaptionView.Reply getReply() { + if (reply == null) { + if (storyItem != null) { + reply = StoryCaptionView.Reply.from(currentAccount, storyItem); + } else if (uploadingStory != null) { + reply = StoryCaptionView.Reply.from(uploadingStory); + } + } + return reply; + } + public void updateCaption() { captionTranslated = false; if (currentStory.uploadingStory != null) { @@ -4709,6 +5121,7 @@ public void updateCaption() { void set(TL_stories.StoryItem storyItem) { this.storyItem = storyItem; + this.reply = null; this.uploadingStory = null; skipped = storyItem instanceof TL_stories.TL_storyItemSkipped; isVideo = isVideoInternal(); @@ -4718,8 +5131,8 @@ private boolean isVideoInternal() { 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"); @@ -4729,6 +5142,7 @@ private boolean isVideoInternal() { void set(StoriesController.UploadingStory uploadingStory) { this.uploadingStory = uploadingStory; + this.reply = null; this.storyItem = null; skipped = false; isVideo = isVideoInternal(); @@ -4792,9 +5206,10 @@ boolean hasSound() { 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; } @@ -4830,8 +5245,8 @@ public File getPath() { 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); @@ -5063,14 +5478,12 @@ public void onAnimationEnd(Animator animation) { } if (!BIG_SCREEN) { - ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); - ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); + ((LayoutParams) bottomActionsLinearLayout.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); int bottomPadding = isSelf ? AndroidUtilities.dp(40) : AndroidUtilities.dp(56); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = bottomPadding; storyCaptionView.blackoutBottomOffset = bottomPadding; } else { - ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); - ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); + ((LayoutParams) bottomActionsLinearLayout.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = AndroidUtilities.dp(8); storyCaptionView.blackoutBottomOffset = AndroidUtilities.dp(8); } @@ -5135,7 +5548,29 @@ private void updateViewOffsets() { chatActivityEnterView.checkAnimation(); } boolean popupVisible = chatActivityEnterView != null && chatActivityEnterView.isPopupShowing(); - if (forceUpdateOffsets || progressToReply != storyViewer.swipeToReplyProgress || progressToHideInterface.get() != prevToHideProgress || lastAnimatingKeyboardHeight != animatingKeyboardHeight || progressToKeyboardLocal != progressToKeyboard || progressToDismissLocal != progressToDismiss || progressToRecord != progressToRecording.get() || popupVisible || progressToStickerExpandedLocal != progressToStickerExpanded.get() || progressToText != progressToTextA.get()) { + float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (BIG_SCREEN) { + inputBackgroundPaint.setColor(ColorUtils.blendARGB( + ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), + ColorUtils.setAlphaComponent(Color.BLACK, 170), + progressToKeyboard + )); + inputBackgroundPaint.setAlpha((int) (inputBackgroundPaint.getAlpha() * (1f - progressToDismiss) * hideInterfaceAlpha * (1f - outT))); + } else { + inputBackgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (140 * hideInterfaceAlpha * (1f - outT)))); + } + if ( + forceUpdateOffsets || + progressToReply != storyViewer.swipeToReplyProgress || + progressToHideInterface.get() != prevToHideProgress || + lastAnimatingKeyboardHeight != animatingKeyboardHeight || + progressToKeyboardLocal != progressToKeyboard || + progressToDismissLocal != progressToDismiss || + progressToRecord != progressToRecording.get() || + popupVisible || + progressToStickerExpandedLocal != progressToStickerExpanded.get() || + progressToText != progressToTextA.get() + ) { forceUpdateOffsets = false; lastAnimatingKeyboardHeight = animatingKeyboardHeight; if (progressToHideInterface.get() != prevToHideProgress) { @@ -5158,17 +5593,6 @@ private void updateViewOffsets() { if (reactionsContainerLayout != null) { reactionsContainerLayout.setVisibility(progressToKeyboard > 0 ? View.VISIBLE : View.GONE); } - float hideInterfaceAlpha = getHideInterfaceAlpha(); - if (BIG_SCREEN) { - inputBackgroundPaint.setColor(ColorUtils.blendARGB( - ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), - ColorUtils.setAlphaComponent(Color.BLACK, 170), - progressToKeyboard - )); - inputBackgroundPaint.setAlpha((int) (inputBackgroundPaint.getAlpha() * (1f - progressToDismiss) * hideInterfaceAlpha)); - } else { - inputBackgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (140 * hideInterfaceAlpha))); - } for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); @@ -5187,7 +5611,7 @@ private void updateViewOffsets() { } else if (child instanceof HintView) { HintView hintView = (HintView) child; hintView.updatePosition(); - } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != mediaBanTooltip && child != likeButtonContainer && (likesReactionLayout == null || likesReactionLayout.getReactionsWindow() == null || child != likesReactionLayout.getReactionsWindow().windowView)) { + } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != bottomActionsLinearLayout && child != repostButtonContainer && child != mediaBanTooltip && child != likeButtonContainer && (likesReactionLayout == null || likesReactionLayout.getReactionsWindow() == null || child != likesReactionLayout.getReactionsWindow().windowView)) { float alpha; float translationY = -enterViewBottomOffset * (1f - progressToKeyboard) - animatingKeyboardHeight - AndroidUtilities.dp(8) * (1f - progressToKeyboard) - AndroidUtilities.dp(20) * storyViewer.swipeToReplyProgress; if (BIG_SCREEN) { @@ -5219,8 +5643,11 @@ private void updateViewOffsets() { } } } - shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); - likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } for (int i = 0; i < storyContainer.getChildCount(); i++) { View child = storyContainer.getChildAt(i); @@ -5255,7 +5682,7 @@ private boolean hideCaptionWithInterface() { } private float getHideInterfaceAlpha() { - return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); + return (1f - progressToHideInterface.get()) * (1f - storyViewer.getProgressToSelfViews()); } @Override @@ -5312,7 +5739,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); } } else if (child == likesReactionLayout) { - child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() - AndroidUtilities.dp(18)); + child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() + bottomActionsLinearLayout.getY() - AndroidUtilities.dp(18)); // if (progressToKeyboard > 0) { // sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); // canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); @@ -5719,6 +6146,7 @@ public static class SharedResources { private final RectF finalRect = new RectF(); private final Paint dimPaint = new Paint(); public Drawable shareDrawable; + public Drawable repostDrawable; public Drawable likeDrawable; public Drawable likeDrawableFilled; public Drawable optionsDrawable; @@ -5730,6 +6158,7 @@ public static class SharedResources { SharedResources(Context context) { shareDrawable = ContextCompat.getDrawable(context, R.drawable.media_share); likeDrawable = ContextCompat.getDrawable(context, R.drawable.media_like); + repostDrawable = ContextCompat.getDrawable(context, R.drawable.media_repost); likeDrawableFilled = ContextCompat.getDrawable(context, R.drawable.media_like_active); likeDrawableFilled.setColorFilter(new PorterDuffColorFilter(0xFFFF2E38, PorterDuff.Mode.MULTIPLY)); optionsDrawable = ContextCompat.getDrawable(context, R.drawable.media_more); @@ -5883,6 +6312,21 @@ public void animateOut(boolean out) { privacyButton.setAlpha(1f - outT); } storyCaptionView.setAlpha(1f - outT); + final float progressToDismissLocal = delegate == null ? 0 : delegate.getProgressToDismiss(); + final float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (likeButtonContainer != null) { + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (shareButton != null) { + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (chatActivityEnterView != null) { + chatActivityEnterView.setAlpha(1f - outT); + invalidate(); + } storyContainer.invalidate(); }); outAnimator.addListener(new AnimatorListenerAdapter() { @@ -5904,6 +6348,21 @@ public void onAnimationEnd(Animator animation) { privacyButton.setAlpha(1f - outT); } storyCaptionView.setAlpha(1f - outT); + final float progressToDismissLocal = delegate == null ? 0 : delegate.getProgressToDismiss(); + final float hideInterfaceAlpha = getHideInterfaceAlpha(); + if (likeButtonContainer != null) { + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (shareButton != null) { + shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (repostButtonContainer != null) { + repostButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal) * (1f - outT)); + } + if (chatActivityEnterView != null) { + chatActivityEnterView.setAlpha(1f - outT); + invalidate(); + } storyContainer.invalidate(); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java index 07fa34e56a..54019eac8a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/ProfileStoriesView.java @@ -37,6 +37,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedFloat; @@ -49,6 +50,8 @@ import java.util.Collections; import java.util.List; +import xyz.nextalone.nagram.NaConfig; + public class ProfileStoriesView extends View implements NotificationCenter.NotificationCenterDelegate { private static final int CIRCLES_MAX = 3; @@ -83,6 +86,7 @@ public class ProfileStoriesView extends View implements NotificationCenter.Notif private float fragmentTransitionProgress; private int uploadingStoriesCount; private StoriesController.UploadingStory lastUploadingStory; + private final StoriesUtilities.StoryGradientTools gradientTools = new StoriesUtilities.StoryGradientTools(this, false); public void setProgressToStoriesInsets(float progressToInsets) { if (this.progressToInsets == progressToInsets) { @@ -362,6 +366,14 @@ private void updateStories(boolean animated, boolean asUpdate) { this.count = newCount; titleDrawable.setText(this.count > 0 ? LocaleController.formatPluralString("Stories", this.count) : "", animated && !LocaleController.isRTL); + if (dialogId >= 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + gradientTools.setUser(user, animated); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + gradientTools.setChat(chat, animated); + } + invalidate(); } @@ -505,7 +517,7 @@ protected void dispatchDraw(Canvas canvas) { if (progressToUploading > 0) { rect2.set(rect1); rect2.inset(-dpf2(2.66f + 2.23f / 2), -dpf2(2.66f + 2.23f / 2)); - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); if (radialProgress == null) { radialProgress = new RadialProgress(this); radialProgress.setBackground(null, true, false); @@ -600,7 +612,7 @@ protected void dispatchDraw(Canvas canvas) { } if (read < 1) { - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); unreadPaint.setAlpha((int) (0xFF * (1f - read) * segmentsAlpha)); unreadPaint.setStrokeWidth(dpf2(2.33f)); canvas.drawArc(rect2, a, -widthAngle * appear, false, unreadPaint); @@ -653,7 +665,7 @@ protected void dispatchDraw(Canvas canvas) { } readPaint.setColor(ColorUtils.blendARGB(0x5affffff, 0x80BBC4CC, expandProgress)); readPaintAlpha = readPaint.getAlpha(); - unreadPaint = StoriesUtilities.getUnreadCirclePaint(rect2, true); + unreadPaint = gradientTools.getPaint(rect2); unreadPaint.setStrokeWidth(lerp(dpf2(2.33f), dpf2(1.5f), expandProgress)); readPaint.setStrokeWidth(lerp(dpf2(1.125f), dpf2(1.5f), expandProgress)); if (expandProgress > 0) { @@ -803,6 +815,10 @@ private StoryCircle nearest(StoryCircle a, StoryCircle b, StoryCircle c) { } private void drawArcs(Canvas canvas, StoryCircle A, StoryCircle B, StoryCircle C, Paint paint) { + if (NaConfig.INSTANCE.getShowSquareAvatar().Bool()) { + return; + } + if (A == null && C == null) { canvas.drawArc(B.borderRect, 0, 360, false, paint); } else if (A != null && C != null) { 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 dcd21c654a..e5995d34ba 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.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 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.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 void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat 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 boolean onItemClick(View view, int position) { 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 @@ private void updateViewsVisibility() { 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 @@ private void updateViewsVisibility() { 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 @@ private void updateViewsVisibility() { 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 static void preload(int currentAccount, long dialogId, TL_stories.StoryIt 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 static void preload(int currentAccount, long dialogId, TL_stories.StoryIt } 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 void didReceivedNotification(int id, int account, Object... args) { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 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 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @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; + } + } + 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); } - 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); } } @@ -893,7 +1004,7 @@ public void updateRows() { 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 void updateRows() { } } 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 @@ private void showPremiumAlert() { 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 static class ViewsModel { 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 static class ViewsModel { 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 void loadNext() { 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); - } - views.clear(); - originalViews.clear(); - } - if (useLocalFilters) { - originalViews.addAll(res.views); - applyLocalFilter(); - } else { - views.addAll(res.views); + 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(); + } +// if (useLocalFilters) { +// originalReactions.addAll(res.reactions); +// applyLocalFilter(); +// } else { + reactions.addAll(res.reactions); +// } + + if (!res.reactions.isEmpty()) { + hasNext = true; + } else { + hasNext = false; + } + offset = res.next_offset; + if (TextUtils.isEmpty(offset)) { + hasNext = false; + } - if (!res.views.isEmpty()) { - hasNext = true; + 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 { + if (error != null && "MSG_ID_INVALID".equals(error.text)) { + totalCount = 0; + } hasNext = false; } - offset = res.next_offset; - if (TextUtils.isEmpty(offset)) { - hasNext = false; + + 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); } + 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 { + 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 = ""; + } - if (storyItem.views == null) { - storyItem.views = new TL_stories.TL_storyViews(); + 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; } - 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); + 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; } - 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; } - if (storyItem.views.reactions_count != res.reactions_count) { - storyItem.views.reactions_count = res.reactions_count; - counterUpdated = true; + + 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 (counterUpdated) { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); + if (views.size() < 20 && hasNext) { + loadNext(); } - } else { - 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 void reloadIfNeed(FiltersState state, boolean showContactsFilter, boolean 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 void reloadIfNeed(FiltersState state, boolean showContactsFilter, boolean } else { release(); views.clear(); + reactions.clear(); initial = true; loading = false; hasNext = true; @@ -1266,7 +1487,8 @@ public HeaderView(@NonNull Context context) { @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 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay 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 @@ private void reload() { 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 8054064bf0..e963e3c872 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -120,7 +120,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; @@ -562,12 +562,12 @@ private void preloadStory(long dialogId, TL_stories.StoryItem storyItem) { 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) { @@ -1261,10 +1261,12 @@ public boolean hasUnreadStories(long dialogId) { } } for (int i = 0; i < userStories.stories.size(); i++) { + TL_stories.StoryItem storyItem = userStories.stories.get(i); + if (storyItem == null) continue; // if (userStories.stories.get(i).justUploaded) { // return true; // } - if (userStories.stories.get(i).id > userStories.max_read_id) { + if (storyItem.id > userStories.max_read_id) { return true; } } @@ -1445,6 +1447,8 @@ public void run(TLObject res, TLRPC.TL_error error) { TL_stories.StoryItem storyItem = null; if (res != null) { TL_stories.TL_stories_stories response = (TL_stories.TL_stories_stories) res; + MessagesController.getInstance(currentAccount).putUsers(response.users, false); + MessagesController.getInstance(currentAccount).putChats(response.chats, false); if (response.stories.size() > 0) { storyItem = response.stories.get(0); resolvedStories.put(hash, storyItem); @@ -1726,7 +1730,7 @@ private void startForeground() { } public void start() { - if (entry.isEdit && !entry.editedMedia) { + if ((entry.isEdit || entry.isRepost && entry.repostMedia != null) && (!entry.editedMedia && entry.round == null)) { sendUploadedRequest(null); return; } @@ -1897,8 +1901,31 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { return; } + boolean sendingSameInput = false; TLRPC.InputMedia media = null; - if (uploadedFile != null) { + if (entry.isRepost && !entry.editedMedia && entry.repostMedia != null) { + if (entry.repostMedia instanceof TLRPC.TL_messageMediaDocument) { + TLRPC.TL_inputMediaDocument inputMedia = new TLRPC.TL_inputMediaDocument(); + TLRPC.TL_inputDocument inputDocument = new TLRPC.TL_inputDocument(); + inputDocument.id = entry.repostMedia.document.id; + inputDocument.access_hash = entry.repostMedia.document.access_hash; + inputDocument.file_reference = entry.repostMedia.document.file_reference; + inputMedia.id = inputDocument; + inputMedia.spoiler = entry.repostMedia.spoiler; + media = inputMedia; + sendingSameInput = true; + } else if (entry.repostMedia instanceof TLRPC.TL_messageMediaPhoto) { + TLRPC.TL_inputMediaPhoto inputMedia = new TLRPC.TL_inputMediaPhoto(); + TLRPC.TL_inputPhoto inputPhoto = new TLRPC.TL_inputPhoto(); + inputPhoto.id = entry.repostMedia.photo.id; + inputPhoto.access_hash = entry.repostMedia.photo.access_hash; + inputPhoto.file_reference = entry.repostMedia.photo.file_reference; + inputMedia.id = inputPhoto; + media = inputMedia; + sendingSameInput = true; + } + } + if (media == null && uploadedFile != null) { if (entry.wouldBeVideo()) { TLRPC.TL_inputMediaUploadedDocument inputMediaVideo = new TLRPC.TL_inputMediaUploadedDocument(); inputMediaVideo.file = uploadedFile; @@ -2017,6 +2044,13 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { sendStory.caption = caption[0].toString(); } + if (entry.isRepost) { + sendStory.flags |= 64; + sendStory.fwd_from_id = MessagesController.getInstance(currentAccount).getInputPeer(entry.repostPeer); + sendStory.fwd_from_story = entry.repostStoryId; + sendStory.fwd_modified = !sendingSameInput; + } + if (entry.period == Integer.MAX_VALUE) { sendStory.pinned = true; } else { @@ -2184,7 +2218,7 @@ public boolean isCloseFriends() { } } - private final HashMap[] storiesLists = new HashMap[2]; + private final HashMap[] storiesLists = new HashMap[3]; @Nullable public StoriesList getStoriesList(long dialogId, int type) { @@ -2291,6 +2325,7 @@ public void unlink(int id) { public static final int TYPE_PINNED = 0; public static final int TYPE_ARCHIVE = 1; + public static final int TYPE_STATISTICS = 2; public final int currentAccount; public final long dialogId; @@ -2399,8 +2434,10 @@ private void preloadCache() { storage.getStorageQueue().postRunnable(() -> { SQLiteCursor cursor = null; HashSet loadUserIds = new HashSet<>(); + HashSet loadChatIds = new HashSet<>(); ArrayList cacheResult = new ArrayList<>(); final ArrayList loadedUsers = new ArrayList<>(); + final ArrayList loadedChats = new ArrayList<>(); try { SQLiteDatabase database = storage.getDatabase(); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM profile_stories WHERE dialog_id = %d AND type = %d ORDER BY story_id DESC", dialogId, type)); @@ -2418,6 +2455,20 @@ private void preloadCache() { loadUserIds.addAll(((TLRPC.TL_privacyValueAllowUsers) rule).users); } } + if (storyItem.fwd_from != null && storyItem.fwd_from.from != null) { + long did = DialogObject.getPeerDialogId(storyItem.fwd_from.from); + if (did >= 0) { + loadUserIds.add(did); + } else { + loadChatIds.add(-did); + } + } + 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(); @@ -2428,6 +2479,9 @@ private void preloadCache() { if (!loadUserIds.isEmpty()) { storage.getUsersInternal(TextUtils.join(",", loadUserIds), loadedUsers); } + if (!loadChatIds.isEmpty()) { + storage.getChatsInternal(TextUtils.join(",", loadChatIds), loadedChats); + } } catch (Throwable e) { storage.checkSQLException(e); } finally { @@ -2441,6 +2495,7 @@ private void preloadCache() { FileLog.d("StoriesList "+type+"{"+ dialogId +"} preloadCache {" + storyItemMessageIds(cacheResult) + "}"); preloading = false; MessagesController.getInstance(currentAccount).putUsers(loadedUsers, true); + MessagesController.getInstance(currentAccount).putChats(loadedChats, true); if (invalidateAfterPreload) { invalidateAfterPreload = false; toLoad = null; @@ -2623,11 +2678,26 @@ private void resetCanLoad() { } public boolean load(boolean force, final int count) { + return load(force, count, Collections.emptyList()); + } + + public boolean load(List ids) { + boolean force = false; + for (Integer id : ids) { + if (!messageObjectsMap.containsKey(id)) { + force = true; + break; + } + } + return load(force, 0, ids); + } + + public boolean load(boolean force, final int count, List ids) { if (loading || (done || error || !canLoad()) && !force) { return false; } if (preloading) { - toLoad = i -> load(force, count); + toLoad = i -> load(force, count, ids); return false; } @@ -2643,6 +2713,12 @@ public boolean load(boolean force, final int count) { } req.limit = count; request = req; + } else if (type == TYPE_STATISTICS) { + TL_stories.TL_stories_getStoriesByID req = new TL_stories.TL_stories_getStoriesByID(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); + req.id.addAll(ids); + request = req; + offset_id = -1; } else { TL_stories.TL_stories_getStoriesArchive req = new TL_stories.TL_stories_getStoriesArchive(); req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); @@ -2669,6 +2745,8 @@ public boolean load(boolean force, final int count) { 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; @@ -3055,7 +3133,7 @@ public void updateBlockedUsers(HashSet ids, Runnable done) { })); } - public boolean isBlocked(TL_stories.TL_storyView storyView) { + public boolean isBlocked(TL_stories.StoryView storyView) { if (storyView == null) { return false; } @@ -3078,12 +3156,12 @@ public boolean isBlocked(long did) { 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 cd3998657e..427693c0b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java @@ -16,9 +16,11 @@ import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Cells.DialogCell; +import org.telegram.ui.Cells.ManageChatUserCell; import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.ReactedUserHolderView; import org.telegram.ui.Cells.SharedPhotoVideoCell2; +import org.telegram.ui.Cells.StatisticPostInfoCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.Components.BlurredRecyclerView; import org.telegram.ui.Components.RecyclerListView; @@ -204,17 +206,31 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto } 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; @@ -227,6 +243,28 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto updateClip(holder); return true; } + } else if (child instanceof StatisticPostInfoCell) { + StatisticPostInfoCell cell = (StatisticPostInfoCell) child; + if (cell.getPostInfo().getId() == storyId) { + holder.view = cell.getImageView(); + holder.params = cell.getStoryAvatarParams(); + holder.storyImage = cell.getImageView().getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; + updateClip(holder); + return true; + } + } else if (child instanceof ManageChatUserCell) { + ManageChatUserCell cell = (ManageChatUserCell) child; + if (cell.getStoryItem() != null && cell.getStoryItem().dialogId == dialogId && cell.getStoryItem().messageId == messageId) { + holder.view = cell.getAvatarImageView(); + holder.params = cell.getStoryAvatarParams(); + holder.avatarImage = cell.getAvatarImageView().getImageReceiver(); + holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; + updateClip(holder); + return true; + } } } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java index e43c492ff8..936155b991 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -78,6 +78,16 @@ public void getAllStories(Consumer consumer) { if (data != null) { TL_stories.StoryItem storyItem = TL_stories.StoryItem.TLdeserialize(data, data.readInt32(true), true); storyItem.dialogId = dialogId; + if (storyItem.fwd_from != null && storyItem.fwd_from.from != null) { + MessagesStorage.addLoadPeerInfo(storyItem.fwd_from.from, usersToLoad, chatsToLoad); + } + 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/StoriesUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java index 4f752fcb79..68a1ddf1da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -42,6 +42,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.ColoredImageSpan; @@ -140,6 +141,10 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv unreadState = state = getPredictiveUnreadState(storiesController, dialogId); } + if (params.forceState != 0) { + unreadState = state = params.forceState; + } + if (params.currentState != state) { if (params.currentState == STATE_PROGRESS) { animated = true; @@ -1044,6 +1049,7 @@ public static class AvatarStoryParams { private long dialogId; public int currentState; + public int forceState; public int prevState; public float progressToSate = 1f; public boolean showProgress = false; @@ -1317,4 +1323,90 @@ void cancel() { params = null; } } + + public static class StoryGradientTools { + public final int currentAccount = UserConfig.selectedAccount; + + private final Runnable invalidate; + private final boolean isDialogCell; + private final GradientTools tools; + + private int color1, color2; + private final AnimatedColor animatedColor1, animatedColor2; + + public StoryGradientTools(View view, boolean isDialogCell) { + this(view::invalidate, isDialogCell); + } + + public StoryGradientTools(Runnable invalidate, boolean isDialogCell) { + this.invalidate = invalidate; + this.isDialogCell = isDialogCell; + + animatedColor1 = new AnimatedColor(invalidate, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + animatedColor2 = new AnimatedColor(invalidate, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + tools = new GradientTools(); + tools.isDiagonal = true; + tools.isRotate = true; + resetColors(false); + tools.paint.setStrokeWidth(AndroidUtilities.dpf2(2.3f)); + tools.paint.setStyle(Paint.Style.STROKE); + tools.paint.setStrokeCap(Paint.Cap.ROUND); + } + + public void setUser(TLRPC.User user, boolean animated) { + int colorId = -1; + if (user != null && user.profile_color != null) { + colorId = user.profile_color.color; + } + setColorId(colorId, animated); + } + + public void setChat(TLRPC.Chat chat, boolean animated) { + int colorId = -1; +// if (chat != null && chat.profile_color != null) { +// colorId = chat.profile_color.color; +// } + setColorId(colorId, animated); + } + + public void setColorId(int colorId, boolean animated) { + MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).profilePeerColors; + MessagesController.PeerColor peerColor = peerColors == null ? null : peerColors.getColor(colorId); + if (peerColor != null) { + setColors( + peerColor.getStoryColor1(Theme.isCurrentThemeDark()), + peerColor.getStoryColor2(Theme.isCurrentThemeDark()), + animated + ); + } else { + resetColors(animated); + } + } + private void resetColors(boolean animated) { + if (isDialogCell) { + setColors(Theme.getColor(Theme.key_stories_circle_dialog1), Theme.getColor(Theme.key_stories_circle_dialog2), animated); + } else { + setColors(Theme.getColor(Theme.key_stories_circle1), Theme.getColor(Theme.key_stories_circle2), animated); + } + } + + private void setColors(int color1, int color2, boolean animated) { + this.color1 = color1; + this.color2 = color2; + if (!animated) { + this.animatedColor1.set(color1, true); + this.animatedColor2.set(color2, true); + } + if (invalidate != null) { + invalidate.run(); + } + } + + public Paint getPaint(RectF bounds) { + tools.setColors(animatedColor1.set(color1), animatedColor2.set(color2)); + tools.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); + return tools.paint; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java index 1187a302af..7852c3a557 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -1,5 +1,8 @@ package org.telegram.ui.Stories; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.lerp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -13,6 +16,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -20,6 +24,7 @@ import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; @@ -43,30 +48,42 @@ import androidx.dynamicanimation.animation.SpringForce; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.tgnet.tl.TL_stories; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.LoadingDrawable; +import org.telegram.ui.Components.ReplyMessageLine; import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilersClickDetector; +import org.telegram.ui.Stories.recorder.StoryEntry; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Stack; import java.util.concurrent.atomic.AtomicReference; @@ -93,7 +110,7 @@ public class StoryCaptionView extends NestedScrollView { private OverScroller scroller; private boolean isLandscape; - private int textHash; + private int textHash, replytitleHash, replytextHash; private int prevHeight; private float backgroundAlpha = 1f; @@ -124,7 +141,7 @@ public StoryCaptionView(@NonNull Context context, Theme.ResourcesProvider resour addView(captionContainer, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); paint.setColor(Color.BLACK); - setFadingEdgeLength(AndroidUtilities.dp(12)); + setFadingEdgeLength(dp(12)); setVerticalFadingEdgeEnabled(true); setWillNotDraw(false); @@ -155,6 +172,10 @@ public StoryCaptionView(@NonNull Context context, Theme.ResourcesProvider resour } } + public void onReplyClick(Reply reply) { + + } + public void onLinkLongPress(URLSpan span, View spoilersTextView, Runnable done) { } @@ -251,15 +272,21 @@ public int calculateNewContainerMarginTop(int width, int height) { final StoryCaptionTextView textView = captionTextview; final CharSequence text = textView.state[0].text; + final CharSequence replytitle = textView.state[0].reply != null ? textView.state[0].reply.title : null; + final CharSequence replytext = textView.state[0].reply != null ? textView.state[0].reply.text : null; final int textHash = text.hashCode(); + final int replytitleHash = replytitle != null ? replytitle.hashCode() : 0; + final int replytextHash = replytext != null ? replytext.hashCode() : 0; final boolean isLandscape = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; - if (this.textHash == textHash && this.isLandscape == isLandscape && this.prevHeight == height && !textView.updating) { + if (this.textHash == textHash && this.replytitleHash == replytitleHash && this.replytextHash == replytextHash && this.isLandscape == isLandscape && this.prevHeight == height && !textView.updating) { return -1; } this.textHash = textHash; + this.replytitleHash = replytitleHash; + this.replytextHash = replytextHash; this.isLandscape = isLandscape; this.prevHeight = height; @@ -364,7 +391,7 @@ private void startSpringAnimationIfNotRunning(float velocityY) { springAnimation.setStartVelocity(velocityY); springAnimation.start(); } - if (getScrollY() < AndroidUtilities.dp(2)) { + if (getScrollY() < dp(2)) { collapse(); } } @@ -468,7 +495,7 @@ public void invalidate() { } public float getProgressToBlackout() { - int maxHeight = Math.min(prevHeight, AndroidUtilities.dp(40)); + int maxHeight = Math.min(prevHeight, dp(40)); return Utilities.clamp((getScrollY() - captionTextview.getTranslationY()) / maxHeight, 1f, 0); } @@ -488,9 +515,9 @@ public void expand(boolean force) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); valueAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); - final float toScrollY = Math.min(getMeasuredHeight() - blackoutBottomOffset - AndroidUtilities.dp(64), captionContainer.getBottom() - getMeasuredHeight()); - setScrollY((int) AndroidUtilities.lerp(fromScrollY, toScrollY, value)); - captionTextview.progressToExpand = AndroidUtilities.lerp(fromP, toP, value); + final float toScrollY = Math.min(getMeasuredHeight() - blackoutBottomOffset - dp(64), captionContainer.getBottom() - getMeasuredHeight()); + setScrollY((int) lerp(fromScrollY, toScrollY, value)); + captionTextview.progressToExpand = lerp(fromP, toP, value); captionTextview.invalidate(); }); valueAnimator.setDuration(250); @@ -511,8 +538,8 @@ public void collapse() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); valueAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); - setScrollY((int) AndroidUtilities.lerp(fromScrollY, toScrollY, value)); - captionTextview.progressToExpand = AndroidUtilities.lerp(fromP, toP, value); + setScrollY((int) lerp(fromScrollY, toScrollY, value)); + captionTextview.progressToExpand = lerp(fromP, toP, value); captionTextview.invalidate(); }); valueAnimator.setDuration(250); @@ -548,6 +575,209 @@ public void checkCancelTextSelection() { } } + public static class Reply { + private int currentAccount; + 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); + public final Drawable ripple = Theme.createRadSelectorDrawable(0x20ffffff, 0, 0); + + public CharSequence title, text; + public boolean updateText; + + public Text titleLayout, textLayout; + + private boolean loaded, loading; + private View view; + public ReplyMessageLine repostLine; + private Runnable whenLoaded; + + public void listen(View view, Runnable whenLoaded) { + this.view = view; + this.whenLoaded = whenLoaded; + this.repostLine = new ReplyMessageLine(view); + ripple.setCallback(view); + animatedSmall.setParent(view); + bounce.setView(view); + load(); + } + + public void load() { + if (!loaded && !loading && peerId != null && storyId != null && view != null) { + loading = true; + MessagesController.getInstance(currentAccount).getStoriesController().resolveStoryLink(peerId, storyId, fwdStoryItem -> { + loaded = true; + if (fwdStoryItem != null && fwdStoryItem.caption != null) { + updateText = true; + text = fwdStoryItem.caption; + small = TextUtils.isEmpty(text); + if (view != null) { + view.invalidate(); + } + if (whenLoaded != null) { + whenLoaded.run(); + } + } + }); + } + } + + public static Reply from(int currentAccount, TL_stories.StoryItem storyItem) { + if (storyItem == null) { + return null; + } + 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); + } + reply.small = true; + if ((storyItem.fwd_from.flags & 4) != 0) { + reply.storyId = storyItem.fwd_from.story_id; + } + reply.load(); + return reply; + } + 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; + } + } + } + return null; + } + + public static Reply from(StoriesController.UploadingStory uploadingStory) { + if (uploadingStory == null || uploadingStory.entry == null) { + return null; + } + 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); + private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Path clipRipple = new Path(); + public final RectF bounds = new RectF(); + private int width; + + public int height() { + return small ? dp(22) : dp(42); + } + + public int width() { + return width; + } + + public void setPressed(boolean pressed, float x, float y) { + bounce.setPressed(pressed); + ripple.setState(pressed ? new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled} : new int[] {}); + if (pressed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ripple.setHotspot(x, y); + } + } + + public void draw(Canvas canvas, float width) { + if (titleLayout == null) { + titleLayout = new Text(title == null ? "" : title, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + if (textLayout == null || updateText) { + textLayout = new Text(text == null ? "" : text, 14); + } + + final float smallT = animatedSmall.set(small); + + backgroundPaint.setColor(0x40000000); + final int boxwidth = this.width = (int) Math.min(width, lerp(dp(20), dp(18), smallT) + Math.max(titleLayout.getCurrentWidth(), textLayout.getCurrentWidth())); + final int boxheight = lerp(dp(42), dp(22), smallT); + bounds.set(0, 0, boxwidth, boxheight); + + canvas.save(); + final float s = bounce.getScale(.02f); + canvas.scale(s, s, bounds.centerX(), bounds.centerY()); + final float r = lerp(dp(5), dp(11), smallT); + canvas.drawRoundRect(bounds, r, r, backgroundPaint); + + canvas.save(); + clipRipple.rewind(); + clipRipple.addRoundRect(bounds, r, r, Path.Direction.CW); + canvas.clipPath(clipRipple); + ripple.setBounds(0, 0, boxwidth, boxheight); + ripple.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.clipRect(0, 0, dp(3), dp(42)); + AndroidUtilities.rectTmp.set(0, 0, dp(10), dp(42)); + linePaint.setColor(0xFFFFFFFF); + linePaint.setAlpha((int) (0xFF * (1f - smallT))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), linePaint); + canvas.restore(); + int ellipsize = boxwidth - dp(20); + if (boxwidth < width) { + ellipsize = (int) Math.min(ellipsize + dp(12), width - dp(20)); + } + titleLayout.ellipsize(ellipsize).draw(canvas, lerp(dp(10), dp(7), smallT), lerp(dp(12), dp(11), smallT), 0xFFFFFFFF, 1f); + textLayout.ellipsize(ellipsize).draw(canvas, dp(10), dp(30), 0xFFFFFFFF, 1f - smallT); + canvas.restore(); + } + } + public class StoryCaptionTextView extends View implements TextSelectionHelper.SimpleSelectabeleView { private final PorterDuffColorFilter emojiColorFilter; @@ -562,7 +792,7 @@ public class StoryCaptionTextView extends View implements TextSelectionHelper.Si float showMoreX; public int collapsedTextHeight(int height) { - return AndroidUtilities.lerp(state[0].collapsedTextHeight(height), state[1] == null ? 0 : state[1].collapsedTextHeight(height), updateT); + return lerp(state[0].collapsedTextHeight(height), state[1] == null ? 0 : state[1].collapsedTextHeight(height), updateT); } public class TextState { @@ -582,6 +812,7 @@ public class TextState { int textHeight; CharSequence text = ""; + public Reply reply; public boolean translating; public final AnimatedFloat translateT = new AnimatedFloat(StoryCaptionView.this, 0, 400, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -590,6 +821,7 @@ public class TextState { private Path loadingPath = new Path(); public int collapsedTextHeight(int height) { + final int replyOffset = reply != null ? reply.height() + dp(8) : 0; if (fullLayout == null) { return height - (verticalPadding * 2 + textHeight); } @@ -600,7 +832,7 @@ public int collapsedTextHeight(int height) { } int i = Math.min(3, lineCount); final int lineHeight = textPaint.getFontMetricsInt(null); - return height - lineHeight * (i + 1); + return height - lineHeight * (i + 1) - replyOffset; } public TextState() { @@ -629,8 +861,17 @@ public TextState() { loadingDrawable.setCallback(StoryCaptionTextView.this); } - public void setup(CharSequence text) { + public void setup(CharSequence text, Reply reply) { this.text = text; + this.reply = reply; + if (this.reply != null) { + this.reply.listen(StoryCaptionTextView.this, () -> { + sizeCached = 0; + requestLayout(); + StoryCaptionView.this.updateTopMargin(); + StoryCaptionView.this.requestLayout(); + }); + } sizeCached = 0; requestLayout(); } @@ -639,6 +880,9 @@ public void measure(int width) { if (TextUtils.isEmpty(text)) { fullLayout = null; textHeight = 0; + if (reply != null) { + textHeight += reply.height() + dp(4); + } if (this == state[0]) { showMore = null; } @@ -649,6 +893,10 @@ public void measure(int width) { } fullLayout = makeTextLayout(textPaint, text, width); textHeight = fullLayout.getHeight(); + int replyOffset = 0; + if (reply != null) { + textHeight += (replyOffset = reply.height() + dp(8)); + } float space = textPaint.measureText(" "); shouldCollapse = fullLayout.getLineCount() > 3; if (shouldCollapse && fullLayout.getLineCount() == 4) { @@ -664,7 +912,7 @@ public void measure(int width) { String showMoreText = LocaleController.getString("ShowMore", R.string.ShowMore); showMore = makeTextLayout(showMorePaint, showMoreText, width); - showMoreY = verticalPadding + collapsedY - AndroidUtilities.dpf2(0.3f); + showMoreY = verticalPadding + replyOffset + collapsedY - AndroidUtilities.dpf2(0.3f); showMoreX = width + horizontalPadding - showMorePaint.measureText(showMoreText); } @@ -698,7 +946,7 @@ public void measure(int width) { lineInfo.staticLayout = layout; lineInfo.finalX = fullLayout.getLineLeft(line); lineInfo.finalY = fullLayout.getLineTop(line) + fullLayout.getTopPadding(); - if (x < showMoreX - AndroidUtilities.dp(16)) { + if (x < showMoreX - dp(16)) { lineInfo.collapsedY = collapsedY; lineInfo.collapsedX = x; x += Math.abs(layout.getLineRight(0) - layout.getLineLeft(0)) + space; @@ -726,7 +974,7 @@ public void draw(Canvas canvas, float alpha) { return; } - alpha = AndroidUtilities.lerp(alpha, alpha * .7f, loadingT); + alpha = lerp(alpha, alpha * .7f, loadingT); if (alpha >= 1) { drawInternal(canvas, loadingT); } else { @@ -760,8 +1008,17 @@ private void putLayoutRects(Layout layout, float tx, float ty) { } private void drawInternal(Canvas canvas, float loadingT) { + int replyOffset = 0; + if (reply != null) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + reply.draw(canvas, getWidth() - horizontalPadding - horizontalPadding); + replyOffset = reply.height() + dp(8); + canvas.restore(); + } + canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); if (links.draw(canvas)) { invalidate(); } @@ -773,7 +1030,7 @@ private void drawInternal(Canvas canvas, float loadingT) { if (!spoilers.isEmpty() || firstLayout == null) { if (fullLayout != null) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); if (textSelectionHelper.isInSelectionMode()) { textSelectionHelper.draw(canvas); } @@ -783,26 +1040,26 @@ private void drawInternal(Canvas canvas, float loadingT) { canvas.restore(); if (drawLoading) { - putLayoutRects(fullLayout, horizontalPadding, verticalPadding); + putLayoutRects(fullLayout, horizontalPadding, verticalPadding + replyOffset); } } } else { if (textSelectionHelper.isInSelectionMode()) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); textSelectionHelper.draw(canvas); canvas.restore(); } if (firstLayout != null) { canvas.save(); - canvas.translate(horizontalPadding, verticalPadding); + canvas.translate(horizontalPadding, verticalPadding + replyOffset); drawLayout(firstLayout, canvas, spoilers); firstLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, firstLayoutEmoji, firstLayout); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, firstLayout, firstLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); canvas.restore(); if (drawLoading) { - putLayoutRects(firstLayout, horizontalPadding, verticalPadding); + putLayoutRects(firstLayout, horizontalPadding, verticalPadding + replyOffset); } } @@ -817,12 +1074,12 @@ private void drawInternal(Canvas canvas, float loadingT) { if (progressToExpand == 0) { continue; } - canvas.translate(horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + canvas.translate(horizontalPadding + lineInfo.finalX, verticalPadding + replyOffset + lineInfo.finalY); canvas.saveLayerAlpha(0, 0, lineInfo.staticLayout.getWidth(), lineInfo.staticLayout.getHeight(), (int) (255 * progressToExpand), Canvas.ALL_SAVE_FLAG); drawLayout(lineInfo.staticLayout, canvas, spoilers); if (drawLoading) { - putLayoutRects(lineInfo.staticLayout, horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + putLayoutRects(lineInfo.staticLayout, horizontalPadding + lineInfo.finalX, verticalPadding + replyOffset + lineInfo.finalY); } lineInfo.staticLayout.draw(canvas); @@ -831,12 +1088,12 @@ private void drawInternal(Canvas canvas, float loadingT) { canvas.restore(); //textPaint.setAlpha(255); } else { - float offsetX = AndroidUtilities.lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); - float offsetY = AndroidUtilities.lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); - canvas.translate(horizontalPadding + offsetX, verticalPadding + offsetY); + float offsetX = lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); + float offsetY = lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); + canvas.translate(horizontalPadding + offsetX, verticalPadding + replyOffset + offsetY); //drawLayout(lineInfo.staticLayout, canvas, -offsetX, -offsetY); if (drawLoading) { - putLayoutRects(lineInfo.staticLayout, horizontalPadding + offsetX, verticalPadding + offsetY); + putLayoutRects(lineInfo.staticLayout, horizontalPadding + offsetX, verticalPadding + replyOffset + offsetY); } lineInfo.staticLayout.draw(canvas); lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, lineInfo.layoutEmoji, lineInfo.staticLayout); @@ -868,8 +1125,9 @@ public boolean touch(MotionEvent event) { } boolean linkResult = false; if (allowIntercept && event.getAction() == MotionEvent.ACTION_DOWN || (pressedLink != null || pressedEmoji != null) && event.getAction() == MotionEvent.ACTION_UP) { + final int replyOffset = reply == null ? 0 : reply.height() + dp(8); int x = (int) (event.getX() - horizontalPadding); - int y = (int) (event.getY() - verticalPadding); + int y = (int) (event.getY() - verticalPadding - replyOffset); final int line = fullLayout.getLineForVertical(y); final int off = fullLayout.getOffsetForHorizontal(line, x); final float left = fullLayout.getLineLeft(line); @@ -986,16 +1244,16 @@ public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesPr textPaint.setColor(Color.WHITE); textPaint.linkColor = Color.WHITE;//Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider); - textPaint.setTextSize(AndroidUtilities.dp(15)); + textPaint.setTextSize(dp(15)); showMorePaint.setColor(Color.WHITE); showMorePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - showMorePaint.setTextSize(AndroidUtilities.dp(16)); + showMorePaint.setTextSize(dp(16)); xRefPaint.setColor(0xff000000); xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); - xRefGradinetPaint.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(16), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); + xRefGradinetPaint.setShader(new LinearGradient(0, 0, dp(16), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); xRefGradinetPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); emojiColorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); @@ -1003,20 +1261,20 @@ public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesPr @Override protected boolean verifyDrawable(@NonNull Drawable who) { - if (state[0] != null && state[0].loadingDrawable == who) { + if (state[0] != null && (state[0].loadingDrawable == who || state[0].reply != null && state[0].reply.ripple == who)) { return true; } - if (state[1] != null && state[1].loadingDrawable == who) { + if (state[1] != null && (state[1].loadingDrawable == who || state[1].reply != null && state[1].reply.ripple == who)) { return true; } return super.verifyDrawable(who); } - public void setText(CharSequence text, boolean translating, boolean animated) { + public void setText(CharSequence text, Reply reply, boolean translating, boolean animated) { if (text == null) { text = ""; } - if (TextUtils.equals(state[0].text, text)) { + if (TextUtils.equals(state[0].text, text) && state[0].reply == reply) { state[0].translating = translating; invalidate(); return; @@ -1030,16 +1288,16 @@ public void setText(CharSequence text, boolean translating, boolean animated) { if (state[1] == null) { state[1] = new TextState(); } - state[1].setup(state[0].text); + state[1].setup(state[0].text, state[0].reply); state[1].translating = state[0].translating; state[1].translateT.set(state[0].translateT.get(), true); - state[0].setup(text); + state[0].setup(text, reply); state[0].translating = translating; state[0].translateT.set(0, true); updateT = 1; animateUpdate(); } else { - state[0].setup(text); + state[0].setup(text, reply); state[0].translating = translating; invalidate(); updateT = 0; @@ -1080,8 +1338,8 @@ public void onAnimationEnd(Animator animation) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int size = widthMeasureSpec + heightMeasureSpec << 16; - horizontalPadding = AndroidUtilities.dp(16); - verticalPadding = AndroidUtilities.dp(8); + horizontalPadding = dp(16); + verticalPadding = dp(8); if (sizeCached != size) { sizeCached = size; int width = MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding * 2; @@ -1090,7 +1348,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { state[1].measure(width); } } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + AndroidUtilities.lerp(state[0].textHeight, state[1] == null ? 0 : state[1].textHeight, updateT), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + lerp(state[0].textHeight, state[1] == null ? 0 : state[1].textHeight, updateT), MeasureSpec.EXACTLY)); } @Override @@ -1113,11 +1371,11 @@ protected void onDraw(Canvas canvas) { xRefPaint.setAlpha((int) (255 * alpha)); showMorePaint.setAlpha((int) (255 * alpha)); canvas.save(); - canvas.translate(showMoreX - AndroidUtilities.dp(32), showMoreY); - canvas.drawRect(0, 0, AndroidUtilities.dp(32), showMore.getHeight() + verticalPadding, xRefGradinetPaint); + canvas.translate(showMoreX - dp(32), showMoreY); + canvas.drawRect(0, 0, dp(32), showMore.getHeight() + verticalPadding, xRefGradinetPaint); canvas.restore(); - canvas.drawRect(showMoreX - AndroidUtilities.dp(16), showMoreY, getMeasuredWidth(), showMoreY + showMore.getHeight() + verticalPadding, xRefPaint); + canvas.drawRect(showMoreX - dp(16), showMoreY, getMeasuredWidth(), showMoreY + showMore.getHeight() + verticalPadding, xRefPaint); canvas.save(); canvas.translate(showMoreX, showMoreY); showMore.draw(canvas); @@ -1207,8 +1465,26 @@ public boolean dispatchTouchEvent(MotionEvent event) { allowIntercept = false; } } + boolean r = false; + if (state[0] != null && state[0].reply != null) { + AndroidUtilities.rectTmp.set(horizontalPadding, verticalPadding, horizontalPadding + state[0].reply.width(), verticalPadding + state[0].reply.height()); + final boolean hit = AndroidUtilities.rectTmp.contains(event.getX(), event.getY()); + if (hit) { + allowIntercept = false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN && hit) { + state[0].reply.setPressed(true, event.getX(), event.getY()); + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (event.getAction() == MotionEvent.ACTION_UP && state[0].reply.bounce.isPressed()) { + onReplyClick(state[0].reply); + } + state[0].reply.setPressed(false, event.getX(), event.getY()); + } + r = hit; + } if (allowIntercept && (expanded || state[0].firstLayout == null)) { - textSelectionHelper.update(horizontalPadding, verticalPadding); + final int replyOffset = state[0] != null && state[0].reply != null ? state[0].reply.height() + dp(8) : 0; + textSelectionHelper.update(horizontalPadding, verticalPadding + replyOffset); textSelectionHelper.onTouchEvent(event); } if (!textSelectionHelper.isInSelectionMode() && allowIntercept && allowClickSpoilers && state[0].clickDetector.onTouchEvent(event)) { @@ -1216,7 +1492,7 @@ public boolean dispatchTouchEvent(MotionEvent event) { textSelectionHelper.clear(); return true; } - return super.dispatchTouchEvent(event); + return super.dispatchTouchEvent(event) || r; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java index f993713023..cced3d0c70 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 @@ 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.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 @@ 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 void set(TL_stories.StoryItem storyItem, ArrayList } } selectedArea = null; + parentHighlightScaleAlpha.set(0, true); invalidate(); onHintVisible(false); malicious = false; @@ -131,7 +144,7 @@ public void set(TL_stories.StoryItem storyItem, ArrayList } 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 void set(TL_stories.StoryItem storyItem, ArrayList 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 void onClick(View v) { 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 @@ protected boolean disablePermissionCheck() { return; } - selectedArea = (AreaView) v; + selectedArea = lastSelectedArea = (AreaView) v; invalidate(); if (hintView != null) { hintView.hide(); @@ -236,7 +260,12 @@ protected boolean disablePermissionCheck() { 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 @@ protected boolean disablePermissionCheck() { 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 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } + 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 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 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 @@ private void drawHighlight(Canvas canvas) { 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 @@ private void drawHighlight(Canvas canvas) { } 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 boolean hasSelected() { 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 static class AreaView extends View { 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 AreaView(Context context, View parent, TL_stories.MediaArea mediaArea) { 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 AreaView(Context context, View parent, TL_stories.MediaArea mediaArea) { 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 @@ protected void onDraw(Canvas canvas) { 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 90000e9883..d1a9c3d8e9 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 @@ protected void dispatchDraw(Canvas canvas) { } } canvas.restore(); -// -// if (transitionViewHolder.avatarImage != null) { -// transitionViewHolder.avatarImage.setVisible(false, true); -// } -// if (transitionViewHolder.storyImage != null) { -// transitionViewHolder.storyImage.setVisible(false, true); -// } } if (runOpenAnimationAfterLayout) { @@ -1616,6 +1609,9 @@ public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets i AndroidUtilities.hideKeyboard(fragment.getFragmentView()); } + static int J = 0; + int j = J++; + private void showKeyboard() { PeerStoriesView currentPeerView = storiesViewPager.getCurrentPeerView(); if (currentPeerView != null) { @@ -2197,6 +2193,9 @@ public void instantClose() { } AndroidUtilities.hideKeyboard(windowView); isClosed = true; + fullyVisible = false; + progressToOpen = 0; + progressToDismiss = 0; updatePlayingMode(); fromX = fromY = 0; if (transitionViewHolder.avatarImage != null) { @@ -2208,7 +2207,6 @@ public void instantClose() { transitionViewHolder.storyImage = null; transitionViewHolder.avatarImage = null; containerView.disableHwAcceleration(); - checkNavBarColor(); locker.unlock(); if (currentPlayerScope != null) { currentPlayerScope.invalidate(); @@ -2222,6 +2220,7 @@ public void instantClose() { windowView = null; isShowing = false; foundViewToClose = false; + checkNavBarColor(); if (onCloseListener != null) { onCloseListener.run(); onCloseListener = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java index 64520608bd..b0f56f9ac4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/UploadingDotsSpannable.java @@ -11,7 +11,7 @@ import org.telegram.ui.Components.CubicBezierInterpolator; public class UploadingDotsSpannable extends ReplacementSpan { - private String text = "…"; + private final String text = "…"; private View parent; int swapPosition1 = 1; @@ -28,12 +28,14 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon return (int) paint.measureText(this.text); } + public boolean fixTop; + @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { TextPaint textPaint = (TextPaint) paint; float characterWidth = paint.measureText(this.text) / 3; - float baseline = -textPaint.getFontMetrics().top; + float baseline = fixTop ? -textPaint.getFontMetrics().ascent : -textPaint.getFontMetrics().top; float textThickness = (float) ((textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top) * (isMediumTypeface ? 0.05f : 0.0365f)); baseline -= textThickness; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java index b45faddfd9..4e5b855096 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java @@ -7,7 +7,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -21,7 +20,6 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; -import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.R; @@ -39,10 +37,12 @@ public class ButtonWithCounterView extends FrameLayout { private final Paint paint; public final AnimatedTextView.AnimatedTextDrawable text; + public final AnimatedTextView.AnimatedTextDrawable subText; private final AnimatedTextView.AnimatedTextDrawable countText; private float countAlpha; private final AnimatedFloat countAlphaAnimated = new AnimatedFloat(350, CubicBezierInterpolator.EASE_OUT_QUINT); private final View rippleView; + private final boolean filled; public ButtonWithCounterView(Context context, Theme.ResourcesProvider resourcesProvider) { this(context, true, resourcesProvider); @@ -51,6 +51,7 @@ public ButtonWithCounterView(Context context, Theme.ResourcesProvider resourcesP public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesProvider resourcesProvider) { super(context); + this.filled = filled; this.resourcesProvider = resourcesProvider; ScaleStateListAnimator.apply(this, .02f, 1.2f); @@ -76,6 +77,13 @@ public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesPro text.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); text.setGravity(Gravity.CENTER_HORIZONTAL); + subText = new AnimatedTextView.AnimatedTextDrawable(true, true, false); + subText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + subText.setCallback(this); + subText.setTextSize(dp(12)); + subText.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + subText.setGravity(Gravity.CENTER_HORIZONTAL); + countText = new AnimatedTextView.AnimatedTextDrawable(false, false, true); countText.setAnimationProperties(.3f, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); countText.setCallback(this); @@ -88,6 +96,13 @@ public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesPro setWillNotDraw(false); } + public void updateColors() { + rippleView.setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), 8, 8)); + text.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + subText.setTextColor(Theme.getColor(filled ? Theme.key_featuredStickers_buttonText : Theme.key_featuredStickers_addButton, resourcesProvider)); + countText.setTextColor(Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider)); + } + public void setCounterColor(int color) { countText.setTextColor(color); counterDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); @@ -130,12 +145,74 @@ public boolean isTimerActive() { } 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(); + } + + private float subTextT = 0f; + private ValueAnimator subTextVisibleAnimator; + private boolean subTextVisible; + + public boolean isSubTextVisible() { + return subTextVisible; + } + + private void cleanSubTextVisibleAnimator(){ + if (subTextVisibleAnimator != null) { + subTextVisibleAnimator.cancel(); + subTextVisibleAnimator = null; + } + } + + public void setSubText(CharSequence newText, boolean animated) { + boolean isNewTextVisible = newText != null; + if (animated) { + subText.cancelAnimation(); + } + setContentDescription(newText); invalidate(); + if (subTextVisible && !isNewTextVisible) { + cleanSubTextVisibleAnimator(); + subTextVisibleAnimator = ValueAnimator.ofFloat(subTextT, 0f); + subTextVisibleAnimator.addUpdateListener(anm -> { + subTextT = (float) anm.getAnimatedValue(); + invalidate(); + }); + subTextVisibleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + subTextVisible = false; + subText.setText(null, false); + } + }); + subTextVisibleAnimator.setDuration(200); + subTextVisibleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + subTextVisibleAnimator.start(); + } else { + subText.setText(newText, animated); + } + + if (!subTextVisible && isNewTextVisible) { + subTextVisible = true; + cleanSubTextVisibleAnimator(); + subTextVisibleAnimator = ValueAnimator.ofFloat(subTextT, 1f); + subTextVisibleAnimator.addUpdateListener(anm -> { + subTextT = (float) anm.getAnimatedValue(); + invalidate(); + }); + subTextVisibleAnimator.setDuration(200); + subTextVisibleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + subTextVisibleAnimator.start(); + } } private float loadingT = 0; @@ -257,7 +334,7 @@ public void setEnabled(boolean enabled) { @Override protected boolean verifyDrawable(@NonNull Drawable who) { - return text == who || countText == who || super.verifyDrawable(who); + return text == who || subText == who || countText == who || super.verifyDrawable(who); } @Override @@ -268,6 +345,11 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private CircularProgressDrawable loadingDrawable; 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) { @@ -296,17 +378,37 @@ protected void onDraw(Canvas canvas) { 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)), (int) ((getMeasuredWidth() - width + getWidth()) / 2f + textWidth), (int) ((getMeasuredHeight() + text.getHeight()) / 2f - dp(1)) ); + AndroidUtilities.rectTmp2.offset(0, (int) (-dp(7) * subTextT)); text.setAlpha((int) (globalAlpha * (1f - loadingT) * AndroidUtilities.lerp(.5f, 1f, enabledT))); text.setBounds(AndroidUtilities.rectTmp2); text.draw(canvas); + if (subTextVisible) { + float subTextWidth = subText.getCurrentWidth(); + width = subTextWidth; + AndroidUtilities.rectTmp2.set( + (int) ((getMeasuredWidth() - width - getWidth()) / 2f), + (int) ((getMeasuredHeight() - subText.getHeight()) / 2f - dp(1)), + (int) ((getMeasuredWidth() - width + getWidth()) / 2f + subTextWidth), + (int) ((getMeasuredHeight() + subText.getHeight()) / 2f - dp(1)) + ); + AndroidUtilities.rectTmp2.offset(0, dp(11)); + canvas.save(); + float scale = AndroidUtilities.lerp(.1f, 1f, subTextT); + canvas.scale(scale, scale, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.bottom); + subText.setAlpha((int) (subTextAlpha * (1f - loadingT) * subTextT * AndroidUtilities.lerp(.5f, 1f, enabledT))); + subText.setBounds(AndroidUtilities.rectTmp2); + subText.draw(canvas); + canvas.restore(); + } + AndroidUtilities.rectTmp2.set( (int) ((getMeasuredWidth() - width) / 2f + textWidth + dp(countFilled ? 5 : 2)), (int) ((getMeasuredHeight() - dp(18)) / 2f), @@ -325,7 +427,8 @@ protected void onDraw(Canvas canvas) { 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 df224c8c0b..3ccbc71344 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -17,10 +17,12 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; +import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -43,6 +45,8 @@ import androidx.annotation.Nullable; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import com.google.zxing.common.detector.MathUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; @@ -73,6 +77,7 @@ import org.telegram.ui.Components.MentionsContainerView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.Text; import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.DarkThemeResourceProvider; @@ -81,7 +86,7 @@ public class CaptionContainerView extends FrameLayout { protected Theme.ResourcesProvider resourcesProvider; private final FrameLayout containerView; - private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + protected final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public final EditTextEmoji editText; private Drawable applyButtonCheck; private CombinedDrawable applyButtonDrawable; @@ -94,8 +99,8 @@ public class CaptionContainerView extends FrameLayout { private final LinearGradient fadeGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(10), new int[] { 0xffff0000, 0x00000000 }, new float[] { 0.05f, 1 }, Shader.TileMode.CLAMP); private final Matrix matrix = new Matrix(); - private final TextPaint hintTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private Bitmap hintTextBitmap; + private final TextPaint hintTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final Paint hintTextBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final FrameLayout rootView; @@ -107,8 +112,8 @@ public class CaptionContainerView extends FrameLayout { private int shiftDp = -4; private final BlurringShader.BlurManager blurManager; - private final BlurringShader.StoryBlurDrawer captionBlur; - private final BlurringShader.StoryBlurDrawer backgroundBlur; + protected final BlurringShader.StoryBlurDrawer captionBlur, replyTextBlur; + protected final BlurringShader.StoryBlurDrawer backgroundBlur, replyBackgroundBlur; private BlurringShader.StoryBlurDrawer mentionBackgroundBlur; protected int currentAccount = UserConfig.selectedAccount; @@ -136,12 +141,22 @@ public CaptionContainerView(Context context, FrameLayout rootView, SizeNotifierF this.blurManager = blurManager; backgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_BACKGROUND, !customBlur()); + replyBackgroundBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_REPLY_BACKGROUND); + replyTextBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_REPLY_TEXT_XFER); backgroundPaint.setColor(0x80000000); keyboardNotifier = new KeyboardNotifier(rootView, this::updateKeyboard); editText = new EditTextEmoji(context, sizeNotifierFrameLayout, null, getEditTextStyle(), true, new DarkThemeResourceProvider()) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (CaptionContainerView.this instanceof CaptionStory && ((CaptionStory) CaptionContainerView.this).isRecording()) { + return false; + } + return super.dispatchTouchEvent(ev); + } + @Override protected void onEmojiKeyboardUpdate() { keyboardNotifier.fire(); @@ -221,7 +236,7 @@ public void onAnimationEnd(Animator animation) { editText.getEditText().drawHint = this::drawHint; editText.getEditText().setSupportRtlHint(true); captionBlur = new BlurringShader.StoryBlurDrawer(blurManager, editText.getEditText(), customBlur() ? BlurringShader.StoryBlurDrawer.BLUR_TYPE_CAPTION : BlurringShader.StoryBlurDrawer.BLUR_TYPE_CAPTION_XFER); - editText.getEditText().setHintColor(0x80ffffff); + editText.getEditText().setHintColor(0xffffffff); editText.getEditText().setHintText(LocaleController.getString(R.string.AddCaption), false); hintTextBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); editText.getEditText().setTranslationX(AndroidUtilities.dp(-40 + 18)); @@ -264,7 +279,7 @@ public void afterTextChanged(Editable s) { 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(); } @@ -288,7 +303,7 @@ public void afterTextChanged(Editable s) { } }); editText.getEditText().setLinkTextColor(Color.WHITE); - addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 12, 12, 12, 12)); + addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 12, 12, 12 + additionalRightMargin(), 12)); applyButton = new BounceableImageView(context); ScaleStateListAnimator.apply(applyButton, 0.05f, 1.25f); @@ -323,6 +338,10 @@ public void afterTextChanged(Editable s) { fadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + public int additionalRightMargin() { + return 0; + } + private final Runnable textChangeRunnable = () -> onTextChange(); protected void onTextChange() {} @@ -350,16 +369,19 @@ public void closeKeyboard() { 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) { + if (this instanceof CaptionStory && ((CaptionStory) this).isRecording()) { + return super.dispatchTouchEvent(ev); + } for (int i = 0; i < getChildCount(); ++i) { View child = getChildAt(i); if (child == null || !child.isClickable() || child.getVisibility() != View.VISIBLE || child.getAlpha() < .5f || editText == child) { @@ -372,7 +394,6 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } editText.getEditText().setForceCursorEnd(true); editText.getEditText().requestFocus(); -// editText.getEditText().setSelection(editText.getEditText().length(), editText.getEditText().length()); editText.openKeyboard(); editText.getEditText().setScrollY(0); bounce.setPressed(true); @@ -746,17 +767,111 @@ public boolean onBackPressed() { protected void onEditHeightChange(int height) {} + private boolean hasReply; + private Text replyTitle, replyText; + public void setReply(CharSequence title, CharSequence text) { + if (title == null && text == null) { + hasReply = false; + invalidate(); + } else { + hasReply = true; + + replyTitle = new Text(title == null ? "" : title, 14, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + replyText = new Text(text == null ? "" : text, 14); + } + } + + private Path replyClipPath; + private Paint replyLinePaint; + private Path replyLinePath; + private float[] replyLinePathRadii; + private void drawReply(Canvas canvas) { + if (!hasReply || replyBackgroundBlur == null || replyTextBlur == null || customBlur()) { + return; + } + + float alpha = 1f; + float top; + if (collapsed) { + if (keyboardShown) { + top = bounds.bottom - Math.max(dp(46), editText.getHeight()); + } else { + top = bounds.bottom - Math.min(dp(82), editText.getHeight()); + } + alpha = 1f - collapsedT.get(); + top -= dp(42 + 8); + } else { + top = bounds.top; + } + + Paint bgBlurPaint = replyBackgroundBlur.getPaint(alpha); + Paint textBlurPaint = replyTextBlur.getPaint(alpha); + + AndroidUtilities.rectTmp.set(bounds.left + dp(10), top + dp(10), bounds.right - dp(10), top + dp(10 + 42)); + if (bgBlurPaint != null) { + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5), dp(5), bgBlurPaint); + } + + if (textBlurPaint != null) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xFF, Canvas.ALL_SAVE_FLAG); + } + if (replyClipPath == null) { + replyClipPath = new Path(); + } else { + replyClipPath.rewind(); + } + final float r = lerp(AndroidUtilities.dp(21), 0, keyboardT); + replyClipPath.addRoundRect(bounds, r, r, Path.Direction.CW); + canvas.clipPath(replyClipPath); + if (replyTitle != null) { + replyTitle.ellipsize((int) (bounds.width() - dp(40))).draw(canvas, bounds.left + dp(20), top + dp(22), 0xFFFFFFFF, 1f); + } + if (replyLinePath == null) { + replyLinePath = new Path(); + replyLinePathRadii = new float[8]; + replyLinePathRadii[0] = replyLinePathRadii[1] = dp(5); + replyLinePathRadii[2] = replyLinePathRadii[3] = 0; + replyLinePathRadii[4] = replyLinePathRadii[5] = 0; + replyLinePathRadii[6] = replyLinePathRadii[7] = dp(5); + } else { + replyLinePath.rewind(); + } + AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top, AndroidUtilities.rectTmp.left + dp(3), AndroidUtilities.rectTmp.bottom); + replyLinePath.addRoundRect(AndroidUtilities.rectTmp, replyLinePathRadii, Path.Direction.CW); + if (replyLinePaint == null) { + replyLinePaint = new Paint(); + replyLinePaint.setColor(0xFFFFFFFF); + } + replyLinePaint.setAlpha((int) (0xFF * alpha)); + canvas.drawPath(replyLinePath, replyLinePaint); + if (textBlurPaint != null) { + canvas.save(); + canvas.drawRect(bounds, textBlurPaint); + canvas.restore(); + canvas.restore(); + } + + if (replyText != null) { + replyText.ellipsize((int) (bounds.width() - dp(40))).draw(canvas, bounds.left + dp(20), top + dp(40), 0xFFFFFFFF, 1f); + } + } + @Override protected void dispatchDraw(Canvas canvas) { if (ignoreDraw) { return; } int height = editText.getHeight(); - if (keyboardShown) { + if (collapsed) { + height = dp(40); + } else if (keyboardShown) { height = Math.max(dp(46), height); } else { height = Math.min(dp(82), height); } + if (!collapsed && hasReply) { + height += dp(42 + 8); + } final int heightAnimated = (int) this.heightAnimated.set(height); if (heightAnimated != lastHeight) { onEditHeightChange(heightAnimated); @@ -767,10 +882,9 @@ protected void dispatchDraw(Canvas canvas) { } updateMentionsLayoutPosition(); final float heightTranslation = dpf2(-1) * keyboardT + height - heightAnimated; - if (Math.abs(lastHeightTranslation - heightTranslation) >= 1) { - editText.getEditText().setTranslationY(heightTranslation); + if (Math.abs(lastHeightTranslation - heightTranslation) >= 1 && !collapsed) { + editText.getEditText().setTranslationY(lastHeightTranslation = heightTranslation); } - lastHeightTranslation = heightTranslation; final float pad = lerp(AndroidUtilities.dp(12), 0, keyboardT); bounds.set( @@ -806,11 +920,109 @@ protected void dispatchDraw(Canvas canvas) { } } + final float wasCollapseT = collapsedT.get(); + final float collapseT = collapsedT.set(collapsed); + if (Math.abs(wasCollapseT - collapseT) > 0.001f || (wasCollapseT <= 0) != (collapseT <= 0)) { + invalidateDrawOver2(); + } + if (collapseT > 0) { + canvas.saveLayerAlpha(bounds, 0xFF, Canvas.ALL_SAVE_FLAG); + } + + drawReply(canvas); + super.dispatchDraw(canvas); + if (collapseT > 0) { + final float cx; + if (collapsedFromX == Integer.MAX_VALUE) { + cx = bounds.right - dp(20); + } else if (collapsedFromX == Integer.MIN_VALUE) { + cx = bounds.left + dp(20); + } else { + cx = collapsedFromX; + } + final float cy = bounds.bottom - dp(20); + final float mxr = Math.max( + Math.max(MathUtils.distance(bounds.left, bounds.top, cx, cy), MathUtils.distance(bounds.left, bounds.bottom, cx, cy)), + Math.max(MathUtils.distance(bounds.right, bounds.top, cx, cy), MathUtils.distance(bounds.right, bounds.bottom, cx, cy)) + ); + final float R = mxr * collapseT; + if (collapsePaint == null) { + collapsePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + collapsePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + collapseGradient = new RadialGradient(0, 0, 32, new int[] { -1, -1, 0 }, new float[] { 0, .6f, 1 }, Shader.TileMode.CLAMP); + collapsePaint.setShader(collapseGradient); + collapseGradientMatrix = new Matrix(); + + collapseOutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + collapseOutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + collapseOutGradient = new RadialGradient(0, 0, 32, new int[] { 0, 0, -1 }, new float[] { 0, .5f, 1 }, Shader.TileMode.CLAMP); + collapseOutPaint.setShader(collapseOutGradient); + } + collapseGradientMatrix.reset(); + collapseGradientMatrix.postTranslate(cx, cy); + collapseGradientMatrix.preScale(Math.max(1, R) / 16f, Math.max(1, R) / 16f); + collapseGradient.setLocalMatrix(collapseGradientMatrix); + canvas.save(); + canvas.drawRoundRect(bounds, r, r, collapsePaint); + canvas.restore(); + canvas.restore(); + + canvas.saveLayerAlpha(bounds, 0xFF, Canvas.ALL_SAVE_FLAG); + drawOver(canvas, bounds); + collapseGradientMatrix.reset(); + collapseGradientMatrix.postTranslate(cx, cy); + collapseGradientMatrix.preScale(Math.max(1, R) / 16f, Math.max(1, R) / 16f); + collapseOutGradient.setLocalMatrix(collapseGradientMatrix); + canvas.save(); + canvas.drawRoundRect(bounds, r, r, collapseOutPaint); + canvas.restore(); + canvas.restore(); + + if (!drawOver2FromParent()) { + drawOver2(canvas, bounds, collapseT); + } + } + canvas.restore(); } + public void drawOver(Canvas canvas, RectF bounds) { + + } + + public void drawOver2(Canvas canvas, RectF bounds, float alpha) { + + } + + public float getOver2Alpha() { + return collapsedT.get(); + } + + public boolean drawOver2FromParent() { + return false; + } + + public void invalidateDrawOver2() { + + } + + public boolean collapsed; + public int collapsedFromX; + public final AnimatedFloat collapsedT = new AnimatedFloat(this, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + public void setCollapsed(boolean collapsed, int cx) { + this.collapsed = collapsed; + this.collapsedFromX = cx; + invalidate(); + } + + private Paint collapsePaint; + private RadialGradient collapseGradient; + private Paint collapseOutPaint; + private RadialGradient collapseOutGradient; + private Matrix collapseGradientMatrix; + public RectF getBounds() { return bounds; } @@ -834,6 +1046,7 @@ private void drawHint(Canvas canvas, Runnable draw) { return; } Paint blurPaint = captionBlur.getPaint(1f); + editText.getEditText().setHintColor(blurPaint != null ? 0xffffffff : 0x80ffffff); if (blurPaint == null) { draw.run(); } else { @@ -1023,7 +1236,7 @@ protected void onDetachedFromWindow() { 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 @@ -1031,11 +1244,26 @@ public void invalidateSelf() { 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); @@ -1045,33 +1273,74 @@ public PeriodDrawable() { 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 setTextSize(float dp) { + activeTextDrawable.setTextSize(dpf2(dp)); + textDrawable.setTextSize(dpf2(dp)); } - public void updateColors(int strokeColor, int fillColor) { + 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 draw(@NonNull Canvas canvas) { - final float cx = getBounds().centerY(); - final float cy = getBounds().centerY(); + public void setBounds(@NonNull Rect bounds) { + super.setBounds(bounds); + this.cx = getBounds().centerX(); + this.cy = getBounds().centerY(); + } - final float r = dpf2(21) / 2f; + @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) { + 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; @@ -1083,7 +1352,7 @@ public void draw(@NonNull Canvas canvas) { } canvas.save(); - canvas.translate(0, -1); + canvas.translate(textOffsetX + 0, textOffsetY); AndroidUtilities.rectTmp2.set( (int) (cx - dp(20)), (int) (cy - dp(20)), @@ -1091,12 +1360,22 @@ public void draw(@NonNull Canvas canvas) { (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 d9642cae32..4caa9ac4cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionStory.java @@ -1,46 +1,95 @@ package org.telegram.ui.Stories.recorder; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; +import static org.telegram.messenger.AndroidUtilities.lerp; import static org.telegram.ui.ActionBar.Theme.RIPPLE_MASK_CIRCLE_20DP; import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextPaint; import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.BlobDrawable; import org.telegram.ui.Components.BlurringShader; +import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.Text; +import org.telegram.ui.Components.WaveDrawable; public class CaptionStory extends CaptionContainerView { + public ButtonBounce roundButtonBounce; + public ImageView roundButton; + public ImageView periodButton; public PeriodDrawable periodDrawable; private ItemOptions periodPopup; 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; + public CaptionStory(Context context, FrameLayout rootView, SizeNotifierFrameLayout sizeNotifierFrameLayout, FrameLayout containerView, Theme.ResourcesProvider resourcesProvider, BlurringShader.BlurManager blurManager) { super(context, rootView, sizeNotifierFrameLayout, containerView, resourcesProvider, blurManager); + roundButton = new ImageView(context); + roundButtonBounce = new ButtonBounce(roundButton); + roundButton.setImageResource(R.drawable.input_video_story); + roundButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, dp(18))); + roundButton.setScaleType(ImageView.ScaleType.CENTER); + addView(roundButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 10)); + roundButton.setOnClickListener(e -> { + showRemoveRoundAlert(); + }); + periodButton = new ImageView(context); periodButton.setImageDrawable(periodDrawable = new PeriodDrawable()); - periodButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(18))); + periodButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, RIPPLE_MASK_CIRCLE_20DP, dp(18))); periodButton.setScaleType(ImageView.ScaleType.CENTER); + setPeriod(86400, false); + addView(periodButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11 + 44 - 4, 10)); periodButton.setOnClickListener(e -> { if (periodPopup != null && periodPopup.isShown()) { return; @@ -82,8 +131,342 @@ public CaptionStory(Context context, FrameLayout rootView, SizeNotifierFrameLayo } periodPopup.setDimAlpha(0).show(); }); - setPeriod(86400, false); - addView(periodButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 10)); + } + + private void checkFlipButton() { + if (flipButton != null) return; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + flipButton = (AnimatedVectorDrawable) ContextCompat.getDrawable(getContext(), R.drawable.avd_flip); + } else { + flipButton = getContext().getResources().getDrawable(R.drawable.vd_flip).mutate(); + } + } + + private boolean hasRoundVideo; + public void setHasRoundVideo(boolean hasRoundVideo) { + roundButton.setImageResource(hasRoundVideo ? R.drawable.input_video_story_remove : R.drawable.input_video_story); + this.hasRoundVideo = hasRoundVideo; + } + + private final RecordDot recordPaint = new RecordDot(this); + private final AnimatedTextView.AnimatedTextDrawable timerTextDrawable = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + { + timerTextDrawable.setAnimationProperties(.16f, 0, 50, CubicBezierInterpolator.DEFAULT); + timerTextDrawable.setTextSize(AndroidUtilities.dp(15)); + timerTextDrawable.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + timerTextDrawable.setText("0:00.0"); + timerTextDrawable.setTextColor(Color.WHITE); + } + + private float slideProgress; + private float lockProgress; + private long startTime; + + @Override + public void drawOver(Canvas canvas, RectF bounds) { + if (currentRecorder != null) { + final float cancel = cancelT.set(cancelling); + final float lock = lockT.set(locked); + + if (startTime <= 0) startTime = System.currentTimeMillis(); + final float wobble = (1f + (float) Math.sin((System.currentTimeMillis() - startTime) / 900f * Math.PI)) / 2f; + + final float rcx = bounds.left + dp(21), rcy = bounds.bottom - dp(20); + recordPaint.setBounds( + (int) (rcx - dp(12)), + (int) (rcy - dp(12)), + (int) (rcx + dp(12)), + (int) (rcy + dp(12)) + ); + recordPaint.draw(canvas); + + timerTextDrawable.setBounds((int) (bounds.left + dp(33.3f) - dp(10) * cancel), (int) (bounds.bottom - dp(20) - dp(9)), (int) (bounds.left + dp(33.3f + 100)), (int) (bounds.bottom - dp(20) + dp(9))); + timerTextDrawable.setText(currentRecorder.sinceRecordingText()); + timerTextDrawable.setAlpha((int) (0xFF * (1f - cancel))); + timerTextDrawable.draw(canvas); + + final float slideToCancelAlpha = (1f - slideProgress) * (1f - lock); + final float cancelAlpha = lock; + + final Paint blurPaint = captionBlur.getPaint(1f); + if (blurPaint != null) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 0xff, Canvas.ALL_SAVE_FLAG); + } + + if (slideToCancelAlpha > 0) { + if (slideToCancelText == null) { + slideToCancelText = new Text(LocaleController.getString(R.string.SlideToCancel2), 15); + } + if (slideToCancelArrowPath == null) { + slideToCancelArrowPath = new Path(); + slideToCancelArrowPath.moveTo(dp(3.83f), 0); + slideToCancelArrowPath.lineTo(0, dp(5)); + slideToCancelArrowPath.lineTo(dp(3.83f), dp(10)); + + slideToCancelArrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + slideToCancelArrowPaint.setStyle(Paint.Style.STROKE); + slideToCancelArrowPaint.setStrokeCap(Paint.Cap.ROUND); + slideToCancelArrowPaint.setStrokeJoin(Paint.Join.ROUND); + } + + slideToCancelArrowPaint.setStrokeWidth(dp(1.33f)); + + slideToCancelText.ellipsize((int) (bounds.width() - dp(5 + 21 + 16 + 10 + 64) - timerTextDrawable.getCurrentWidth())); + final float width = dp(5 + 6.33f) + slideToCancelText.getWidth(); + final float x = bounds.centerX() - width / 2f - (bounds.width() / 6f) * lerp(slideProgress, 1f, lock) - wobble * dp(6) * (1f - slideProgress); + + int color = blurPaint != null ? 0xffffffff : 0x80ffffff; + color = Theme.multAlpha(color, slideToCancelAlpha); + + canvas.save(); + canvas.translate(x, bounds.centerY() - dp(5)); + slideToCancelArrowPaint.setColor(color); + canvas.drawPath(slideToCancelArrowPath, slideToCancelArrowPaint); + canvas.restore(); + slideToCancelText.draw(canvas, x + dp(5 + 6.33f), bounds.centerY(), color, 1f); + } + + if (cancelAlpha > 0) { + if (cancelText == null) { + cancelText = new Text(LocaleController.getString(R.string.CancelRound), 15, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + } + + cancelText.ellipsize((int) (bounds.width() - dp(5 + 21 + 16 + 10 + 64) - timerTextDrawable.getCurrentWidth())); + final float x = bounds.centerX() - cancelText.getWidth() / 2f + (bounds.width() / 4f) * (1f - cancelAlpha); + + int color = blurPaint != null ? 0xffffffff : 0x80ffffff; + color = Theme.multAlpha(color, cancelAlpha); + cancelText.draw(canvas, x, bounds.centerY(), color, 1f); + cancelBounds.set(x - dp(12), bounds.top, x + cancelText.getWidth() + dp(12), bounds.bottom); + } + + if (blurPaint != null) { + canvas.drawRect(bounds, blurPaint); + canvas.restore(); + } + + invalidate(); + } + } + + private final Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final BlobDrawable tinyWaveDrawable = new BlobDrawable(11, LiteMode.FLAGS_CHAT); + private final BlobDrawable bigWaveDrawable = new BlobDrawable(12, LiteMode.FLAGS_CHAT); + private final Drawable roundDrawable; + { + whitePaint.setColor(0xFFFFFFFF); + roundPaint.setColor(0xFF1A9CFF); + + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(55); + tinyWaveDrawable.generateBlob(); + + bigWaveDrawable.minRadius = dp(47); + bigWaveDrawable.maxRadius = dp(55); + bigWaveDrawable.generateBlob(); + + roundDrawable = getContext().getResources().getDrawable(R.drawable.input_video_pressed).mutate(); + } + + private float amplitude; + private final AnimatedFloat animatedAmplitude = new AnimatedFloat(this::invalidateDrawOver2, 0, 200, CubicBezierInterpolator.DEFAULT); + public void setAmplitude(double value) { + amplitude = (float) (Math.min(WaveDrawable.MAX_AMPLITUDE, value) / WaveDrawable.MAX_AMPLITUDE); + invalidate(); + } + + private final Path circlePath = new Path(); + private final Path boundsPath = new Path(); + + @Override + public void drawOver2(Canvas canvas, RectF bounds, float alpha) { + if (alpha <= 0) { + return; + } + + final float cancel = cancel2T.set(cancelling); + final float lock = lock2T.set(locked); + final float amplitude = animatedAmplitude.set(this.amplitude); + + final float radius = (dp(41) + dp(30) * amplitude * (1f - slideProgress)) * (1f - cancel) * alpha; + final float cx = lerp(bounds.right - dp(20) - (getWidth() * .35f) * slideProgress * (1f - lock), bounds.left + dp(20), cancel); + final float cy = bounds.bottom - dp(20); + + if (LiteMode.isEnabled(LiteMode.FLAGS_CHAT)) { + tinyWaveDrawable.minRadius = dp(47); + tinyWaveDrawable.maxRadius = dp(47) + dp(15) * BlobDrawable.FORM_SMALL_MAX; + + bigWaveDrawable.minRadius = dp(50); + bigWaveDrawable.maxRadius = dp(50) + dp(12) * BlobDrawable.FORM_BIG_MAX; + + bigWaveDrawable.update(amplitude, 1.01f); + tinyWaveDrawable.update(amplitude, 1.02f); + + bigWaveDrawable.paint.setColor(Theme.multAlpha(roundPaint.getColor(), WaveDrawable.CIRCLE_ALPHA_2 * alpha)); + canvas.save(); + final float s1 = radius / bigWaveDrawable.minRadius; + canvas.scale(s1, s1, cx, cy); + bigWaveDrawable.draw(cx, cy, canvas, bigWaveDrawable.paint); + canvas.restore(); + + tinyWaveDrawable.paint.setColor(Theme.multAlpha(roundPaint.getColor(), WaveDrawable.CIRCLE_ALPHA_1 * alpha)); + canvas.save(); + final float s2 = radius / tinyWaveDrawable.minRadius; + canvas.scale(s2, s2, cx, cy); + tinyWaveDrawable.draw(cx, cy, canvas, tinyWaveDrawable.paint); + canvas.restore(); + } + + final float R = Math.min(radius, dp(41 + 14)); + roundPaint.setAlpha((int) (0xFF * alpha)); + canvas.drawCircle(cx, cy, R, roundPaint); + + canvas.save(); + circlePath.rewind(); + circlePath.addCircle(cx, cy, R, Path.Direction.CW); + canvas.clipPath(circlePath); + roundDrawable.setBounds( + (int) (cx - roundDrawable.getIntrinsicWidth() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cy - roundDrawable.getIntrinsicHeight() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cx + roundDrawable.getIntrinsicWidth() / 2f * (1f - cancel) * (stopping ? alpha : 1f)), + (int) (cy + roundDrawable.getIntrinsicHeight() / 2f * (1f - cancel) * (stopping ? alpha : 1f)) + ); + roundDrawable.setAlpha((int) (0xFF * (1f - cancel) * (stopping ? alpha : 1f))); + roundDrawable.draw(canvas); + if (lock > 0) { + final float sz = dpf2(19.33f) / 2f * lock * alpha; + AndroidUtilities.rectTmp.set(cx - sz, cy - sz, cx + sz, cy + sz); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(5.33f), dp(5.33f), whitePaint); + } + canvas.restore(); + + drawLock(canvas, bounds, alpha); + + if (cancelling && (roundButton.getVisibility() == View.INVISIBLE || periodButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0)) { + canvas.saveLayerAlpha(bounds, (int) (0xFF * (1f - keyboardT)), Canvas.ALL_SAVE_FLAG); + + boundsPath.rewind(); + boundsPath.addRoundRect(bounds, dp(21), dp(21), Path.Direction.CW); + canvas.clipPath(boundsPath); + + if (roundButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0) { + canvas.save(); + canvas.translate(roundButton.getX() + dp(180) * (1f - cancel), roundButton.getY()); + roundButton.draw(canvas); + canvas.restore(); + } + + if (periodButton.getVisibility() == View.INVISIBLE || collapsedT.get() > 0) { + canvas.save(); + canvas.translate(periodButton.getX() + dp(180) * (1f - cancel), periodButton.getY()); + periodButton.draw(canvas); + canvas.restore(); + } + + canvas.restore(); + } + + checkFlipButton(); + flipButton.setAlpha((int) (0xFF * alpha * (1f - cancel))); + final int timelineHeight = getTimelineHeight(); + flipButton.setBounds((int) bounds.left + dp(4), (int) (bounds.top - timelineHeight - dp(36 + 12)), (int) (bounds.left + dp(4 + 36)), (int) (bounds.top - timelineHeight - dp(12))); + flipButton.draw(canvas); + } + + public int getTimelineHeight() { + return 0; + } + + private final Paint lockBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint lockHandlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { lockHandlePaint.setStyle(Paint.Style.STROKE); } + private final AnimatedFloat lockCancelledT = new AnimatedFloat(this::invalidateDrawOver2, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + private final RectF lockBounds = new RectF(); + private final RectF cancelBounds = new RectF(); + private final RectF lockRect = new RectF(); + private final Path lockHandle = new Path(); + + private void drawLock(Canvas canvas, RectF bounds, float alpha) { + final float cancel = cancel2T.get(); + final float lock = lock2T.get(); + + final float scale = lerp(lockCancelledT.set(slideProgress < .4f), 0f, lock) * (1f - cancel) * alpha; + + final float w = scale * dp(36), h = scale * lerp(dp(50), dp(36), lock); + final float cx = bounds.right - dp(20); + final float cy = lerp( + bounds.bottom - dp(20 + 60) - h / 2f - dp(120) * lockProgress * (1f - lock), + bounds.bottom - dp(20), + 1f - scale + ); + lockBounds.set(cx - w / 2f, cy - h / 2f, cx + w / 2f, cy + h / 2f); + + final float r = lerp(dp(18), dp(14), lock); + lockShadowPaint.setShadowLayer(dp(1), 0, dp(.66f), Theme.multAlpha(0x20000000, scale)); + lockShadowPaint.setColor(0); + canvas.drawRoundRect(lockBounds, r, r, lockShadowPaint); + + Paint backgroundBlurPaint = backgroundBlur.getPaint(scale); + if (backgroundBlurPaint == null) { + lockBackgroundPaint.setColor(0x40000000); + lockBackgroundPaint.setAlpha((int) (0x40 * scale)); + canvas.drawRoundRect(lockBounds, r, r, lockBackgroundPaint); + } else { + canvas.drawRoundRect(lockBounds, r, r, backgroundBlurPaint); + backgroundPaint.setAlpha((int) (0x33 * scale)); + canvas.drawRoundRect(lockBounds, r, r, backgroundPaint); + } + + canvas.save(); + canvas.scale(scale, scale, cx, cy); + + lockPaint.setColor(Theme.multAlpha(0xFFFFFFFF, scale)); + lockHandlePaint.setColor(Theme.multAlpha(0xFFFFFFFF, scale * (1f - lock))); + + final float lockRectW = lerp(dp(15.33f), dp(13), lock); + final float lockRectH = lerp(dp(12.66f), dp(13), lock); + final float lockRectY = cy + dp(4) * (1f - lock); + canvas.rotate(12 * lockProgress * (1f - lock), cx, lockRectY); + + lockRect.set(cx - lockRectW / 2f, lockRectY - lockRectH / 2f, cx + lockRectW / 2f, lockRectY + lockRectH / 2f); + canvas.drawRoundRect(lockRect, dp(3.66f), dp(3.66f), lockPaint); + + if (lock < 1) { + canvas.save(); + canvas.rotate(12 * lockProgress * (1f - lock), cx, lockRectY - lockRectH / 2f); + canvas.translate(0, lockRectH / 2f * lock); + canvas.scale(1f - lock, 1f - lock, cx, lockRectY - lockRectH / 2f); + + lockHandle.rewind(); + final float radius = dp(4.33f); + final float y = lockRectY - lockRectH / 2f - dp(3.66f); + lockHandle.moveTo(cx + radius, y + dp(3.66f)); + lockHandle.lineTo(cx + radius, y); + AndroidUtilities.rectTmp.set(cx - radius, y - radius, cx + radius, y + radius); + lockHandle.arcTo(AndroidUtilities.rectTmp, 0, -180, false); + lockHandle.lineTo(cx - radius, y + dp(3.66f) * lerp(lerp(.4f, 0, lockProgress), 1f, lock)); + + lockHandlePaint.setStrokeWidth(dp(2)); + canvas.drawPath(lockHandle, lockHandlePaint); + canvas.restore(); + } + + canvas.restore(); + } + + private Text slideToCancelText; + private Path slideToCancelArrowPath; + private Paint slideToCancelArrowPaint; + + private Text cancelText; + + @Override + public int additionalRightMargin() { + return 36; } public void setPeriod(int period) { @@ -131,17 +514,20 @@ public void setOnPremiumHint(Utilities.Callback listener) { protected void beforeUpdateShownKeyboard(boolean show) { if (!show) { periodButton.setVisibility(periodVisible ? View.VISIBLE : View.GONE); + roundButton.setVisibility(View.VISIBLE); } } @Override protected void onUpdateShowKeyboard(float keyboardT) { periodButton.setAlpha(1f - keyboardT); + roundButton.setAlpha(1f - keyboardT); } @Override protected void afterUpdateShownKeyboard(boolean show) { periodButton.setVisibility(!show && periodVisible ? View.VISIBLE : View.GONE); + roundButton.setVisibility(!show ? View.VISIBLE : View.GONE); if (show) { periodButton.setVisibility(View.GONE); } @@ -156,4 +542,327 @@ protected int getCaptionPremiumLimit() { protected int getCaptionDefaultLimit() { return MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault; } + + private RoundVideoRecorder currentRecorder; + private float fromX, fromY; + private final AnimatedFloat cancelT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat cancel2T = new AnimatedFloat(this::invalidateDrawOver2, 0, 420, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat lockT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat lock2T = new AnimatedFloat(this::invalidateDrawOver2, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean cancelling, stopping, locked; + private boolean recordTouch; + private boolean recording; + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (recording && currentRecorder != null && currentRecorder.cameraView != null && flipButton != null) { + AndroidUtilities.rectTmp.set(flipButton.getBounds()); + AndroidUtilities.rectTmp.inset(-dp(12), -dp(12)); + for (int i = 0; i < ev.getPointerCount(); ++i) { + if (AndroidUtilities.rectTmp.contains(ev.getX(i), ev.getY(i))) { + if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { + currentRecorder.cameraView.switchCamera(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && flipButton instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) flipButton).start(); + } + } + if (!recordTouch) { + return true; + } + break; + } + } + } + AndroidUtilities.rectTmp.set(roundButton.getX(), roundButton.getY(), roundButton.getX() + roundButton.getMeasuredWidth(), roundButton.getY() + roundButton.getMeasuredHeight()); + if (recordTouch || !hasRoundVideo && !keyboardShown && AndroidUtilities.rectTmp.contains(ev.getX(), ev.getY())) { + return roundButtonTouchEvent(ev); + } + if (recording && locked && cancelBounds.contains(ev.getX(), ev.getY())) { + releaseRecord(false, true); + recordTouch = false; + return true; + } + if (recording && (lockBounds.contains(ev.getX(), ev.getY()) || getBounds().contains(ev.getX(), ev.getY()))) { + releaseRecord(false, false); + recordTouch = false; + return true; + } + return super.dispatchTouchEvent(ev); + } + + private final Runnable doneCancel = () -> { + setCollapsed(false, Integer.MIN_VALUE); + roundButton.setVisibility(VISIBLE); + periodButton.setVisibility(VISIBLE); + }; + + private boolean roundButtonTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (stopRecording()) { + return true; + } + recordTouch = true; + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + if (!canRecord()) { + return true; + } + AndroidUtilities.cancelRunOnUIThread(doneCancel); + fromX = ev.getX(); + fromY = ev.getY(); + amplitude = 0; + slideProgress = 0f; + cancelT.set(0, true); + cancel2T.set(0, true); + cancelling = false; + stopping = false; + locked = false; + recordPaint.reset(); + recording = true; + startTime = System.currentTimeMillis(); + setCollapsed(true, Integer.MAX_VALUE); + invalidateDrawOver2(); + + putRecorder(currentRecorder = new RoundVideoRecorder(getContext()) { + @Override + protected void receivedAmplitude(double amplitude) { + setAmplitude(amplitude); + } + + @Override + public void stop() { + super.stop(); + if (recording) { + releaseRecord(true, false); + } + } + }); + return true; + } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { + if (!cancelling) { + slideProgress = Utilities.clamp((fromX - ev.getX()) / (getWidth() * .35f), 1, 0); + lockProgress = Utilities.clamp((fromY - ev.getY()) / (getWidth() * .3f), 1, 0); + if (!locked && !cancelling && slideProgress >= 1) { + cancelling = true; + recording = false; + roundButton.setVisibility(INVISIBLE); + periodButton.setVisibility(INVISIBLE); + recordPaint.playDeleteAnimation(); + + if (currentRecorder != null) { + currentRecorder.cancel(); + } + + AndroidUtilities.runOnUIThread(doneCancel, 800); + } else if (!locked && !cancelling && lockProgress >= 1 && slideProgress < .4f) { + locked = true; + + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) {} + } + invalidate(); + invalidateDrawOver2(); + } + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + if (!cancelling && !locked) { + releaseRecord(false, false); + } + recordTouch = false; + } + return recordTouch; + } + + private void releaseRecord(boolean byRecorder, boolean cancel) { + AndroidUtilities.cancelRunOnUIThread(doneCancel); + + stopping = true; + recording = false; + setCollapsed(false, (int) (getBounds().right - dp(20) - (getWidth() * .35f) * slideProgress)); + + if (currentRecorder != null) { + if (!byRecorder) { + if (cancel) { + currentRecorder.cancel(); + } else { + currentRecorder.stop(); + } + } + currentRecorder = null; + } + invalidateDrawOver2(); + } + + public boolean isRecording() { + return recording; + } + + public boolean stopRecording() { + if (recording) { + recordTouch = false; + releaseRecord(false, false); + return true; + } + return false; + } + + public boolean canRecord() { + return false; + } + + public void putRecorder(RoundVideoRecorder recorder) { + // Override + } + + public void showRemoveRoundAlert() { + if (!hasRoundVideo) return; + AlertDialog d = new AlertDialog.Builder(getContext(), resourcesProvider) + .setTitle(LocaleController.getString(R.string.StoryRemoveRoundTitle)) + .setMessage(LocaleController.getString(R.string.StoryRemoveRoundMessage)) + .setPositiveButton(LocaleController.getString(R.string.Remove), (di, w) -> removeRound()) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .show(); + TextView button = (TextView) d.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold, resourcesProvider)); + } + } + + public void removeRound() { + // Override + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + recordPaint.attach(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + recordPaint.detach(); + } + + private class RecordDot extends Drawable { + + private final Paint redDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float alpha; + private float alpha2 = 1f; + private long lastUpdateTime; + private boolean isIncr; + boolean attachedToWindow; + boolean playing; + RLottieDrawable drawable; + private boolean enterAnimation; + + private final View parent; + + public void attach() { + attachedToWindow = true; + if (playing) { + drawable.start(); + } + drawable.setMasterParent(parent); + } + + public void detach() { + attachedToWindow = false; + drawable.stop(); + drawable.setMasterParent(null); + } + + public RecordDot(View parent) { + this.parent = parent; + int resId = R.raw.chat_audio_record_delete_3; + drawable = new RLottieDrawable(resId, "" + resId, AndroidUtilities.dp(28), AndroidUtilities.dp(28), false, null); + drawable.setCurrentParentView(parent); + drawable.setInvalidateOnProgressSet(true); + updateColors(); + } + + public void updateColors() { + int dotColor = 0xffDB4646; + redDotPaint.setColor(dotColor); + drawable.beginApplyLayerColors(); + drawable.setLayerColor("Cup Red.**", dotColor); + drawable.setLayerColor("Box.**", dotColor); + drawable.commitApplyLayerColors(); + } + + public void resetAlpha() { + alpha = 1.0f; + lastUpdateTime = System.currentTimeMillis(); + isIncr = false; + playing = false; + drawable.stop(); + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + if (playing) { + drawable.setAlpha((int) (255 * alpha * alpha2)); + } + redDotPaint.setAlpha((int) (255 * alpha * alpha2)); + + long dt = (System.currentTimeMillis() - lastUpdateTime); + if (enterAnimation) { + alpha = 1; + } else { + if (!isIncr && !playing) { + alpha -= dt / 600.0f; + if (alpha <= 0) { + alpha = 0; + isIncr = true; + } + } else { + alpha += dt / 600.0f; + if (alpha >= 1) { + alpha = 1; + isIncr = false; + } + } + } + lastUpdateTime = System.currentTimeMillis(); + drawable.setBounds(getBounds()); + if (playing) { + drawable.draw(canvas); + } + if (!playing || !drawable.hasBitmap()) { + canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), dp(5), redDotPaint); + } + invalidate(); + } + + @Override + public void setAlpha(int alpha) { + alpha2 = (float) alpha / 0xFF; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + public void playDeleteAnimation() { + playing = true; + drawable.setProgress(0); + if (attachedToWindow) { + drawable.start(); + } + } + + public void reset() { + playing = false; + drawable.stop(); + drawable.setProgress(0); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java index 15fb236dc0..1b689d2b78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java @@ -39,6 +39,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; +import org.telegram.messenger.VideoEncodingService; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedFloat; @@ -343,6 +344,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (finalSize > 0) { onDone.run(); + VideoEncodingService.stop(); stop(false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index abe8e175c4..092b4e722c 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 @@ private void loadInternal(final boolean failed, Utilities.Callback 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 @@ private void loadInternal(final boolean failed, Utilities.Callback 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 @@ private File prepareFile(File file) { } public void append(StoryEntry entry) { - if (entry == null) { + if (entry == null || entry.isRepostMessage) { return; } prepare(entry); @@ -330,7 +340,7 @@ public void deleteForEdit(long peerId, int storyId) { } 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 static class StoryDraft { private int period; - private final ArrayList parts = new ArrayList<>(); - public boolean isEdit; public int editStoryId; public long editStoryPeerId; @@ -496,6 +504,16 @@ public static class StoryDraft { public float audioLeft, audioRight = 1; public float audioVolume = 1; + public String roundPath; + public String roundThumb; + public long roundDuration; + public long roundOffset; + public float roundLeft; + public float roundRight; + public float roundVolume = 1; + + public float videoVolume = 1f; + public TLRPC.InputPeer peer; public StoryDraft(@NonNull StoryEntry entry) { @@ -531,8 +549,6 @@ public StoryDraft(@NonNull StoryEntry entry) { 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; @@ -545,6 +561,16 @@ public StoryDraft(@NonNull StoryEntry entry) { this.audioRight = entry.audioRight; this.audioVolume = entry.audioVolume; + this.roundPath = entry.round == null ? "" : entry.round.getAbsolutePath(); + this.roundThumb = entry.roundThumb; + this.roundDuration = entry.roundDuration; + this.roundOffset = entry.roundOffset; + this.roundLeft = entry.roundLeft; + this.roundRight = entry.roundRight; + this.roundVolume = entry.roundVolume; + + this.videoVolume = entry.videoVolume; + this.peer = entry.peer; } @@ -609,12 +635,6 @@ public StoryEntry toEntry() { } 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; @@ -632,6 +652,19 @@ public StoryEntry toEntry() { entry.audioLeft = audioLeft; entry.audioRight = audioRight; entry.audioVolume = audioVolume; + + if (roundPath != null) { + entry.round = new File(roundPath); + } + entry.roundThumb = roundThumb; + entry.roundDuration = roundDuration; + entry.roundOffset = roundOffset; + entry.roundLeft = roundLeft; + entry.roundRight = roundRight; + entry.roundVolume = roundVolume; + + entry.videoVolume = videoVolume; + entry.peer = peer; return entry; } @@ -699,10 +732,7 @@ public void toStream(AbstractSerializedData stream) { } 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); @@ -741,11 +771,26 @@ public void toStream(AbstractSerializedData stream) { stream.writeFloat(audioRight); stream.writeFloat(audioVolume); } + if (peer != null) { peer.serializeToStream(stream); } else { new TLRPC.TL_inputPeerSelf().serializeToStream(stream); } + + if (roundPath == null) { + stream.writeInt32(TLRPC.TL_null.constructor); + } else { + stream.writeInt32(TLRPC.TL_documentAttributeVideo.constructor); + stream.writeString(roundPath); + stream.writeInt64(roundDuration); + stream.writeInt64(roundOffset); + stream.writeFloat(roundLeft); + stream.writeFloat(roundRight); + stream.writeFloat(roundVolume); + } + + stream.writeFloat(videoVolume); } public int getObjectSize() { @@ -833,7 +878,7 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { 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) { @@ -870,12 +915,6 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { 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); @@ -923,6 +962,20 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { if (stream.remaining() > 0) { peer = TLRPC.InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); } + if (stream.remaining() > 0) { + magic = stream.readInt32(exception); + if (magic == TLRPC.TL_documentAttributeVideo.constructor) { + roundPath = stream.readString(exception); + roundDuration = stream.readInt64(exception); + roundOffset = stream.readInt64(exception); + roundLeft = stream.readFloat(exception); + roundRight = stream.readFloat(exception); + roundVolume = stream.readFloat(exception); + } + } + if (stream.remaining() > 0) { + videoVolume = stream.readFloat(exception); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java index 848269d9e9..4ced1ab848 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java @@ -72,8 +72,8 @@ public void destroy(boolean async, Runnable beforeDestroyRunnable) { private boolean doNotSpanRotation; private float[] tempPoint = new float[4]; - private Matrix toScreen = new Matrix(); - private Matrix toGL = new Matrix(); + private final Matrix toScreen = new Matrix(); + private final Matrix toGL = new Matrix(); private boolean firstMeasure = true; private boolean atTop, atBottom; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java index 7a73bb6add..04293febe7 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 int getItemCount() { } } - 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 3b7e392629..eae8dba769 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 HintView2 setMaxWidthPx(int widthPx) { 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 @@ private static float measureCorrectly(CharSequence text, TextPaint paint) { 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 static int cutInFancyHalf(CharSequence text, TextPaint paint) { 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 static int cutInFancyHalf(CharSequence text, TextPaint paint) { // 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 @@ private void makeLayout(CharSequence text, int width) { 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 @@ protected void dispatchDraw(Canvas canvas) { 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 910e2c8a92..0000000000 --- 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 6d64da61b8..f81f439e64 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.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.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.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.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; @@ -121,6 +126,7 @@ import org.telegram.ui.Components.Paint.Views.PaintWeightChooserView; import org.telegram.ui.Components.Paint.Views.PhotoView; import org.telegram.ui.Components.Paint.Views.ReactionWidgetEntityView; +import org.telegram.ui.Components.Paint.Views.RoundView; import org.telegram.ui.Components.Paint.Views.StickerView; import org.telegram.ui.Components.Paint.Views.TextPaintView; import org.telegram.ui.Components.Point; @@ -160,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; @@ -257,6 +264,7 @@ public void set(float val) { private AnimatorSet keyboardAnimator; public final KeyboardNotifier keyboardNotifier; + private StoryEntry initialEntry; private ArrayList initialEntities; private int w, h; @@ -270,11 +278,14 @@ public void set(float val) { 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, 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; @@ -383,7 +394,7 @@ public ColorFilter getAnimatedEmojiColorFilter() { 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); @@ -571,6 +582,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }; // addView(entitiesView); + this.initialEntry = entry; this.initialEntities = entities; if (w > 0 && h > 0) { setupEntities(); @@ -797,7 +809,7 @@ protected void onDraw(Canvas canvas) { 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); @@ -1252,7 +1264,7 @@ public void updateZoom(boolean zoomedOut) { } } - private boolean selectEntity(EntityView entityView) { + public boolean selectEntity(EntityView entityView) { return selectEntity(entityView, true); } @@ -1328,6 +1340,8 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { AndroidUtilities.hideKeyboard(((TextPaintView) currentEntityView).getFocusedView()); hideEmojiPopup(false); } + } else if (currentEntityView instanceof RoundView) { + onDeselectRound((RoundView) currentEntityView); } } changed = true; @@ -1341,6 +1355,9 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { removeEntity(oldEntity); } } + if (oldEntity != currentEntityView && currentEntityView instanceof RoundView) { + onSelectRound((RoundView) currentEntityView); + } if (currentEntityView != null) { currentEntityView.select(selectionContainerView); @@ -1762,15 +1779,15 @@ public boolean canClickWidget(Integer widgetId) { 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; } @@ -2095,6 +2112,8 @@ public void init() { private void setupEntities() { if (initialEntities != null) { ArrayList entities = initialEntities; + StoryEntry entry = initialEntry; + initialEntry = null; initialEntities = null; for (int a = 0, N = entities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = entities.get(a); @@ -2135,13 +2154,25 @@ private void setupEntities() { 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); @@ -2156,6 +2187,16 @@ private void setupEntities() { entityView.changeStyle(false); } view = entityView; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_ROUND) { + if (entry.round == null) { + continue; + } + RoundView roundView = createRound(entry.roundThumb, false); + onCreateRound(roundView); + if ((entity.subType & 2) != 0) { + roundView.mirror(false); + } + view = roundView; } else { continue; } @@ -2290,13 +2331,15 @@ public static boolean isVideoStickerDocument(TLRPC.Document document) { @Override public Bitmap getBitmap(ArrayList entities, Bitmap[] thumbBitmap) { - return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false); + return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true, false, false, null); } - public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean drawBlur) { + public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities, boolean 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) { @@ -2420,6 +2463,13 @@ public Bitmap getBitmap(ArrayList entities, int res 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; @@ -2453,6 +2503,62 @@ public Bitmap getBitmap(ArrayList entities, int res mediaEntity.mediaArea.dark = reactionView.isDark(); mediaEntity.mediaArea.flipped = reactionView.isMirrored(); mediaEntity.mediaArea.coordinates = new TL_stories.TL_mediaAreaCoordinates(); + } else if (entity instanceof RoundView) { + skipDrawToBitmap = true; + RoundView roundView = (RoundView) entity; + Size size = roundView.getBaseSize(); + mediaEntity.width = size.width; + mediaEntity.height = size.height; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_ROUND; + if (entry != null) { + mediaEntity.text = entry.round.getAbsolutePath(); + mediaEntity.roundOffset = entry.roundOffset; + mediaEntity.roundDuration = entry.roundDuration; + mediaEntity.roundLeft = (long) (entry.roundLeft * entry.roundDuration); + mediaEntity.roundRight = (long) (entry.roundRight * entry.roundDuration); + } + mediaEntity.subType = 4; + if (roundView.isMirrored()) { + mediaEntity.subType |= 2; + } + } else 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; } @@ -2475,7 +2581,17 @@ public Bitmap getBitmap(ArrayList entities, int res 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; @@ -2496,7 +2612,7 @@ public Bitmap getBitmap(ArrayList entities, int res 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; @@ -2505,7 +2621,7 @@ public Bitmap getBitmap(ArrayList entities, int res 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++) { @@ -2534,7 +2650,14 @@ public Bitmap getBitmap(ArrayList entities, int res } 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(); } @@ -3354,6 +3477,14 @@ public void onAddButtonPressed(View btn) { } 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); @@ -3362,25 +3493,31 @@ private void showMenuForEntity(final EntityView entityView) { 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 -> { - removeEntity(entityView); - - if (popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(true); - } - }); - parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); + 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 (entityView instanceof TextPaintView) { TextView editView = new TextView(getContext()); @@ -3433,13 +3570,15 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (entityView instanceof StickerView || entityView instanceof PhotoView || entityView instanceof ReactionWidgetEntityView) { + if (entityView instanceof StickerView || entityView instanceof RoundView || entityView instanceof PhotoView || entityView instanceof ReactionWidgetEntityView) { TextView flipView = createActionLayoutButton(4, LocaleController.getString("Flip", R.string.Flip)); flipView.setOnClickListener(v -> { if (entityView instanceof StickerView) { ((StickerView) entityView).mirror(true); - } else if (entityView instanceof ReactionWidgetEntityView){ + } else if (entityView instanceof ReactionWidgetEntityView) { ((ReactionWidgetEntityView) entityView).mirror(true); + } else if (entityView instanceof RoundView) { + ((RoundView) entityView).mirror(true); } else { ((PhotoView) entityView).mirror(true); } @@ -3450,7 +3589,23 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 44)); } - if (!(entityView instanceof PhotoView) && !(entityView instanceof LocationView) && !(entityView instanceof ReactionWidgetEntityView)) { + if (entityView instanceof PhotoView && ((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); @@ -3554,7 +3709,7 @@ private Point startPositionRelativeToEntity(EntityView entityView) { 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(); @@ -3878,6 +4033,94 @@ public PhotoView createPhoto(String path, boolean select) { return view; } + public void onCreateRound(RoundView roundView) { + + } + + public void onTryDeleteRound() { + + } + + public void onDeleteRound() { + + } + + public void onSwitchSegmentedAnimation(PhotoView photoView) { + + } + + public void onDeselectRound(RoundView roundView) { + + } + + public void onSelectRound(RoundView roundView) { + + } + + public void deleteRound() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child instanceof RoundView) { + if (currentEntityView == child) { + selectEntity(null); + } + child.animate().scaleX(0).scaleY(0) + .setDuration(280).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT) + .withEndAction(() -> removeEntity((RoundView) child)).start(); + } + } + } + + private boolean creatingNewRound; + public RoundView createRound(String thumbPath, boolean select) { + forceChanges = true; + creatingNewRound = true; + deleteRound(); + int w = entitiesView.getMeasuredWidth(), h = entitiesView.getMeasuredHeight(); + if (w <= 0) w = this.w; + if (h <= 0) h = this.h; + float side = (float) Math.floor(w * 0.43f); + Size size = new Size(side, side); + float x = w - size.width / 2f - dp(16); + float y = dp(72) + size.height / 2f; + RoundView view = new RoundView(getContext(), new Point(x, y), 0, 1f, size, thumbPath); + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + post(() -> selectEntity(view)); + } + creatingNewRound = false; + return view; + } + + public 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); @@ -3976,11 +4219,18 @@ private void removeEntity(EntityView entityView) { if (entityView != null) { undoStore.unregisterUndo(entityView.getUUID()); } + if (entityView instanceof PhotoView) { + ((PhotoView) entityView).deleteSegmentedFile(); + } weightChooserView.setValueOverride(weightDefaultValueOverride); weightChooserView.setShowPreview(true); colorSwatch.brushWeight = weightDefaultValueOverride.get(); setCurrentSwatch(colorSwatch, true); + + if (!creatingNewRound && entityView instanceof RoundView) { + onDeleteRound(); + } } private void registerRemovalUndo(final EntityView entityView) { @@ -3997,6 +4247,14 @@ public boolean onEntitySelected(EntityView entityView) { 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(); @@ -4518,4 +4776,19 @@ protected void onDetachedFromWindow() { protected void onGalleryClick() { } + + public EntityView getSelectedEntity() { + return currentEntityView; + } + + public RoundView findRoundView() { + for (int i = 0; i < entitiesView.getChildCount(); ++i) { + View child = entitiesView.getChildAt(i); + if (child instanceof RoundView) { + return (RoundView) child; + } + } + return null; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewButtons.java index 2227f1f4dc..c24eb0d645 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 PreviewButtons(Context context) { 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 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto 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 void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { } 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/PreviewHighlightView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java index 99d4bdb02f..509d073e2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java @@ -3,7 +3,6 @@ import static org.telegram.messenger.AndroidUtilities.dp; import static org.telegram.messenger.AndroidUtilities.dpf2; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -73,7 +72,7 @@ protected void dispatchDraw(Canvas canvas) { } }; PeerStoriesView.PeerHeaderView headerView = new PeerStoriesView.PeerHeaderView(getContext(), null); - headerView.backupImageView.getAvatarDrawable().setInfo(me); + headerView.backupImageView.getAvatarDrawable().setInfo(currentAccount, me); headerView.backupImageView.setForUserOrChat(me, headerView.backupImageView.getAvatarDrawable()); CharSequence text = UserObject.getUserName(me); text = Emoji.replaceEmoji(text, headerView.titleView.getPaint().getFontMetricsInt(), false); @@ -144,7 +143,7 @@ public void updateCount() { public void updateCaption(CharSequence caption) { caption = AnimatedEmojiSpan.cloneSpans(new SpannableString(caption)); - storyCaptionView.captionTextview.setText(caption, false, false); + storyCaptionView.captionTextview.setText(caption, null, false, false); } private boolean shownTop = false, shownBottom = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java index 060bf8efcb..e90825ba8e 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,40 @@ 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; import org.telegram.ui.Components.VideoPlayer; @@ -60,6 +85,10 @@ public class PreviewView extends FrameLayout { private PhotoFilterView photoFilterView; public Runnable invalidateBlur; + private RoundView roundView; + private VideoPlayer roundPlayer; + private int roundPlayerWidth, roundPlayerHeight; + private VideoPlayer audioPlayer; // private VideoTimelinePlayView videoTimelineView; @@ -70,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) {} @@ -107,9 +135,10 @@ public void set(StoryEntry entry, Runnable whenReady, long seekTo) { 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); return; } if (entry.isVideo) { @@ -125,9 +154,38 @@ public void set(StoryEntry entry, Runnable whenReady, long seekTo) { 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); } public void setupAudio(StoryEntry entry, boolean animated) { @@ -171,7 +229,7 @@ public void onRenderedFirstFrame() { @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - + invalidateTextureViewHolder(); } @Override @@ -180,7 +238,7 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { } }); audioPlayer.preparePlayer(Uri.fromFile(new File(entry.audioPath)), "other"); - audioPlayer.setVolume(entry.audioVolume); + checkVolumes(); if (videoPlayer != null && getDuration() > 0) { long startPos = (long) (entry.left * getDuration()); @@ -235,10 +293,20 @@ public void setupAudio(MessageObject messageObject, boolean animated) { private void seekTo(long position) { if (videoPlayer != null) { videoPlayer.seekTo(position, false); + } else if (roundPlayer != null) { + roundPlayer.seekTo(position, false); } else if (audioPlayer != null) { audioPlayer.seekTo(position, false); } updateAudioPlayer(true); + updateRoundPlayer(true); + } + + public void seek(long position) { + seekTo(position); + if (timelineView != null) { + timelineView.setProgress(0); + } } public void setVideoTimelineView(TimelineView timelineView) { @@ -261,6 +329,15 @@ public void onProgressChange(long progress, boolean fast) { } } + @Override + public void onVideoVolumeChange(float volume) { + if (entry == null) { + return; + } + entry.videoVolume = volume; + checkVolumes(); + } + @Override public void onVideoLeftChange(float left) { if (entry == null) { @@ -324,14 +401,71 @@ public void onAudioVolumeChange(float volume) { } entry.audioVolume = volume; entry.editedMedia = true; - if (audioPlayer != null) { - audioPlayer.setVolume(volume); + checkVolumes(); + } + + @Override + public void onRoundLeftChange(float left) { + if (entry == null) { + return; + } + entry.roundLeft = left; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundRightChange(float right) { + if (entry == null) { + return; + } + entry.roundRight = right; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundOffsetChange(long offset) { + if (entry == null) { + return; } + entry.roundOffset = offset; + entry.editedMedia = true; + updateRoundPlayer(true); + } + + @Override + public void onRoundRemove() { + setupRound(null, null, true); + PreviewView.this.onRoundRemove(); + } + + @Override + public void onRoundVolumeChange(float volume) { + if (entry == null) { + return; + } + entry.roundVolume = volume; + entry.editedMedia = true; + checkVolumes(); + } + + @Override + public void onRoundSelectChange(boolean selected) { + PreviewView.this.onRoundSelectChange(selected); } }); } } + public void onRoundRemove() { + // Override + } + + public void onRoundSelectChange(boolean selected) { + // Override + } + private void setupImage(StoryEntry entry) { if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); @@ -465,14 +599,16 @@ private void setupGradient() { 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) { @@ -483,7 +619,7 @@ private void setupVideoPlayer(StoryEntry entry, Runnable whenReady, long seekTo) }).start(); } if (timelineView != null) { - timelineView.setVideo(null, 1); + timelineView.setVideo(false, null, 1, 0); } AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (whenReady != null) { @@ -539,14 +675,13 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre if (textureView != null) { textureView.setVideoSize(videoWidth, videoHeight); } -// if (whenReadyFinal[0] != null && entry != null && entry.width > 0 && entry.height > 0) { -// post(whenReadyFinal[0]); -// whenReadyFinal[0] = null; -// } } @Override public void onRenderedFirstFrame() { + if (textureViewHolder != null && textureViewHolder.active) { + textureViewHolder.activateTextureView(videoWidth, videoHeight); + } if (whenReadyFinal[0] != null) { post(whenReadyFinal[0]); whenReadyFinal[0] = null; @@ -558,7 +693,7 @@ public void onRenderedFirstFrame() { 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(); @@ -573,7 +708,9 @@ public void onRenderedFirstFrame() { } @Override - public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + invalidateTextureViewHolder(); + } @Override public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { @@ -590,11 +727,15 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { 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) { @@ -612,10 +753,11 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { if (seekTo > 0) { videoPlayer.seekTo(seekTo); } - videoPlayer.setMute(entry.muted); + checkVolumes(); updateAudioPlayer(true); - timelineView.setVideo(entry.getOriginalFile().getAbsolutePath(), getDuration()); + 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) { @@ -624,67 +766,157 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { } } + 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) { + roundPlayer.pause(); + roundPlayer.releasePlayer(true); + roundPlayer = null; + } + if (timelineView != null) { + timelineView.setRoundNull(animated); + } + this.roundView = null; + AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); + } else { + if (roundPlayer != null) { + roundPlayer.releasePlayer(true); + roundPlayer = null; + } + + roundPlayer = new VideoPlayer(); + roundPlayer.allowMultipleInstances = true; + roundPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + @Override + public void onStateChanged(boolean playWhenReady, int playbackState) { + if (roundPlayer == null) { + return; + } + if (roundPlayer != null && roundPlayer.isPlaying()) { + AndroidUtilities.runOnUIThread(updateRoundProgressRunnable); + } else { + AndroidUtilities.cancelRunOnUIThread(updateRoundProgressRunnable); + } + } + + @Override + public void onError(VideoPlayer player, Exception e) { + + } + + @Override + public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + roundPlayerWidth = width; + roundPlayerHeight = height; + if (PreviewView.this.roundView != null) { + PreviewView.this.roundView.resizeTextureView(width, height); + } + } + + @Override + public void onRenderedFirstFrame() { + + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} + + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + }); + + Uri uri = Uri.fromFile(entry.round); + roundPlayer.preparePlayer(uri, "other"); + checkVolumes(); + attachRoundView(roundView); + timelineView.setRound(entry.round.getAbsolutePath(), entry.roundDuration, entry.roundOffset, entry.roundLeft, entry.roundRight, entry.roundVolume, animated); + updateRoundPlayer(true); + } + } + + public void attachRoundView(RoundView roundView) { + this.roundView = roundView; + if (roundView != null && roundPlayer != null) { + roundPlayer.setTextureView(roundView.textureView); + } + } + public long release() { if (audioPlayer != null) { audioPlayer.pause(); audioPlayer.releasePlayer(true); audioPlayer = null; } + long t = 0; + if (roundPlayer != null) { + t = roundPlayer.getCurrentPosition(); + roundPlayer.pause(); + roundPlayer.releasePlayer(true); + roundPlayer = null; + } if (videoPlayer != null) { - long t = videoPlayer.getCurrentPosition(); + t = videoPlayer.getCurrentPosition(); videoPlayer.pause(); videoPlayer.releasePlayer(true); videoPlayer = null; - return t; - } - return 0; - } - - 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()); - } } + return t; } public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterView) { @@ -716,8 +948,10 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi seekedLastTime = System.currentTimeMillis(); videoPlayer.seekTo(pos = (long) (entry.left * getDuration())); updateAudioPlayer(true); + updateRoundPlayer(true); } else { updateAudioPlayer(pos < lastPos); + updateRoundPlayer(pos < lastPos); } timelineView.setProgress(videoPlayer.getCurrentPosition()); } else { @@ -731,7 +965,7 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi }; private final Runnable updateAudioProgressRunnable = () -> { - if (audioPlayer == null || videoPlayer != null || timelineView == null) { + if (audioPlayer == null || videoPlayer != null || roundPlayer != null || timelineView == null) { return; } @@ -748,12 +982,31 @@ public void setFilterTextureView(TextureView view, PhotoFilterView photoFilterVi } }; + private final Runnable updateRoundProgressRunnable = () -> { + if (roundPlayer == null || videoPlayer != null || timelineView == null) { + return; + } + + long pos = roundPlayer.getCurrentPosition(); + if (entry != null && (pos < entry.roundLeft * entry.roundDuration || pos > entry.roundRight * entry.roundDuration) && System.currentTimeMillis() - seekedLastTime > MIN_DURATION / 2) { + seekedLastTime = System.currentTimeMillis(); + roundPlayer.seekTo(pos = (long) (entry.roundLeft * entry.roundDuration)); + updateAudioPlayer(true); + } + timelineView.setProgress(pos); + + if (roundPlayer.isPlaying()) { + AndroidUtilities.cancelRunOnUIThread(this.updateRoundProgressRunnable); + AndroidUtilities.runOnUIThread(this.updateRoundProgressRunnable, (long) (1000L / AndroidUtilities.screenRefreshRate)); + } + }; + private void updateAudioPlayer(boolean updateSeek) { if (audioPlayer == null || entry == null) { return; } - if (videoPlayer == null) { + if (videoPlayer == null && roundPlayer == null) { audioPlayer.setPlayWhenReady(pauseLinks.isEmpty()); audioPlayer.setLooping(true); @@ -768,9 +1021,11 @@ private void updateAudioPlayer(boolean updateSeek) { return; } - final long pos = videoPlayer.getCurrentPosition(); + VideoPlayer player = videoPlayer != null ? videoPlayer : roundPlayer; + + final long pos = player.getCurrentPosition(); final long duration = (long) ((entry.audioRight - entry.audioLeft) * entry.audioDuration); - boolean shouldPlaying = videoPlayer.isPlaying() && pos >= entry.audioOffset && pos <= entry.audioOffset + duration; + boolean shouldPlaying = player.isPlaying() && pos >= entry.audioOffset && pos <= entry.audioOffset + duration; long audioPos = pos - entry.audioOffset + (long) (entry.audioLeft * entry.audioDuration); if (audioPlayer.isPlaying() != shouldPlaying) { audioPlayer.setPlayWhenReady(shouldPlaying); @@ -780,19 +1035,71 @@ private void updateAudioPlayer(boolean updateSeek) { } } + private void updateRoundPlayer(boolean updateSeek) { + if (roundPlayer == null || entry == null) { + return; + } + + if (videoPlayer == null) { + roundPlayer.setPlayWhenReady(pauseLinks.isEmpty()); + roundPlayer.setLooping(true); + if (roundView != null) { + roundView.setShown(true, false); + } + + long pos = roundPlayer.getCurrentPosition(); + if (updateSeek && roundPlayer.getDuration() != C.TIME_UNSET) { + final float progress = pos / (float) roundPlayer.getDuration(); + if ((progress < entry.roundLeft || progress > entry.roundRight) && System.currentTimeMillis() - seekedLastTime > MIN_DURATION / 2) { + seekedLastTime = System.currentTimeMillis(); + roundPlayer.seekTo(pos = -entry.roundOffset); + } + } + return; + } + + final long pos = videoPlayer.getCurrentPosition(); + final long duration = (long) ((entry.roundRight - entry.roundLeft) * entry.roundDuration); + boolean shouldPlayingInSeek = pos >= entry.roundOffset && pos <= entry.roundOffset + duration; + boolean shouldPlaying = videoPlayer.isPlaying() && shouldPlayingInSeek; + long roundPos = pos - entry.roundOffset + (long) (entry.roundLeft * entry.roundDuration); + if (roundView != null) { + roundView.setShown(shouldPlayingInSeek, true); + } + if (roundPlayer.isPlaying() != shouldPlaying) { + roundPlayer.setPlayWhenReady(shouldPlaying); + roundPlayer.seekTo(roundPos); + } else if (updateSeek && Math.abs(roundPlayer.getCurrentPosition() - roundPos) > 120) { + roundPlayer.seekTo(roundPos); + } + } + private Runnable onErrorListener; public void whenError(Runnable listener) { onErrorListener = listener; } + public boolean isMuted; public void mute(boolean value) { - if (videoPlayer == null) { - return; + isMuted = value; + checkVolumes(); + } + public void checkVolumes() { + if (videoPlayer != null) { + videoPlayer.setVolume(isMuted || (entry != null && entry.muted) ? 0 : (entry != null ? entry.videoVolume : 1f)); + } + if (roundPlayer != null) { + roundPlayer.setVolume(isMuted ? 0 : (entry != null ? entry.roundVolume : 1f)); + } + if (audioPlayer != null) { + audioPlayer.setVolume(isMuted ? 0 : (entry != null ? entry.audioVolume : 1f)); } - videoPlayer.setMute(value); } + private 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; @@ -831,10 +1138,35 @@ public void setDraw(boolean draw) { } 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) { @@ -853,46 +1185,16 @@ protected void dispatchDraw(Canvas canvas) { } } 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); @@ -917,7 +1219,7 @@ public void setVisibility(int visibility) { } public void applyMatrix() { - if (entry == null) { + if (entry == null || entry.isRepostMessage) { return; } if (textureView != null) { @@ -951,16 +1253,7 @@ public void setAllowCropping(boolean allow) { 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; @@ -995,33 +1288,15 @@ private boolean touchEvent(MotionEvent ev) { 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) { @@ -1051,15 +1326,6 @@ private boolean touchEvent(MotionEvent ev) { } 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); @@ -1078,41 +1344,19 @@ private boolean touchEvent(MotionEvent ev) { 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; @@ -1127,39 +1371,10 @@ private boolean touchEvent(MotionEvent ev) { 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) { @@ -1190,10 +1405,8 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { @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; @@ -1234,6 +1447,7 @@ public void updatePauseReason(int reasonId, boolean pause) { videoPlayer.setPlayWhenReady(pauseLinks.isEmpty()); } updateAudioPlayer(true); + updateRoundPlayer(true); } // ignores actual player and other reasons to pause a video @@ -1244,4 +1458,202 @@ public boolean isPlaying() { 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/RecordControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java index 7538878026..6081706dd7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RecordControl.java @@ -211,6 +211,15 @@ public void setInvert(float invert) { unlockDrawable.setColorFilter(new PorterDuffColorFilter(ColorUtils.blendARGB(0xffffffff, 0xff000000, invert), PorterDuff.Mode.MULTIPLY)); } + public float amplitude; + public final AnimatedFloat animatedAmplitude = new AnimatedFloat(this, 0, 200, CubicBezierInterpolator.DEFAULT); + public void setAmplitude(float amplitude, boolean animated) { + this.amplitude = amplitude; + if (!animated) { + this.animatedAmplitude.set(amplitude, true); + } + } + private float cx, cy; private float leftCx, rightCx; @@ -340,7 +349,7 @@ protected void onDraw(Canvas canvas) { } canvas.save(); - scale = lerp(recordButton.getScale(startModeIsVideo ? 0 : .2f), 1, recordingT); + scale = lerp(recordButton.getScale(startModeIsVideo ? 0 : .2f), 1 + .2f * animatedAmplitude.set(amplitude), recordingT); canvas.scale(scale, scale, cx, cy); mainPaint.setColor(ColorUtils.blendARGB(WHITE, RED, isVideo)); float acx = lerp(cx, recordCx.set(cx + dp(4) * touchCenterT16), touchIsCenterT); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java new file mode 100644 index 0000000000..5269263266 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/RoundVideoRecorder.java @@ -0,0 +1,323 @@ +package org.telegram.ui.Stories.recorder; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ViewAnimator; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.camera.CameraController; +import org.telegram.messenger.camera.CameraView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Views.RoundView; + +import java.io.File; + +public class RoundVideoRecorder extends FrameLayout { + + public final CameraView cameraView; + public final File file; + + private long recordingStarted = -1; + private long recordingStopped = -1; + public final long MAX_DURATION = 59_500L; + + private final Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Runnable stopRunnable = this::stop; + + public RoundVideoRecorder(Context context) { + super(context); + + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setStrokeCap(Paint.Cap.ROUND); + progressPaint.setStrokeJoin(Paint.Join.ROUND); + + file = StoryEntry.makeCacheFile(UserConfig.selectedAccount, true); + + cameraView = new CameraView(context, true, false) { + private final Path circlePath = new Path(); + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + circlePath.rewind(); + circlePath.addCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth() / 2f, getHeight() / 2f), Path.Direction.CW); + canvas.clipPath(circlePath); + super.dispatchDraw(canvas); + canvas.restore(); + } + + @Override + protected boolean square() { + return true; + } + + @Override + protected void receivedAmplitude(double amplitude) { + RoundVideoRecorder.this.receivedAmplitude(amplitude); + } + }; + cameraView.setScaleX(0f); + cameraView.setScaleY(0f); + addView(cameraView); + cameraView.setDelegate(() -> { + if (recordingStarted > 0) return; + CameraController.getInstance().recordVideo(cameraView.getCameraSession(), file, false, (thumbPath, duration) -> { + recordingStopped = System.currentTimeMillis(); + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + if (cancelled) { + return; + } + if (duration > 1000) { + cameraView.destroy(true, null); + if (onDoneCallback != null) { + onDoneCallback.run(file, thumbPath, duration); + } + } else { + destroy(false); + } + }, () -> { + cameraView.animate().scaleX(1f).scaleY(1f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(280).start(); + recordingStarted = System.currentTimeMillis(); + invalidate(); + + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } catch (Exception ignore) {} + + AndroidUtilities.runOnUIThread(stopRunnable, MAX_DURATION); + }, cameraView, true); + }); + cameraView.initTexture(); + + setWillNotDraw(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = MeasureSpec.getSize(widthMeasureSpec); + final int height = MeasureSpec.getSize(heightMeasureSpec); + + final int side = (int) (Math.min(width, height) * .43f); + cameraView.measure( + MeasureSpec.makeMeasureSpec(side, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(side, MeasureSpec.EXACTLY) + ); + + setMeasuredDimension(width, height); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int x = (right - left) - cameraView.getMeasuredWidth() - dp(16); + final int y = dp(72); + cameraView.layout(x, y, x + cameraView.getMeasuredWidth(), y + cameraView.getMeasuredHeight()); + } + + protected void receivedAmplitude(double amplitude) { + + } + + private Utilities.Callback3 onDoneCallback; + public RoundVideoRecorder onDone(Utilities.Callback3 onDoneCallback) { + this.onDoneCallback = onDoneCallback; + return this; + } + + private Runnable onDestroyCallback; + public RoundVideoRecorder onDestroy(Runnable onDestroyCallback) { + this.onDestroyCallback = onDestroyCallback; + return this; + } + + private float alpha = 1f; + private RoundView roundView; + + @Override + protected void dispatchDraw(Canvas canvas) { + AndroidUtilities.rectTmp.set( + cameraView.getX() + cameraView.getWidth() / 2f * (1f - cameraView.getScaleX()), + cameraView.getY() + cameraView.getHeight() / 2f * (1f - cameraView.getScaleY()), + cameraView.getX() + cameraView.getWidth() - cameraView.getWidth() / 2f * (1f - cameraView.getScaleX()), + cameraView.getY() + cameraView.getHeight() - cameraView.getHeight() / 2f * (1f - cameraView.getScaleY()) + ); + + shadowPaint.setShadowLayer(dp(2), 0, dp(.66f), Theme.multAlpha(0x20000000, alpha)); + shadowPaint.setAlpha((int) (0xff * alpha)); + canvas.drawCircle(AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY(), Math.min(AndroidUtilities.rectTmp.width() / 2f, AndroidUtilities.rectTmp.height() / 2f) - 1, shadowPaint); + + super.dispatchDraw(canvas); + if (roundView != null && roundView.getWidth() > 0 && roundView.getHeight() > 0) { + canvas.save(); + canvas.translate(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top); + canvas.scale( + AndroidUtilities.rectTmp.width() / roundView.getWidth(), + AndroidUtilities.rectTmp.height() / roundView.getHeight() + ); + float wasAlpha = roundView.getAlpha(); + roundView.setDraw(true); + roundView.setAlpha(1f - alpha); + roundView.draw(canvas); + roundView.setAlpha(wasAlpha); + roundView.setDraw(false); + canvas.restore(); + } + + if (recordingStarted > 0) { + float t = Utilities.clamp(sinceRecording() / (float) MAX_DURATION, 1, 0); + + progressPaint.setStrokeWidth(dp(3.33f)); + progressPaint.setColor(Theme.multAlpha(0xbeffffff, alpha)); + progressPaint.setShadowLayer(dp(1), 0, dp(.33f), Theme.multAlpha(0x20000000, alpha)); + AndroidUtilities.rectTmp.inset(-dp(3.33f / 2f + 6), -dp(3.33f / 2f + 6)); + canvas.drawArc(AndroidUtilities.rectTmp, -90f, 360f * t, false, progressPaint); + + if (recordingStopped <= 0) + invalidate(); + } + } + + public long sinceRecording() { + return recordingStarted < 0 ? 0 : Math.min(MAX_DURATION, (recordingStopped < 0 ? System.currentTimeMillis() : recordingStopped) - recordingStarted); + } + + public String sinceRecordingText() { + long fullms = sinceRecording(); + int sec = (int) (fullms / 1000); + int ms = (int) ((fullms - sec * 1000) / 100); + int min = (int) (sec / 60); + sec = sec % 60; + return min + ":" + (sec < 10 ? "0" : "") + sec + "." + ms; + } + + private ValueAnimator cameraViewAnimator; + public void hideTo(RoundView roundView) { + if (roundView == null) { + destroy(false); + return; + } + + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + cameraView.destroy(true, null); + if (roundView != null) { + roundView.setDraw(false); + } + post(() -> { + if (roundView.getWidth() <= 0) { + cameraView.animate().scaleX(0).scaleY(1).withEndAction(() -> { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(this); + } + }).start(); + return; + } + + final float scale = (float) roundView.getWidth() / cameraView.getWidth(); + if (cameraViewAnimator != null) { + cameraViewAnimator.cancel(); + } + cameraViewAnimator = ValueAnimator.ofFloat(0, 1); + final float fromScale = cameraView.getScaleX(); + final float toX = (roundView.getX() + roundView.getWidth() / 2f) - (cameraView.getX() + cameraView.getWidth() / 2f); + final float toY = (roundView.getY() + roundView.getHeight() / 2f) - (cameraView.getY() + cameraView.getHeight() / 2f); + cameraViewAnimator.addUpdateListener(anm -> { + final float t = (float) anm.getAnimatedValue(); + cameraView.setScaleX(AndroidUtilities.lerp(fromScale, scale, t)); + cameraView.setScaleY(AndroidUtilities.lerp(fromScale, scale, t)); + cameraView.setTranslationX(toX * t); + cameraView.setTranslationY(toY * t); + cameraView.setAlpha(1f - t); + alpha = 1f - t; + invalidate(); + }); + cameraViewAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (roundView != null) { + roundView.setDraw(true); + } + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(RoundVideoRecorder.this); + } + } + }); + cameraViewAnimator.setDuration(320); + cameraViewAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + this.roundView = roundView; + cameraViewAnimator.start(); + }); + } + + public void stop() { + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + if (recordingStarted <= 0) { + destroy(true); + } else { + CameraController.getInstance().stopVideoRecording(cameraView.getCameraSessionRecording(), false, false); + } + } + + private boolean cancelled = false; + public void cancel() { + cancelled = true; + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + CameraController.getInstance().stopVideoRecording(cameraView.getCameraSessionRecording(), false, false); + destroy(false); + } + + private ValueAnimator destroyAnimator; + private float destroyT; + public void destroy(boolean instant) { + if (onDestroyCallback != null) { + onDestroyCallback.run(); + onDestroyCallback = null; + } + AndroidUtilities.cancelRunOnUIThread(stopRunnable); + cameraView.destroy(true, null); + try { + file.delete(); + } catch (Exception ignore) {} + if (instant) { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(this); + } + } else { + if (destroyAnimator != null) { + destroyAnimator.cancel(); + } + destroyAnimator = ValueAnimator.ofFloat(destroyT, 1); + destroyAnimator.addUpdateListener(anm -> { + destroyT = (float) anm.getAnimatedValue(); + cameraView.setScaleX(1f - destroyT); + cameraView.setScaleY(1f - destroyT); + invalidate(); + }); + destroyAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (getParent() instanceof ViewGroup) { + ((ViewGroup) getParent()).removeView(RoundVideoRecorder.this); + } + } + }); + destroyAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + destroyAnimator.setDuration(280); + destroyAnimator.start(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java index ef432b18e4..eaf72d6aa9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/SliderView.java @@ -34,6 +34,7 @@ public class SliderView extends View { public static final int TYPE_VOLUME = 0; public static final int TYPE_WARMTH = 1; public static final int TYPE_INTENSITY = 2; + public static final int TYPE_DIMMING = 3; private final int currentType; @@ -87,6 +88,8 @@ public SliderView(Context context, int type) { text2.setText(LocaleController.getString(R.string.FlashWarmth)); } else if (currentType == TYPE_INTENSITY) { text2.setText(LocaleController.getString(R.string.FlashIntensity)); + } else if (currentType == TYPE_DIMMING) { + text2.setText(LocaleController.getString(R.string.WallpaperDimming)); } } text.setText(""); @@ -103,6 +106,7 @@ public SliderView setMinMax(float min, float max) { public SliderView setValue(float volume) { this.value = (volume - this.minVolume) / (this.maxVolume - this.minVolume); + this.valueAnimated.set(this.value, true); updateText(volume); return this; } @@ -112,6 +116,12 @@ public SliderView setOnValueChange(Utilities.Callback listener) { return this; } + public void animateValueTo(float volume) { + this.valueIsAnimated = true; + this.value = (volume - this.minVolume) / (this.maxVolume - this.minVolume); + updateText(volume); + } + private final Path clipPath = new Path(); private final Path speaker1Path = new Path(); private final Path speaker2Path = new Path(); @@ -246,7 +256,11 @@ private void updateText(float value) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - r = dpf2(6.33f); + if (currentType == TYPE_DIMMING) { + r = dpf2(8); + } else { + r = dpf2(6.33f); + } textPaint.setTextSize(dp(16)); text.setTextSize(dp(15)); if (currentType == TYPE_VOLUME) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java index e46654cb12..12fdbfb33b 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.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.util.ArrayList; import java.util.List; -public class StoryEntry extends IStoryPart { +public class StoryEntry { public final int currentAccount = UserConfig.selectedAccount; @@ -63,6 +69,16 @@ public class StoryEntry extends IStoryPart { public boolean editedMedia, editedCaption, editedPrivacy; public ArrayList editedMediaAreas; + public boolean isRepost; + public CharSequence repostPeerName; + public TLRPC.Peer repostPeer; + public int repostStoryId; + public String repostCaption; + public TLRPC.MessageMedia repostMedia; + + public boolean isRepostMessage; + public ArrayList messageObjects; + public boolean isError; public TLRPC.TL_error error; @@ -82,60 +98,35 @@ public class StoryEntry extends IStoryPart { public boolean fileDeletable; 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 TLRPC.InputPeer peer; + public File round; + public String roundThumb; + public long roundDuration; + public long roundOffset; + public float roundLeft, roundRight = 1; + public float roundVolume = 1; - 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]); - } - } - } + public TLRPC.InputPeer peer; - // 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; @@ -165,6 +156,9 @@ public void serializeToStream(AbstractSerializedData stream) { public ArrayList mediaEntities; public List stickers; public List editStickers; + public File messageFile; + public File messageVideoMaskFile; + public File backgroundFile; // filter public File filterFile; @@ -174,12 +168,19 @@ public void serializeToStream(AbstractSerializedData stream) { private boolean fromCamera; public boolean wouldBeVideo() { + return wouldBeVideo(mediaEntities); + } + + public boolean wouldBeVideo(ArrayList mediaEntities) { if (isVideo) { return true; } if (audioPath != null) { return true; } + if (round != null) { + return true; + } if (mediaEntities != null && !mediaEntities.isEmpty()) { for (int i = 0; i < mediaEntities.size(); ++i) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(i); @@ -207,6 +208,23 @@ private boolean isAnimated(TLRPC.Document document, String path) { ); } + 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(); @@ -215,9 +233,36 @@ public Bitmap buildBitmap(float scale, Bitmap mainFileBitmap) { 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) { @@ -240,24 +285,24 @@ public Bitmap buildBitmap(float scale, Bitmap mainFileBitmap) { } } - 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); @@ -465,6 +510,18 @@ public void clearPaint() { 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; @@ -485,7 +542,7 @@ public void destroy(boolean draft) { clearFilter(); if (file != null) { if (fileDeletable && (!isEdit || editedMedia)) { - file.delete(); + file.delete(); } file = null; } @@ -495,11 +552,27 @@ public void destroy(boolean draft) { } 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(); + round = null; + } + if (roundThumb != null && (!isEdit || editedMedia)) { + try { + new File(roundThumb).delete(); + } catch (Exception e) {} + roundThumb = null; } } if (thumbPathBitmap != null) { @@ -509,6 +582,168 @@ public void destroy(boolean draft) { cancelCheckStickers(); } + public static StoryEntry repostStoryItem(File file, TL_stories.StoryItem storyItem) { + StoryEntry entry = new StoryEntry(); + entry.isRepost = true; + entry.repostMedia = storyItem.media; + entry.repostPeer = MessagesController.getInstance(entry.currentAccount).getPeer(storyItem.dialogId); + entry.repostStoryId = storyItem.id; + entry.repostCaption = storyItem.caption; + entry.file = file; + entry.fileDeletable = false; + entry.width = 720; + entry.height = 1280; + if (storyItem.media instanceof TLRPC.TL_messageMediaPhoto) { + entry.isVideo = false; + if (file != null) { + entry.decodeBounds(file.getAbsolutePath()); + } + } else if (storyItem.media instanceof TLRPC.TL_messageMediaDocument) { + entry.isVideo = true; + if (storyItem.media.document != null && storyItem.media.document.attributes != null) { + for (int i = 0; i < storyItem.media.document.attributes.size(); ++i) { + TLRPC.DocumentAttribute attr = storyItem.media.document.attributes.get(i); + if (attr instanceof TLRPC.TL_documentAttributeVideo) { + entry.width = attr.w; + entry.height = attr.h; + entry.fileDuration = attr.duration; + break; + } + } + } + if (storyItem.media.document != null) { + if (storyItem.firstFramePath != null) { + entry.thumbPath = storyItem.firstFramePath; + } else if (storyItem.media.document.thumbs != null) { + for (int i = 0; i < storyItem.media.document.thumbs.size(); ++i) { + TLRPC.PhotoSize photoSize = storyItem.media.document.thumbs.get(i); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + entry.thumbPathBitmap = ImageLoader.getStrippedPhotoBitmap(photoSize.bytes, null); + continue; + } + File path = FileLoader.getInstance(entry.currentAccount).getPathToAttach(photoSize, true); + if (path != null && path.exists()) { + entry.thumbPath = path.getAbsolutePath(); + continue; + } + } + } + } + } + entry.setupMatrix(); + entry.checkStickers(storyItem); + return entry; + } + + public static 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; @@ -761,100 +996,124 @@ public void getVideoEditedInfo(@NonNull Utilities.Callback when 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(); - - 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(); - - final int encoderBitrate = MediaController.extractRealEncoderBitrate(info.resultWidth, info.resultHeight, info.bitrate, true); - if (isVideo) { + 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.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 && 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; + } 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 = 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(); + } + 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 { - if (filterFile != null) { - info.originalPath = filterFile.getAbsolutePath(); - } else { - info.originalPath = videoPath; - } - info.isPhoto = true; - 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.estimatedDuration = info.originalDuration = duration = averageDuration; } - info.avatarStartTime = -1; + 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; - info.cropState = new MediaController.CropState(); - info.cropState.useMatrix = new Matrix(); - info.cropState.useMatrix.set(matrix); + info.cropState = new MediaController.CropState(); + info.cropState.useMatrix = new Matrix(); + info.cropState.useMatrix.set(matrix); - info.mediaEntities = mediaEntities; + info.mediaEntities = mediaEntities; - info.gradientTopColor = gradientTopColor; - info.gradientBottomColor = gradientBottomColor; - info.forceFragmenting = true; + info.gradientTopColor = gradientTopColor; + info.gradientBottomColor = gradientBottomColor; + info.forceFragmenting = true; - info.hdrInfo = hdrInfo; - info.parts = parts; + info.hdrInfo = hdrInfo; - info.mixedSoundInfos.clear(); - 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.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); + 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) { @@ -1071,9 +1330,6 @@ public StoryEntry copy() { 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); @@ -1094,6 +1350,8 @@ public StoryEntry copy() { newEntry.uploadThumbFile = uploadThumbFile; newEntry.draftThumbFile = draftThumbFile; newEntry.paintFile = paintFile; + newEntry.messageFile = messageFile; + newEntry.backgroundFile = backgroundFile; newEntry.paintBlurFile = paintBlurFile; newEntry.paintEntitiesFile = paintEntitiesFile; newEntry.averageDuration = averageDuration; @@ -1110,6 +1368,14 @@ public StoryEntry copy() { newEntry.thumbBitmap = thumbBitmap; newEntry.fromCamera = fromCamera; newEntry.thumbPathBitmap = thumbPathBitmap; + newEntry.isRepost = isRepost; + newEntry.round = round; + newEntry.roundLeft = roundLeft; + newEntry.roundRight = roundRight; + newEntry.roundDuration = roundDuration; + newEntry.roundThumb = roundThumb; + newEntry.roundOffset = roundOffset; + newEntry.roundVolume = roundVolume; return newEntry; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java index df3a45a14b..574ce11682 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java @@ -50,8 +50,6 @@ import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.exoplayer2.util.Consumer; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -89,13 +87,11 @@ import org.telegram.ui.Components.GroupCreateSpan; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; -import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RadioButton; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.ViewPagerFixed; -import org.telegram.ui.LaunchActivity; import org.telegram.ui.Stories.StoriesController; import java.util.ArrayList; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java index 538e0c0c9f..d7f2d7507b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacySelector.java @@ -497,6 +497,9 @@ private static StoryPrivacyBottomSheet.StoryPrivacy getSaved(int currentAccount) } public static void applySaved(int currentAccount, StoryEntry entry) { + if (entry == null) { + return; + } entry.privacy = getSaved(currentAccount); entry.privacyRules.clear(); entry.privacyRules.addAll(entry.privacy.rules); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java index 5b11bd5554..55bbf5ee98 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.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.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; @@ -48,11 +50,11 @@ import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; +import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.URLSpan; -import android.util.Log; import android.util.Pair; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -67,6 +69,7 @@ import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; @@ -98,6 +101,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; +import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.camera.CameraController; import org.telegram.messenger.camera.CameraSession; import org.telegram.tgnet.TLObject; @@ -107,19 +111,27 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.BasePermissionsActivity; +import org.telegram.ui.AvatarSpan; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.Components.AlertsCreator; +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; import org.telegram.ui.Components.PhotoFilterView; @@ -129,8 +141,10 @@ 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; import org.telegram.ui.Components.ZoomControlView; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; @@ -154,8 +168,8 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg private final Theme.ResourcesProvider resourcesProvider = new DarkThemeResourceProvider(); - private Activity activity; - private int currentAccount; + private final Activity activity; + private final int currentAccount; private boolean isShown; private boolean prepareClosing; @@ -165,9 +179,11 @@ 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; + private long wasSendPeer = 0; private ClosingViewProvider closingSourceProvider; public static StoryRecorder getInstance(Activity activity, int currentAccount) { @@ -222,7 +238,7 @@ public StoryRecorder(Activity activity, int currentAccount) { private ValueAnimator openCloseAnimator; private SourceView fromSourceView; private float fromRounding; - private RectF fromRect = new RectF(); + private final RectF fromRect = new RectF(); private float openProgress; private int openType; private float dismissProgress; @@ -235,13 +251,14 @@ public static class SourceView { int type = 0; float rounding; RectF screenRect = new RectF(); + Drawable backgroundDrawable; ImageReceiver backgroundImageReceiver; + boolean hasShadow; Paint backgroundPaint; Drawable iconDrawable; int iconSize; View view; - protected void show() {} protected void hide() {} protected void drawAbove(Canvas canvas, float alpha) {} @@ -336,6 +353,7 @@ protected void hide() { 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(); @@ -344,6 +362,36 @@ protected void hide() { 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; @@ -389,6 +437,21 @@ public StoryRecorder closeToWhenSent(ClosingViewProvider closingSourceProvider) return this; } + public void replaceSourceView(SourceView sourceView) { + if (sourceView != null) { + fromSourceView = sourceView; + openType = sourceView.type; + fromRect.set(sourceView.screenRect); + fromRounding = sourceView.rounding; + } else { + fromSourceView = null; + openType = 0; + fromRect.set(0, dp(100), AndroidUtilities.displaySize.x, dp(100) + AndroidUtilities.displaySize.y); + fromRounding = dp(8); + } + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); + } + public void open(SourceView sourceView) { open(sourceView, true); } @@ -401,6 +464,7 @@ public void open(SourceView sourceView, boolean animated) { prepareClosing = false; // privacySelectorHintOpened = false; forceBackgroundVisible = false; + videoTextureHolder.active = false; if (windowManager != null && windowView != null && windowView.getParent() == null) { windowManager.addView(windowView, windowLayoutParams); @@ -428,7 +492,7 @@ public void open(SourceView sourceView, boolean animated) { fromRounding = dp(8); } containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); containerView.setTranslationX(0); containerView.setTranslationY(0); @@ -450,7 +514,6 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean } prepareClosing = false; -// privacySelectorHintOpened = false; forceBackgroundVisible = false; if (windowManager != null && windowView != null && windowView.getParent() == null) { @@ -459,6 +522,7 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean outputEntry = entry; isVideo = outputEntry != null && outputEntry.isVideo; + videoTextureHolder.active = false; if (sourceView != null) { fromSourceView = sourceView; @@ -472,7 +536,7 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean fromRounding = dp(8); } containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); containerView.setTranslationX(0); containerView.setTranslationY(0); @@ -493,6 +557,115 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean }, time); navigateTo(PAGE_PREVIEW, false); switchToEditMode(EDIT_MODE_NONE, false); + previewButtons.appear(false, false); + + addNotificationObservers(); + } + + public void openForward(SourceView sourceView, StoryEntry entry, long time, boolean animated) { + if (isShown) { + return; + } + + prepareClosing = false; + forceBackgroundVisible = false; + + if (windowManager != null && windowView != null && windowView.getParent() == null) { + windowManager.addView(windowView, windowLayoutParams); + } + + outputEntry = entry; + StoryPrivacySelector.applySaved(currentAccount, outputEntry); + isVideo = outputEntry != null && outputEntry.isVideo; + videoTextureHolder.active = false; + + 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); + } + + navigateToPreviewWithPlayerAwait(() -> { + animateOpenTo(1, animated, this::onOpenDone); + }, 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(); } @@ -524,7 +697,7 @@ public void close(boolean animated) { onClosePrepareListener = null; prepareClosing = false; close(animated); - }, wasSend); + }, wasSend, wasSendPeer); return; } @@ -533,7 +706,7 @@ public void close(boolean animated) { } animateOpenTo(0, animated, this::onCloseDone); - if (openType == 1) { + if (openType == 1 || openType == 0) { windowView.setBackgroundColor(0x00000000); previewButtons.appear(false, true); } @@ -570,6 +743,7 @@ private void animateOpenTo(final float value, boolean animated, Runnable onDone) public void onAnimationEnd(Animator animation) { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -588,6 +762,9 @@ public void onAnimationEnd(Animator animation) { onFullyOpenListener.run(); onFullyOpenListener = null; } + + containerView.invalidate(); + previewContainer.invalidate(); } }); if (value < 1 && wasSend) { @@ -595,7 +772,7 @@ public void onAnimationEnd(Animator animation) { 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); @@ -606,6 +783,7 @@ public void onAnimationEnd(Animator animation) { } else { frozenDismissProgress = null; openProgress = value; + applyOpenProgress(); containerView.invalidate(); windowView.invalidate(); if (onDone != null) { @@ -613,6 +791,9 @@ public void onAnimationEnd(Animator animation) { } checkBackgroundVisibility(); } + if (value > 0) { + firstOpen = false; + } } private void onOpenDone() { @@ -633,6 +814,17 @@ private void onOpenDone() { } else { onResumeInternal(); } + + if (outputEntry != null && outputEntry.isRepost) { + createPhotoPaintView(); + hidePhotoPaintView(); + createFilterPhotoView(); + } else if (outputEntry != null && outputEntry.isRepostMessage) { + if (outputEntry.isVideo) { + previewView.setupVideoPlayer(outputEntry, null, 0); + } + createFilterPhotoView(); + } } private void onCloseDone() { @@ -694,8 +886,8 @@ public void setOnFullyOpenListener(Runnable listener) { onFullyOpenListener = listener; } - private Utilities.Callback3 onClosePrepareListener; - public void setOnPrepareCloseListener(Utilities.Callback3 listener) { + private Utilities.Callback4 onClosePrepareListener; + public void setOnPrepareCloseListener(Utilities.Callback4 listener) { onClosePrepareListener = listener; } @@ -706,6 +898,28 @@ public void setOnPrepareCloseListener(Utilities.Callback3= Build.VERSION_CODES.LOLLIPOP) { previewContainer.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -1645,9 +1902,12 @@ public void getOutline(View view, Outline outline) { 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()) { + return false; + } return photoFilterEnhanceView.onTouch(ev); } @@ -1677,9 +1937,6 @@ public void onEntityDragEnd(boolean delete) { 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); } @@ -1704,10 +1961,59 @@ protected void onTimeDrag(boolean dragStart, long time, boolean dragEnd) { videoTimeView.setTime(time, !dragStart); videoTimeView.show(!dragEnd, true); } + + @Override + public void onRoundSelectChange(boolean selected) { + if (paintView == null) return; + if (!selected && paintView.getSelectedEntity() instanceof RoundView) { + paintView.selectEntity(null); + } else if (selected && !(paintView.getSelectedEntity() instanceof RoundView) && paintView.findRoundView() != null) { + paintView.selectEntity(paintView.findRoundView()); + } + } + + @Override + public void onRoundRemove() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } + + @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(() -> { - if (currentEditMode != EDIT_MODE_NONE || currentPage != PAGE_PREVIEW || captionEdit.keyboardShown) { + if (currentEditMode != EDIT_MODE_NONE || currentPage != PAGE_PREVIEW || captionEdit.keyboardShown || captionEdit != null && captionEdit.isRecording()) { return; } if (timelineView.onBackPressed()) { @@ -1730,6 +2036,29 @@ protected void onTimeDrag(boolean dragStart, long time, boolean dragEnd) { 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); @@ -1738,7 +2067,7 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { @Override protected boolean captionLimitToast() { - if (MessagesController.getInstance(currentAccount).premiumLocked) { + if (MessagesController.getInstance(currentAccount).premiumFeaturesBlocked()) { return false; } Bulletin visibleBulletin = Bulletin.getVisibleBulletin(); @@ -1779,6 +2108,102 @@ public void onClick(@NonNull View widget) { protected void onCaptionLimitUpdate(boolean overLimit) { previewButtons.setShareEnabled(!videoError && !overLimit && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); } + + @Override + public boolean canRecord() { + return requestAudioPermission(); + } + + @Override + public void putRecorder(RoundVideoRecorder recorder) { + if (currentRoundRecorder != null) { + currentRoundRecorder.destroy(true); + } + if (previewView != null) { + previewView.mute(true); + previewView.seek(0); + } + recorder.onDone((file, thumb, duration) -> { + if (previewView != null) { + previewView.mute(false); + previewView.seek(0); + } + if (outputEntry != null) { + outputEntry.round = file; + outputEntry.roundThumb = thumb; + outputEntry.roundDuration = duration; + outputEntry.roundLeft = 0; + outputEntry.roundRight = 1; + outputEntry.roundOffset = 0; + outputEntry.roundVolume = 1f; + + createPhotoPaintView(); + if (previewView != null && paintView != null) { + RoundView roundView = paintView.createRound(outputEntry.roundThumb, true); + setHasRoundVideo(true); + previewView.setupRound(outputEntry, roundView, true); + + recorder.hideTo(roundView); + } else { + recorder.destroy(false); + } + } + }); + recorder.onDestroy(() -> { + if (previewView != null) { + previewView.mute(false); + previewView.seek(0); + } + }); + previewContainer.addView(currentRoundRecorder = recorder, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + @Override + public void removeRound() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } + + @Override + public void invalidateDrawOver2() { + if (captionEditOverlay != null) { + captionEditOverlay.invalidate(); + } + } + + @Override + public boolean drawOver2FromParent() { + return true; + } + + @Override + public int getTimelineHeight() { + if (videoTimelineContainerView != null && timelineView != null && timelineView.getVisibility() == View.VISIBLE) { + return timelineView.getContentHeight(); + } + return 0; + } }; captionEdit.setAccount(currentAccount); captionEdit.setUiBlurBitmap(this::getUiBlurBitmap); @@ -1817,18 +2242,28 @@ public int getBottomOffset(int tag) { visibleBulletin.updatePosition(); } }); + captionEditOverlay = new View(context) { + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + canvas.translate(captionContainer.getX() + captionEdit.getX(), captionContainer.getY() + captionEdit.getY()); + captionEdit.drawOver2(canvas, captionEdit.getBounds(), captionEdit.getOver2Alpha()); + canvas.restore(); + } + }; + containerView.addView(captionEditOverlay); timelineView = new TimelineView(context, containerView, previewContainer, resourcesProvider, blurManager); previewView.setVideoTimelineView(timelineView); timelineView.setVisibility(View.GONE); timelineView.setAlpha(0f); videoTimelineContainerView = new FrameLayout(context); - videoTimelineContainerView.addView(timelineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 0)); + videoTimelineContainerView.addView(timelineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, TimelineView.heightDp(), Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 0)); videoTimeView = new VideoTimeView(context); videoTimeView.setVisibility(View.GONE); videoTimeView.show(false, false); videoTimelineContainerView.addView(videoTimeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 25, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 0, 0, 0)); - captionContainer.addView(videoTimelineContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80 + 25, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 68)); + captionContainer.addView(videoTimelineContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, TimelineView.heightDp() + 25, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 68)); captionContainer.addView(captionEdit, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL_HORIZONTAL | Gravity.BOTTOM, 0, 200, 0, 0)); backButton = new FlashViews.ImageViewInvertable(context); @@ -1859,14 +2294,19 @@ public int getBottomOffset(int tag) { 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); @@ -1884,19 +2324,19 @@ public int getBottomOffset(int tag) { } outputEntry.muted = !outputEntry.muted; final boolean hasMusic = !TextUtils.isEmpty(outputEntry.audioPath); + final boolean hasRound = outputEntry.round != null; muteHint.setText( outputEntry.muted ? - LocaleController.getString(hasMusic ? R.string.StoryOriginalSoundMuted : R.string.StorySoundMuted) : - LocaleController.getString(hasMusic ? R.string.StoryOriginalSoundNotMuted : R.string.StorySoundNotMuted), + LocaleController.getString(hasMusic || hasRound ? R.string.StoryOriginalSoundMuted : R.string.StorySoundMuted) : + LocaleController.getString(hasMusic || hasRound ? R.string.StoryOriginalSoundNotMuted : R.string.StorySoundNotMuted), muteHint.shown() ); muteHint.show(); setIconMuted(outputEntry.muted, true); - previewView.mute(outputEntry.muted); + previewView.checkVolumes(); }); muteButton.setVisibility(View.GONE); muteButton.setAlpha(0f); - actionBarContainer.addView(muteButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT, 0, 0, 48, 0)); playButton = new PlayPauseButton(context); playButton.setBackground(Theme.createSelectorDrawable(0x20ffffff)); @@ -1907,7 +2347,10 @@ public int getBottomOffset(int tag) { 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)); @@ -2058,7 +2501,7 @@ public int getBottomOffset(int tag) { previewButtons = new PreviewButtons(context); previewButtons.setVisibility(View.GONE); previewButtons.setOnClickListener((Integer btn) -> { - if (outputEntry == null) { + if (outputEntry == null || captionEdit.isRecording()) { return; } captionEdit.clearFocus(); @@ -2251,12 +2694,10 @@ private void upload(boolean asStory) { return; } preparingUpload = true; - Utilities.globalQueue.postRunnable(() -> { - applyPaint(); - AndroidUtilities.runOnUIThread(() -> { - preparingUpload = false; - uploadInternal(asStory); - }); + applyPaintInBackground(() -> { + applyPaintMessage(); + preparingUpload = false; + uploadInternal(asStory); }); } @@ -2283,6 +2724,7 @@ private void uploadInternal(boolean asStory) { outputEntry = null; wasSend = true; + wasSendPeer = sendAsDialogId; forceBackgroundVisible = true; checkBackgroundVisibility(); @@ -2297,7 +2739,7 @@ private void uploadInternal(boolean asStory) { if (fromSourceView != null) { openType = fromSourceView.type; containerView.updateBackground(); - previewContainer.setBackgroundColor(openType == 1 ? 0 : 0xff1f1f1f); + previewContainer.setBackgroundColor(openType == 1 || openType == 0 ? 0 : 0xff1f1f1f); fromRect.set(fromSourceView.screenRect); fromRounding = fromSourceView.rounding; fromSourceView.hide(); @@ -2357,7 +2799,7 @@ private File prepareThumb(StoryEntry storyEntry, boolean forDraft) { 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) { @@ -2399,9 +2841,11 @@ private File prepareThumb(StoryEntry storyEntry, boolean forDraft) { 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(); } @@ -2526,19 +2970,22 @@ private void takePicture(Utilities.Callback done) { if (outputFile == null) { return; } + int w = -1, h = -1; + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(outputFile.getAbsolutePath(), opts); + w = opts.outWidth; + h = opts.outHeight; + } catch (Exception ignore) {} + int rotate = orientation == -1 ? 0 : 90; if (orientation == -1) { - int w = -1, h = -1; - try { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeFile(outputFile.getAbsolutePath(), opts); - w = opts.outWidth; - h = opts.outHeight; - } catch (Exception ignore) {} if (w > h) { rotate = 270; } + } else if (h > w && rotate != 0) { + rotate = 0; } outputEntry = StoryEntry.fromPhotoShoot(outputFile, rotate); StoryPrivacySelector.applySaved(currentAccount, outputEntry); @@ -2921,6 +3368,12 @@ public void onAnimationEnd(Animator animation) { } public boolean onBackPressed() { + if (openCloseAnimator != null && openCloseAnimator.isRunning()) { + return false; + } + if (captionEdit != null && captionEdit.stopRecording()) { + return false; + } if (takingVideo) { recordControl.stopRecording(); return false; @@ -2930,6 +3383,9 @@ public boolean onBackPressed() { } if (captionEdit.onBackPressed()) { return false; + } else if (themeSheet != null) { + themeSheet.dismiss(); + return false; } else if (galleryListView != null) { if (galleryListView.onBackPressed()) { return false; @@ -2942,10 +3398,10 @@ public boolean onBackPressed() { } else if (currentEditMode > EDIT_MODE_NONE) { switchToEditMode(EDIT_MODE_NONE, true); return false; - } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isEdit || (paintView != null && paintView.hasChanges()) || outputEntry.editedMedia || outputEntry.editedCaption)) { + } else if (currentPage == PAGE_PREVIEW && (outputEntry == null || !outputEntry.isRepost && !outputEntry.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)) { + } 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(); @@ -2957,9 +3413,43 @@ public boolean onBackPressed() { } } + private void setReply() { + if (captionEdit == null) return; + if (outputEntry == null || !outputEntry.isRepost) { + captionEdit.setReply(null, null); + } else { + TLRPC.Peer peer = outputEntry.repostPeer; + CharSequence peerName; + if (peer instanceof TLRPC.TL_peerUser) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(peer.user_id); + String name = UserObject.getUserName(user); + peerName = outputEntry.repostPeerName = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(name); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(peer)); + String name = chat == null ? "" : chat.title; + peerName = outputEntry.repostPeerName = new SpannableStringBuilder(MessageObject.userSpan()).append(" ").append(name); + } + CharSequence repostCaption = outputEntry.repostCaption; + if (TextUtils.isEmpty(repostCaption)) { + SpannableString s = new SpannableString(LocaleController.getString(R.string.Story)); + s.setSpan(new CharacterStyle() { + @Override + public void updateDrawState(TextPaint tp) { + tp.setAlpha(0x80); + } + }, 0, s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + repostCaption = s; + } + captionEdit.setReply(peerName, repostCaption); + } + } + private Runnable afterPlayerAwait; private boolean previewAlreadySet; public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo) { + navigateToPreviewWithPlayerAwait(open, seekTo, 800); + } + public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo, long ms) { if (awaitingPlayer || outputEntry == null) { return; } @@ -2979,7 +3469,7 @@ public void navigateToPreviewWithPlayerAwait(Runnable open, long seekTo) { previewView.setVisibility(View.VISIBLE); previewView.set(outputEntry, afterPlayerAwait, seekTo); previewView.setupAudio(outputEntry, false); - AndroidUtilities.runOnUIThread(afterPlayerAwait, 400); + AndroidUtilities.runOnUIThread(afterPlayerAwait, ms); } private AnimatorSet pageAnimator; @@ -2997,7 +3487,7 @@ public void navigateTo(int page, boolean animated) { 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) { @@ -3031,9 +3521,11 @@ public void navigateTo(int page, boolean animated) { 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)); @@ -3067,9 +3559,11 @@ public void onAnimationEnd(Animator animation) { 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); @@ -3106,6 +3600,22 @@ public void onAnimationEnd(Animator animation) { 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; @@ -3393,6 +3903,12 @@ private void onNavigateStart(int fromPage, int toPage) { 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); @@ -3401,15 +3917,20 @@ private void onNavigateStart(int fromPage, int toPage) { // privacySelector.setStoryPeriod(outputEntry == null || !UserConfig.getInstance(currentAccount).isPremium() ? 86400 : outputEntry.period); captionEdit.setPeriod(outputEntry == null ? 86400 : outputEntry.period, false); - captionEdit.setPeriodVisible(!MessagesController.getInstance(currentAccount).premiumLocked && (outputEntry == null || !outputEntry.isEdit)); + captionEdit.setPeriodVisible(!MessagesController.getInstance(currentAccount).premiumFeaturesBlocked() && (outputEntry == null || !outputEntry.isEdit)); + captionEdit.setHasRoundVideo(outputEntry != null && outputEntry.round != null); + setReply(); } if (toPage == PAGE_PREVIEW) { videoError = false; 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 : () -> { @@ -3439,12 +3960,39 @@ private void onNavigateStart(int fromPage, int toPage) { } 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); timelineView.setVisibility(View.VISIBLE); titleTextView.setVisibility(View.VISIBLE); - titleTextView.setText(outputEntry != null && outputEntry.isEdit ? LocaleController.getString(R.string.RecorderEditStory) : LocaleController.getString(R.string.RecorderNewStory)); + titleTextView.setTranslationX(0); + if (outputEntry != null && outputEntry.isEdit) { + titleTextView.setText(LocaleController.getString(R.string.RecorderEditStory)); + } else if (outputEntry != null && outputEntry.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); + titleTextView.setTranslationX(-dp(6)); + SpannableString avatar = new SpannableString("a"); + avatar.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (outputEntry.repostPeer instanceof TLRPC.TL_peerUser) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(outputEntry.repostPeer.user_id); + span.setUser(user); + title.append(avatar).append(" "); + title.append(UserObject.getUserName(user)); + } else { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-DialogObject.getPeerDialogId(outputEntry.repostPeer)); + span.setChat(chat); + title.append(avatar).append(" "); + title.append(chat != null ? chat.title : ""); + } + titleTextView.setText(title); + } else { + titleTextView.setText(LocaleController.getString(R.string.RecorderNewStory)); + } + // MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); // MediaDataController.getInstance(currentAccount).checkFeaturedEmoji(); } @@ -3489,6 +4037,9 @@ private void onNavigateEnd(int fromPage, int toPage) { 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); @@ -3501,9 +4052,13 @@ private void onNavigateEnd(int fromPage, int toPage) { videoTimeView.setVisibility(View.GONE); } if (toPage == PAGE_PREVIEW) { - createPhotoPaintView(); - hidePhotoPaintView(); - createFilterPhotoView(); + if (outputEntry == null || !outputEntry.isRepost) { + createPhotoPaintView(); + hidePhotoPaintView(); + } + if (outputEntry == null || !outputEntry.isRepost && !outputEntry.isRepostMessage) { + createFilterPhotoView(); + } if (photoFilterEnhanceView != null) { photoFilterEnhanceView.setAllowTouch(false); } @@ -3548,6 +4103,9 @@ public void switchToEditMode(int editMode, boolean animated) { if (currentEditMode == editMode) { return; } + if (editMode != EDIT_MODE_NONE && (captionEdit != null && captionEdit.isRecording())) { + return; + } final int oldEditMode = currentEditMode; currentEditMode = editMode; @@ -3602,6 +4160,9 @@ public void switchToEditMode(int editMode, boolean animated) { 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)); @@ -3717,11 +4278,13 @@ private void createPhotoPaintView() { null, previewView.getOrientation(), outputEntry == null ? null : outputEntry.mediaEntities, + outputEntry, w, h, new MediaController.CropState(), null, blurManager, - resourcesProvider + resourcesProvider, + videoTextureHolder ) { @Override public void onEntityDraggedTop(boolean value) { @@ -3744,13 +4307,12 @@ public void onEntityDraggedBottom(boolean value) { @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(); } @@ -3763,11 +4325,22 @@ public void onEntityDragStart() { 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; @@ -3776,20 +4349,13 @@ public void onEntityDragStart() { 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); } @@ -3831,7 +4397,6 @@ protected void onAudioSelect(MessageObject messageObject) { 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) { @@ -3865,6 +4430,109 @@ protected boolean checkAudioPermission(Runnable granted) { } return true; } + + @Override + public void onCreateRound(RoundView roundView) { + if (previewView != null) { + previewView.attachRoundView(roundView); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(true); + } + } + + @Override + public void onTryDeleteRound() { + if (captionEdit != null) { + captionEdit.showRemoveRoundAlert(); + } + } + + @Override + public void onDeleteRound() { + if (previewView != null) { + previewView.setupRound(null, null, true); + } + if (paintView != null) { + paintView.deleteRound(); + } + if (captionEdit != null) { + captionEdit.setHasRoundVideo(false); + } + if (outputEntry != null) { + if (outputEntry.round != null) { + try { + outputEntry.round.delete(); + } catch (Exception ignore) {} + outputEntry.round = null; + } + if (outputEntry.roundThumb != null) { + try { + new File(outputEntry.roundThumb).delete(); + } catch (Exception ignore) {} + outputEntry.roundThumb = null; + } + } + } + + @Override + public void 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) { + timelineView.selectRound(true); + } + } + + @Override + public void onDeselectRound(RoundView roundView) { + if (timelineView != null) { + timelineView.selectRound(false); + } + } }; paintView.setBlurManager(blurManager); containerView.addView(paintView); @@ -3930,6 +4598,9 @@ private void orderPreviewViews() { if (previewHighlight != null) { previewHighlight.bringToFront(); } + if (currentRoundRecorder != null) { + currentRoundRecorder.bringToFront(); + } } private void destroyPhotoPaintView() { @@ -3971,6 +4642,12 @@ private void onSwitchEditModeStart(int fromMode, int toMode) { 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) { @@ -4016,6 +4693,9 @@ private void onSwitchEditModeEnd(int fromMode, int toMode) { 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); @@ -4028,6 +4708,193 @@ private void onSwitchEditModeEnd(int fromMode, int toMode) { 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) { @@ -4042,7 +4909,7 @@ private void applyPaint() { } else { outputEntry.mediaEntities.clear(); } - paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false); + paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false, false, false, outputEntry); if (!outputEntry.isVideo) { outputEntry.averageDuration = Utilities.clamp(paintView.getLcm(), 7500L, 5000L); } @@ -4052,7 +4919,7 @@ private void applyPaint() { final boolean wouldBeVideo = outputEntry.wouldBeVideo(); outputEntry.mediaEntities = new ArrayList<>(); - Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, !isVideo); + Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false, false, !isVideo, outputEntry); if (outputEntry.mediaEntities.isEmpty()) { outputEntry.mediaEntities = null; } @@ -4082,8 +4949,94 @@ private void applyPaint() { } 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); + 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(); @@ -4101,6 +5054,42 @@ private void applyPaint() { } } + // 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) { @@ -4280,7 +5269,17 @@ protected void onSavedDualCameraSuccess() { } dualButton.setValue(isDual()); } + + @Override + protected void receivedAmplitude(double amplitude) { + if (recordControl != null) { + recordControl.setAmplitude(Utilities.clamp((float) (amplitude / WaveDrawable.MAX_AMPLITUDE), 1, 0), true); + } + } }; + if (recordControl != null) { + recordControl.setAmplitude(0, false); + } cameraView.isStory = true; cameraView.setThumbDrawable(getCameraThumb()); cameraView.initTexture(); @@ -4427,6 +5426,7 @@ private void showDismissEntry() { showSavedDraftHint = !outputEntry.isDraft; applyFilter(null); applyPaint(); + applyPaintMessage(); destroyPhotoFilterView(); StoryEntry storyEntry = outputEntry; storyEntry.destroy(true); @@ -4443,11 +5443,11 @@ private void showDismissEntry() { }); } builder.setPositiveButton(outputEntry != null && outputEntry.isDraft && !outputEntry.isEdit ? LocaleController.getString("StoryDeleteDraft") : LocaleController.getString("Discard", R.string.Discard), (dialogInterface, i) -> { - if (outputEntry != null && !outputEntry.isEdit && outputEntry.isDraft) { + if (outputEntry != null && !(outputEntry.isEdit || outputEntry.isRepost && !outputEntry.isRepostMessage) && outputEntry.isDraft) { MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().delete(outputEntry); outputEntry = null; } - if (outputEntry != null && outputEntry.isEdit) { + if (outputEntry != null && (outputEntry.isEdit || outputEntry.isRepost && !outputEntry.isRepostMessage)) { close(true); } else { navigateTo(PAGE_CAMERA, true); @@ -4644,6 +5644,22 @@ private void onRequestPermissionsResultInternal(int requestCode, String[] permis if (granted) { MediaController.loadGalleryPhotosAlbums(0); animateGalleryListView(true); + } else { + new AlertDialog.Builder(getContext(), resourcesProvider) + .setTopAnimation(R.raw.permission_request_folder, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)) + .setMessage(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PermissionStorageWithHint))) + .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); + activity.startActivity(intent); + } catch (Exception e) { + FileLog.e(e); + } + }) + .setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), null) + .create() + .show(); } } else if (requestCode == 112) { if (!granted) { @@ -4934,4 +5950,195 @@ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, }, 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 0000000000..4c2a95c054 --- /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 e80473070b..25a1ff8fe6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/TimelineView.java @@ -66,13 +66,21 @@ interface TimelineDelegate { void onVideoLeftChange(float left); void onVideoRightChange(float right); + void onVideoVolumeChange(float volume); void onAudioOffsetChange(long offset); void onAudioLeftChange(float left); void onAudioRightChange(float right); - void onAudioVolumeChange(float volume); void onAudioRemove(); + + void onRoundOffsetChange(long offset); + void onRoundLeftChange(float left); + void onRoundRightChange(float right); + void onRoundVolumeChange(float volume); + void onRoundRemove(); + + void onRoundSelectChange(boolean selected); } private TimelineDelegate delegate; @@ -81,12 +89,24 @@ interface TimelineDelegate { private long scroll; private boolean hasVideo; + private boolean isMainVideoRound; private String videoPath; private long videoDuration; private float videoLeft; private float videoRight; + private float videoVolume; private VideoThumbsLoader thumbs; + private boolean hasRound; + private String roundPath; + private boolean roundSelected; + private long roundDuration; + private long roundOffset; + private float roundLeft; + private float roundRight; + private float roundVolume; + private VideoThumbsLoader roundThumbs; + private boolean hasAudio; private String audioPath; private boolean audioSelected; @@ -96,21 +116,30 @@ interface TimelineDelegate { private float audioRight; private boolean waveformIsLoaded; private float audioVolume; + private boolean resetWaveform; private AudioWaveformLoader waveform; private long getBaseDuration() { if (hasVideo) { return videoDuration; } + if (hasRound) { + return roundDuration; + } if (hasAudio) { return audioDuration; } return Math.max(1, audioDuration); } + private final AnimatedFloat roundT = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat roundSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat audioT = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); private final AnimatedFloat audioSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat videoSelectedT = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private final AnimatedFloat waveformLoaded = new AnimatedFloat(this, 0, 600, CubicBezierInterpolator.EASE_OUT_QUINT); private final AnimatedFloat waveformMax = new AnimatedFloat(this, 0, 360, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -124,6 +153,9 @@ private long getBaseDuration() { private final Path videoClipPath = new Path(); private final Path selectedVideoClipPath = new Path(); + private final RectF roundBounds = new RectF(); + private final Path roundClipPath = new Path(); + private final Paint regionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint regionCutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint regionHandlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -190,11 +222,11 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, audioWaveformBlur = new BlurringShader.StoryBlurDrawer(blurManager, this, BlurringShader.StoryBlurDrawer.BLUR_TYPE_AUDIO_WAVEFORM_BACKGROUND); onLongPress = () -> { - if (!pressVideo && hasAudio) { + if (pressType == 2 && hasAudio) { SliderView slider = new SliderView(getContext(), SliderView.TYPE_VOLUME) - .setValue(audioVolume) .setMinMax(0, 1.5f) + .setValue(audioVolume) .setOnValueChange(volume -> { audioVolume = volume; if (delegate != null) { @@ -202,7 +234,8 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, } }); final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); - float uiRight = Math.min(w - px - ph, px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelectedT.get()) * audioDuration) / (float) videoScrollDuration * sw); + final float uiRight = Math.min(w - px - ph, px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelectedT.get()) * audioDuration) / (float) videoScrollDuration * sw); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0) - (hasAudio ? getAudioHeight() + dp(4) : 0); ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) .addView(slider) .addSpaceGap() @@ -213,10 +246,63 @@ public TimelineView(Context context, ViewGroup container, View previewContainer, }) .setGravity(Gravity.RIGHT) .forceTop(true) - .translate(-(w - uiRight) + dp(18), dp(4) + (!hasVideo ? dp(audioSelected ? 35 : 40) : 0)) + .translate(-(w - uiRight) + dp(18), y) .show(); itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception e) {} + } else if (pressType == 1 && hasRound) { + SliderView slider = + new SliderView(getContext(), SliderView.TYPE_VOLUME) + .setMinMax(0, 1.5f) + .setValue(roundVolume) + .setOnValueChange(volume -> { + roundVolume = volume; + if (delegate != null) { + delegate.onRoundVolumeChange(volume); + } + }); + final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); + final float uiRight = Math.min(w - px - ph, px + ph + (roundOffset - scroll + lerp(roundRight, 1, roundSelectedT.get()) * roundDuration) / (float) videoScrollDuration * sw); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0); + ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) + .addView(slider) + .addSpaceGap() + .add(R.drawable.msg_delete, LocaleController.getString(R.string.StoryRoundRemove), () -> { + if (delegate != null) { + delegate.onRoundRemove(); + } + }) + .setGravity(Gravity.RIGHT) + .forceTop(true) + .translate(-(w - uiRight) + dp(18), y) + .show(); + itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); + + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception e) {} + } else if (pressType == 0 && hasVideo) { + SliderView slider = + new SliderView(getContext(), SliderView.TYPE_VOLUME) + .setMinMax(0, 1.5f) + .setValue(videoVolume) + .setOnValueChange(volume -> { + videoVolume = volume; + if (delegate != null) { + delegate.onVideoVolumeChange(volume); + } + }); + final float y = h - py - (hasVideo ? getVideoHeight() + dp(4) : 0); + ItemOptions itemOptions = ItemOptions.makeOptions(container, resourcesProvider, this) + .addView(slider) + .setGravity(Gravity.RIGHT) + .forceTop(true) + .translate(dp(18), y) + .show(); + itemOptions.setBlurBackground(blurManager, -previewContainer.getX(), -previewContainer.getY()); try { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception e) {} @@ -228,7 +314,7 @@ public void setDelegate(TimelineDelegate delegate) { this.delegate = delegate; } - public void setVideo(String videoPath, long videoDuration) { + public void setVideo(boolean isRound, String videoPath, long videoDuration, float videoVolume) { if (TextUtils.equals(this.videoPath, videoPath)) { return; } @@ -236,29 +322,103 @@ public void setVideo(String videoPath, long videoDuration) { thumbs.destroy(); thumbs = null; } + isMainVideoRound = isRound; if (videoPath != null) { scroll = 0; this.videoPath = videoPath; this.videoDuration = videoDuration; + this.videoVolume = videoVolume; setupVideoThumbs(); } else { this.videoPath = null; this.videoDuration = 1; scroll = 0; } + if (!hasRound) { + roundSelected = false; + } hasVideo = this.videoPath != null; progress = 0; invalidate(); } + public void setRoundNull(boolean animated) { + setRound(null, 0, 0, 0, 0, 0, animated); + } + + public void setRound(String roundPath, long roundDuration, long offset, float left, float right, float volume, boolean animated) { + if (TextUtils.equals(this.roundPath, roundPath)) { + return; + } + if (roundThumbs != null) { + roundThumbs.destroy(); + roundThumbs = null; + } + final long hadRoundDuration = this.roundDuration; + if (roundPath != null) { + this.roundPath = roundPath; + this.roundDuration = roundDuration; + this.roundOffset = offset - (long) (left * roundDuration); + this.roundLeft = left; + this.roundRight = right; + this.roundVolume = volume; + setupRoundThumbs(); + if (!hasVideo) { + audioSelected = false; + roundSelected = true; + } + } else { + this.roundPath = null; + this.roundDuration = 1; + roundSelected = false; + } + hasRound = this.roundPath != null; + if (hadRoundDuration != roundDuration && !hasVideo && waveform != null) { + resetWaveform = true; + setupAudioWaveform(); + } + if (hasAudio && hasRound && !hasVideo) { + audioLeft = 0; + audioRight = Utilities.clamp((float) roundDuration / audioDuration, 1, 0); + } + if (!animated) { + roundSelectedT.set(roundSelected, true); + audioSelectedT.set(audioSelected, true); + roundT.set(hasRound, true); + } + invalidate(); + } + + public void selectRound(boolean select) { + if (select && hasRound) { + roundSelected = true; + audioSelected = false; + } else { + roundSelected = false; + audioSelected = hasAudio && !hasVideo; + } + invalidate(); + } + private void setupVideoThumbs() { if (getMeasuredWidth() <= 0 || this.thumbs != null) { return; } - this.thumbs = new VideoThumbsLoader(videoPath, getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), dp(38)); + this.thumbs = new VideoThumbsLoader(isMainVideoRound, videoPath, w - px - px, dp(38), videoDuration > 2 ? videoDuration : null); if (this.thumbs.getDuration() > 0) { videoDuration = this.thumbs.getDuration(); } + setupRoundThumbs(); + } + + private void setupRoundThumbs() { + if (getMeasuredWidth() <= 0 || this.roundThumbs != null || hasVideo && videoDuration < 1) { + return; + } + this.roundThumbs = new VideoThumbsLoader(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(); + } } private final AnimatedFloat loopProgress = new AnimatedFloat(0, this, 0, 340, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -266,7 +426,8 @@ private void setupVideoThumbs() { public void setProgress(long progress) { if ( hasVideo && progress < this.progress && progress <= videoDuration * videoLeft + 240 && this.progress + 240 >= videoDuration * videoRight || - hasAudio && progress < this.progress && progress <= audioDuration * audioLeft + 240 && this.progress + 240 >= audioDuration * audioRight + hasAudio && !hasRound && !hasVideo && progress < this.progress && progress <= audioDuration * audioLeft + 240 && this.progress + 240 >= audioDuration * audioRight || + hasRound && !hasVideo && progress < this.progress && progress <= roundDuration * audioLeft + 240 && this.progress + 240 >= roundDuration * audioRight ) { loopProgressFrom = -1; loopProgress.set(1, true); @@ -339,7 +500,7 @@ public void setAudio(String audioPath, String audioAuthorText, String audioTitle } private void setupAudioWaveform() { - if (getMeasuredWidth() <= 0 || this.waveform != null) { + if (getMeasuredWidth() <= 0 || this.waveform != null && !resetWaveform) { return; } this.waveform = new AudioWaveformLoader(audioPath, getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); @@ -349,15 +510,22 @@ private void setupAudioWaveform() { } private static final int HANDLE_PROGRESS = 0; + private static final int HANDLE_VIDEO_SCROLL = 1; private static final int HANDLE_VIDEO_LEFT = 2; private static final int HANDLE_VIDEO_RIGHT = 3; private static final int HANDLE_VIDEO_REGION = 4; + private static final int HANDLE_AUDIO_SCROLL = 5; private static final int HANDLE_AUDIO_LEFT = 6; private static final int HANDLE_AUDIO_RIGHT = 7; private static final int HANDLE_AUDIO_REGION = 8; + private static final int HANDLE_ROUND_SCROLL = 9; + private static final int HANDLE_ROUND_LEFT = 10; + private static final int HANDLE_ROUND_RIGHT = 11; + private static final int HANDLE_ROUND_REGION = 12; + private int detectHandle(MotionEvent event) { float x = event.getX(); float y = event.getY(); @@ -369,7 +537,8 @@ private int detectHandle(MotionEvent event) { return HANDLE_PROGRESS; } - final boolean isInVideo = y > h - py - getVideoHeight() - dp(2); + final boolean isInVideo = hasVideo && y > h - py - getVideoHeight() - dp(2); + final boolean isInRound = hasRound && y > h - py - getVideoHeight() - dp(4) - getRoundHeight() - dp(4) - dp(2) && y < h - py - getVideoHeight() - dp(2); if (isInVideo) { final float leftX = px + ph + (videoLeft * videoDuration - scroll) / (float) scrollWidth * sw; @@ -382,19 +551,36 @@ private int detectHandle(MotionEvent event) { } else if (x >= leftX && x <= rightX && (videoLeft > 0.01f || videoRight < .99f)) { return HANDLE_VIDEO_REGION; } + } else if (isInRound) { + float leftX = px + ph + (roundOffset + roundLeft * roundDuration - scroll) / (float) scrollWidth * sw; + float rightX = px + ph + (roundOffset + roundRight * roundDuration - scroll) / (float) scrollWidth * sw; + if (roundSelected || !hasVideo) { + if (x >= leftX - dp(10 + 5) && x <= leftX + dp(5)) { + return HANDLE_ROUND_LEFT; + } else if (x >= rightX - dp(5) && x <= rightX + dp(10 + 5)) { + return HANDLE_ROUND_RIGHT; + } else if (x >= leftX && x <= rightX) { + if (!hasVideo) { + return HANDLE_ROUND_REGION; + } else { + return HANDLE_ROUND_SCROLL; + } + } + leftX = px + ph + (roundOffset - scroll) / (float) scrollWidth * sw; + rightX = px + ph + (roundOffset + roundDuration - scroll) / (float) scrollWidth * sw; + } + if (x >= leftX && x <= rightX) { + return HANDLE_ROUND_SCROLL; + } } else if (hasAudio) { float leftX = px + ph + (audioOffset + audioLeft * audioDuration - scroll) / (float) scrollWidth * sw; float rightX = px + ph + (audioOffset + audioRight * audioDuration - scroll) / (float) scrollWidth * sw; - - if (audioSelected || !hasVideo) { + if (audioSelected || !hasVideo && !hasRound) { if (x >= leftX - dp(10 + 5) && x <= leftX + dp(5)) { return HANDLE_AUDIO_LEFT; } else if (x >= rightX - dp(5) && x <= rightX + dp(10 + 5)) { return HANDLE_AUDIO_RIGHT; } else if (x >= leftX && x <= rightX) { - final float maxDuration = Math.min(MAX_SCROLL_DURATION, getBaseDuration()); - final float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; - final float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + maxDuration) / (float) audioDuration); if (!hasVideo) { return HANDLE_AUDIO_REGION; } else { @@ -419,6 +605,12 @@ private int detectHandle(MotionEvent event) { public boolean onBackPressed() { if (audioSelected) { audioSelected = false; + if (hasRound && !hasVideo) { + roundSelected = true; + if (delegate != null) { + delegate.onRoundSelectChange(true); + } + } return true; } return false; @@ -465,8 +657,8 @@ private boolean setProgressAt(float x, boolean fast) { private float getVideoHeight() { if (!hasVideo) return 0; - float audioSelected = this.audioSelectedT.set(this.audioSelected); - return lerp(dp(28), dp(38), 1f - audioSelected); + float videoSelected = this.videoSelectedT.set(!this.audioSelected && !this.roundSelected); + return lerp(dp(28), dp(38), videoSelected); } private float getAudioHeight() { @@ -474,11 +666,18 @@ private float getAudioHeight() { return lerp(dp(28), dp(38), audioSelected); } + private float getRoundHeight() { + if (!hasRound) + return 0; + float roundSelected = this.roundSelectedT.set(this.roundSelected); + return lerp(dp(28), dp(38), roundSelected); + } + private long lastTime; private long pressTime; private float lastX; private int pressHandle = -1; - private boolean pressVideo = true; + private int pressType = -1; private boolean draggingProgress, dragged; private boolean hadDragChange; private VelocityTracker velocityTracker; @@ -487,15 +686,12 @@ private float getAudioHeight() { @Override public boolean onTouchEvent(MotionEvent event) { - if (!hasVideo && !hasAudio) { + if (!hasVideo && !hasAudio && !hasRound) { return false; } - if (hasVideo && !hasAudio && event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < h - py - getVideoHeight() - py) { - return false; - } - - if (hasAudio && !hasVideo && event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < h - py - getAudioHeight() - py) { + final float top = h - py - py - (hasVideo ? getVideoHeight() + dp(4) : 0) - (hasAudio ? getAudioHeight() + dp(4) : 0) - (hasRound ? getRoundHeight() + dp(4) : 0); + if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < top) { return false; } @@ -507,7 +703,26 @@ public boolean onTouchEvent(MotionEvent event) { } scroller.abortAnimation(); pressHandle = detectHandle(event); - pressVideo = !hasAudio || event.getY() > h - py - getVideoHeight() - (hasVideo ? dp(4) : 0); + pressType = -1; + int y = h - py; + if (pressType == -1 && hasVideo) { + if (event.getY() < y && event.getY() > y - getVideoHeight() - dp(2)) { + pressType = 0; + } + y -= getVideoHeight() + dp(4); + } + if (pressType == -1 && hasRound) { + if (event.getY() < y && event.getY() > y - getRoundHeight() - dp(2)) { + pressType = 1; + } + y -= getRoundHeight() + dp(4); + } + if (pressType == -1 && hasAudio) { + if (event.getY() < y && event.getY() > y - getAudioHeight() - dp(2)) { + pressType = 2; + } + y -= getAudioHeight() + dp(4); + } pressTime = System.currentTimeMillis(); draggingProgress = pressHandle == HANDLE_PROGRESS || pressHandle == -1 || pressHandle == HANDLE_VIDEO_SCROLL; hadDragChange = false; @@ -582,13 +797,15 @@ public boolean onTouchEvent(MotionEvent event) { if (pressHandle == HANDLE_AUDIO_LEFT) { float maxValue = audioRight - minAudioSelect() / (float) audioDuration; float minValue = Math.max(0, scroll - audioOffset) / (float) audioDuration; - if (!hasVideo) { + if (!hasVideo && !hasRound) { minValue = Math.max(minValue, audioRight - MAX_SELECT_DURATION / (float) audioDuration); if (!hadDragChange && d < 0 && audioLeft <= (audioRight - MAX_SELECT_DURATION / (float) audioDuration)) { pressHandle = HANDLE_AUDIO_REGION; } - } else { + } else if (hasVideo) { minValue = Math.max(minValue, (videoLeft * videoDuration + scroll - audioOffset) / (float) audioDuration); + } else if (hasRound) { + minValue = Math.max(minValue, (roundLeft * roundDuration + scroll - audioOffset) / (float) audioDuration); } float wasAudioLeft = audioLeft; audioLeft = Utilities.clamp(audioLeft + d, maxValue, minValue); @@ -604,13 +821,15 @@ public boolean onTouchEvent(MotionEvent event) { } else if (pressHandle == HANDLE_AUDIO_RIGHT) { float maxValue = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); float minValue = audioLeft + minAudioSelect() / (float) audioDuration; - if (!hasVideo) { + if (!hasVideo && !hasRound) { maxValue = Math.min(maxValue, audioLeft + MAX_SELECT_DURATION / (float) audioDuration); if (!hadDragChange && d > 0 && audioRight >= (audioLeft + MAX_SELECT_DURATION / (float) audioDuration)) { pressHandle = HANDLE_AUDIO_REGION; } - } else { + } else if (hasVideo) { maxValue = Math.min(maxValue, (videoRight * videoDuration + scroll - audioOffset) / (float) audioDuration); + } else if (hasRound) { + maxValue = Math.min(maxValue, (roundRight * roundDuration + scroll - audioOffset) / (float) audioDuration); } float wasAudioRight = audioRight; audioRight = Utilities.clamp(audioRight + d, maxValue, minValue); @@ -625,9 +844,9 @@ public boolean onTouchEvent(MotionEvent event) { float minLeft = Math.max(0, scroll - audioOffset) / (float) audioDuration; float maxRight = Math.min(1, Math.max(0, scroll - audioOffset + videoScrollDuration) / (float) audioDuration); if (d > 0) { - d = Math.min(maxRight - audioRight, d); + d = Math.min(Math.max(0, maxRight - audioRight), d); } else { - d = Math.max(minLeft - audioLeft, d); + d = Math.max(Math.min(0, minLeft - audioLeft), d); } audioLeft += d; audioRight += d; @@ -641,7 +860,7 @@ public boolean onTouchEvent(MotionEvent event) { delegate.onProgressDragChange(true); } } - if (!hasVideo) { + if (!hasVideo && !hasRound) { progress = (long) (audioLeft * audioDuration); if (delegate != null) { delegate.onProgressDragChange(true); @@ -651,11 +870,90 @@ public boolean onTouchEvent(MotionEvent event) { invalidate(); dragged = true; draggingProgress = false; + } else if (pressHandle == HANDLE_ROUND_LEFT || pressHandle == HANDLE_ROUND_RIGHT || pressHandle == HANDLE_ROUND_REGION) { + float d = Δx / sw * (videoScrollDuration / (float) roundDuration); + if (pressHandle == HANDLE_ROUND_LEFT) { + float maxValue = roundRight - minAudioSelect() / (float) roundDuration; + float minValue = Math.max(0, scroll - roundOffset) / (float) roundDuration; + if (!hasVideo) { + minValue = Math.max(minValue, roundRight - MAX_SELECT_DURATION / (float) roundDuration); + if (!hadDragChange && d < 0 && roundLeft <= (roundRight - MAX_SELECT_DURATION / (float) roundDuration)) { + pressHandle = HANDLE_AUDIO_REGION; + } + } else { + minValue = Math.max(minValue, (videoLeft * videoDuration + scroll - roundOffset) / (float) roundDuration); + } + float wasAudioLeft = roundLeft; + roundLeft = Utilities.clamp(roundLeft + d, maxValue, minValue); + if (Math.abs(wasAudioLeft - roundLeft) > 0.01f) { + hadDragChange = true; + } + if (delegate != null) { + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + } + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + } + } else if (pressHandle == HANDLE_ROUND_RIGHT) { + float maxValue = Math.min(1, Math.max(0, scroll - roundOffset + videoScrollDuration) / (float) roundDuration); + float minValue = roundLeft + minAudioSelect() / (float) roundDuration; + if (!hasVideo) { + maxValue = Math.min(maxValue, roundLeft + MAX_SELECT_DURATION / (float) roundDuration); + if (!hadDragChange && d > 0 && roundRight >= (roundLeft + MAX_SELECT_DURATION / (float) roundDuration)) { + pressHandle = HANDLE_AUDIO_REGION; + } + } else { + maxValue = Math.min(maxValue, (videoRight * videoDuration + scroll - roundOffset) / (float) roundDuration); + } + float wasAudioRight = roundRight; + roundRight = Utilities.clamp(roundRight + d, maxValue, minValue); + if (Math.abs(wasAudioRight - roundRight) > 0.01f) { + hadDragChange = true; + } + if (delegate != null) { + delegate.onRoundRightChange(roundRight); + } + } + if (pressHandle == HANDLE_ROUND_REGION) { + float minLeft = Math.max(0, scroll - roundOffset) / (float) roundDuration; + float maxRight = Math.min(1, Math.max(0, scroll - roundOffset + videoScrollDuration) / (float) roundDuration); + if (d > 0) { + d = Math.min(maxRight - roundRight, d); + } else { + d = Math.max(minLeft - roundLeft, d); + } + roundLeft += d; + roundRight += d; + + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + delegate.onRoundRightChange(roundRight); + } + if (delegate != null) { + delegate.onProgressDragChange(true); + } + } + if (!hasVideo) { + progress = (long) (roundLeft * roundDuration); + if (delegate != null) { + delegate.onProgressDragChange(true); + delegate.onProgressChange(progress, false); + } + } + invalidate(); + dragged = true; + draggingProgress = false; } else if (pressHandle == HANDLE_AUDIO_SCROLL) { float d = Δx / sw * videoScrollDuration; moveAudioOffset(d); dragged = true; draggingProgress = false; + } else if (pressHandle == HANDLE_ROUND_SCROLL) { + float d = Δx / sw * videoScrollDuration; + moveRoundOffset(d); + dragged = true; + draggingProgress = false; } else if (draggingProgress) { setProgressAt(event.getX(), now - lastTime < 350); if (!dragged && delegate != null) { @@ -677,11 +975,33 @@ public boolean onTouchEvent(MotionEvent event) { boolean scrollStopped = true; if (event.getAction() == MotionEvent.ACTION_UP) { if (System.currentTimeMillis() - pressTime <= ViewConfiguration.getTapTimeout() && !dragged) { - if (!pressVideo && !audioSelected) { + if (pressType == 2 && !audioSelected) { audioSelected = true; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } invalidate(); - } else if (pressVideo && audioSelected) { + } else if (pressType == 1 && !roundSelected) { audioSelected = false; + roundSelected = true; + if (delegate != null) { + delegate.onRoundSelectChange(true); + } + invalidate(); + } else if (pressType != 2 && audioSelected) { + audioSelected = false; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } + invalidate(); + } else if (pressType != 1 && roundSelected) { + audioSelected = false; + roundSelected = false; + if (delegate != null) { + delegate.onRoundSelectChange(false); + } invalidate(); } else { long wasProgress = progress; @@ -714,6 +1034,9 @@ public boolean onTouchEvent(MotionEvent event) { if (hasVideo) { mx = (long) ((videoRight * videoDuration) - (0 * audioDuration)); mn = (long) ((videoLeft * videoDuration) - (1 * audioDuration)); + } else if (hasRound) { + mx = (long) ((roundRight * roundDuration) - (0 * audioDuration)); + mn = (long) ((roundLeft * roundDuration) - (1 * audioDuration)); } else { mx = 0; mn = (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION)); @@ -722,6 +1045,25 @@ public boolean onTouchEvent(MotionEvent event) { scroller.fling(wasScrollX = scrollX, 0, velocity, 0, (int) (px + ph + mn / (float) videoScrollDuration * sw), (int) (px + ph + mx / (float) videoScrollDuration * sw), 0, 0); scrollStopped = false; } + } else if ((pressHandle == HANDLE_ROUND_SCROLL || pressHandle == HANDLE_ROUND_REGION && !dragged) && roundSelected && velocityTracker != null) { + velocityTracker.computeCurrentVelocity(hasVideo ? 1000 : 1500); + final int velocity = (int) velocityTracker.getXVelocity(); + scrollingVideo = false; + if (Math.abs(velocity) > dp(100)) { + final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); + final int scrollX = (int) (px + ph + roundOffset / (float) videoScrollDuration * sw); + final long mx, mn; + if (hasVideo) { + mx = (long) ((videoRight * videoDuration) - (0 * roundDuration)); + mn = (long) ((videoLeft * videoDuration) - (1 * roundDuration)); + } else { + mx = 0; + mn = (long) -(roundDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION)); + } + scrolling = true; + scroller.fling(wasScrollX = scrollX, 0, velocity, 0, (int) (px + ph + mn / (float) videoScrollDuration * sw), (int) (px + ph + mx / (float) videoScrollDuration * sw), 0, 0); + scrollStopped = false; + } } } if (askExactSeek != null) { @@ -745,12 +1087,11 @@ public boolean onTouchEvent(MotionEvent event) { } private long minAudioSelect() { - return (long) Math.max(MIN_SELECT_DURATION, Math.min(hasVideo ? videoDuration : audioDuration, MAX_SELECT_DURATION) * 0.15f); + return (long) Math.max(MIN_SELECT_DURATION, Math.min(hasVideo ? videoDuration : (hasRound ? roundDuration : audioDuration), MAX_SELECT_DURATION) * 0.15f); } private void moveAudioOffset(final float d) { - final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); - if (!hasVideo) { + if (!hasVideo && !hasRound) { long wasAudioOffset = audioOffset; audioOffset = Utilities.clamp(audioOffset + (long) d, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); long rd = audioOffset - wasAudioOffset; @@ -761,14 +1102,17 @@ private void moveAudioOffset(final float d) { delegate.onAudioRightChange(audioRight); } } else if (audioSelected) { - long mx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); - final float wasDuration = Math.min(audioRight - audioLeft, (videoRight - videoLeft) * videoDuration / (float) audioDuration); + final float L = hasVideo ? videoLeft * videoDuration : roundLeft * roundDuration; + final float R = hasVideo ? videoRight * videoDuration : roundRight * roundDuration; + final float D = hasVideo ? (videoRight - videoLeft) * videoDuration : (roundRight - roundLeft) * roundDuration; + long mx = (long) (R - (audioRight * audioDuration)); + long mn = (long) (L - (audioLeft * audioDuration)); + final float wasDuration = Math.min(audioRight - audioLeft, D / (float) audioDuration); if (audioOffset + (long) d > mx) { - audioRight = Utilities.clamp((videoRight * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1, wasDuration); + audioRight = Utilities.clamp((R - audioOffset - (long) d) / (float) audioDuration, 1, wasDuration); audioLeft = Utilities.clamp(audioRight - wasDuration, 1, 0); - long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + long mmx = (long) (R - (audioRight * audioDuration)); + long mmn = (long) (L - (audioLeft * audioDuration)); if (mmx < mmn) { long t = mmx; mmx = mmn; @@ -780,10 +1124,10 @@ private void moveAudioOffset(final float d) { delegate.onAudioRightChange(audioRight); } } else if (audioOffset + (long) d < mn) { - audioLeft = Utilities.clamp((videoLeft * videoDuration - audioOffset - (long) d) / (float) audioDuration, 1 - wasDuration, 0); + audioLeft = Utilities.clamp((L - audioOffset - (long) d) / (float) audioDuration, 1 - wasDuration, 0); audioRight = Utilities.clamp(audioLeft + wasDuration, 1, 0); - long mmx = (long) ((videoRight * videoDuration) - (audioRight * audioDuration)); - long mmn = (long) ((videoLeft * videoDuration) - (audioLeft * audioDuration)); + long mmx = (long) (R - (audioRight * audioDuration)); + long mmn = (long) (L - (audioLeft * audioDuration)); if (mmx < mmn) { long t = mmx; mmx = mmn; @@ -810,6 +1154,8 @@ private void moveAudioOffset(final float d) { long progressToStart; if (hasVideo) { progressToStart = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else if (hasRound) { + progressToStart = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (roundRight * roundDuration), (long) (roundLeft * roundDuration)); } else { progressToStart = Utilities.clamp((long) (audioLeft * audioDuration), audioDuration, 0); } @@ -821,6 +1167,8 @@ private void moveAudioOffset(final float d) { } else if (dragged || scrolling) { if (hasVideo) { progress = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else if (hasRound) { + progress = Utilities.clamp(audioOffset + (long) (audioLeft * audioDuration), (long) (roundRight * videoDuration), (long) (roundLeft * videoDuration)); } else { progress = Utilities.clamp((long) (audioLeft * audioDuration), audioDuration, 0); } @@ -830,6 +1178,87 @@ private void moveAudioOffset(final float d) { } } + private void moveRoundOffset(final float d) { + if (!hasVideo) { + long wasAudioOffset = roundOffset; + roundOffset = Utilities.clamp(roundOffset + (long) d, 0, (long) -(roundDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); + long rd = roundOffset - wasAudioOffset; + roundLeft = Utilities.clamp(roundLeft - (float) rd / roundDuration, 1, 0); + roundRight = Utilities.clamp(roundRight - (float) rd / roundDuration, 1, 0); + if (delegate != null) { + delegate.onAudioLeftChange(roundLeft); + delegate.onAudioRightChange(roundRight); + } + } else if (roundSelected) { + long mx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + final float wasDuration = Math.min(roundRight - roundLeft, (videoRight - videoLeft) * videoDuration / (float) roundDuration); + if (roundOffset + (long) d > mx) { + roundRight = Utilities.clamp((videoRight * videoDuration - roundOffset - (long) d) / (float) roundDuration, 1, wasDuration); + roundLeft = Utilities.clamp(roundRight - wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + roundOffset = Utilities.clamp(roundOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundRightChange(roundRight); + } + } else if (roundOffset + (long) d < mn) { + roundLeft = Utilities.clamp((videoLeft * videoDuration - roundOffset - (long) d) / (float) roundDuration, 1 - wasDuration, 0); + roundRight = Utilities.clamp(roundLeft + wasDuration, 1, 0); + long mmx = (long) ((videoRight * videoDuration) - (roundRight * roundDuration)); + long mmn = (long) ((videoLeft * videoDuration) - (roundLeft * roundDuration)); + if (mmx < mmn) { + long t = mmx; + mmx = mmn; + mmn = t; + } + roundOffset = Utilities.clamp(roundOffset + (long) d, mmx, mmn); + if (delegate != null) { + delegate.onRoundLeftChange(roundLeft); + delegate.onRoundRightChange(roundRight); + } + } else { + roundOffset += (long) d; + } + } else { + roundOffset = Utilities.clamp(roundOffset + (long) d, (long) (getBaseDuration() - roundDuration * roundRight), (long) (-roundLeft * roundDuration)); + } + invalidate(); + if (delegate != null) { + delegate.onRoundOffsetChange(roundOffset + (long) (roundLeft * roundDuration)); + } + if (!dragged && delegate != null) { + delegate.onProgressDragChange(true); + + long progressToStart; + if (hasVideo) { + progressToStart = Utilities.clamp(roundOffset + (long) (roundLeft * roundDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else { + progressToStart = Utilities.clamp((long) (roundLeft * roundDuration), roundDuration, 0); + } + if (hasVideo && Math.abs(progress - progressToStart) > 400) { + loopProgressFrom = progress; + loopProgress.set(1, true); + } + delegate.onProgressChange(progress = progressToStart, false); + } else if (dragged || scrolling) { + if (hasVideo) { + progress = Utilities.clamp(roundOffset + (long) (roundLeft * roundDuration), (long) (videoRight * videoDuration), (long) (videoLeft * videoDuration)); + } else { + progress = Utilities.clamp((long) (roundLeft * roundDuration), roundDuration, 0); + } + if (delegate != null) { + delegate.onProgressChange(progress, false); + } + } + } + private int wasScrollX; @Override public void computeScroll() { @@ -837,15 +1266,12 @@ public void computeScroll() { int scrollX = scroller.getCurrX(); final long videoScrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); if (scrollingVideo) { - long wasScroll = scroll; scroll = (long) Math.max(0, ((scrollX - px - ph) / (float) sw * videoScrollDuration)); -// videoLeft = Utilities.clamp(videoLeft + (scroll - wasScroll) / (float) videoDuration, 1, 0); -// videoRight = Utilities.clamp(videoRight + (scroll - wasScroll) / (float) videoDuration, 1, 0); -// if (delegate != null) { -// delegate.onVideoLeftChange(videoLeft); -// delegate.onVideoRightChange(videoRight); -// } } else { + if (!audioSelected) { + scroller.abortAnimation(); + return; + } final float d = ((scrollX - px - ph) / (float) sw * videoScrollDuration) - ((wasScrollX - px - ph) / (float) sw * videoScrollDuration); moveAudioOffset(d); } @@ -958,6 +1384,7 @@ protected void dispatchDraw(Canvas canvas) { final long scrollDuration = Math.min(getBaseDuration(), MAX_SCROLL_DURATION); float videoHeight = 0; float videoT = hasVideo ? 1 : 0; + float videoSelected = videoSelectedT.set(!audioSelected && !roundSelected); // draw video thumbs if (hasVideo) { @@ -975,10 +1402,10 @@ protected void dispatchDraw(Canvas canvas) { final int fromFrame = (int) Math.max(0, Math.floor((videoStartX - px) / frameWidth)); final int toFrame = (int) Math.min(thumbs.count, Math.ceil(((videoEndX - videoStartX) - px) / frameWidth) + 1); - final int y = (int) (h - py - videoHeight); + final int y = (int) videoBounds.top; boolean allLoaded = thumbs.frames.size() >= toFrame; - boolean fullyCovered = allLoaded; + 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); @@ -1029,16 +1456,103 @@ protected void dispatchDraw(Canvas canvas) { canvas.restore(); } + final float p = dp(4); + float roundT = this.roundT.set(hasRound); + float roundSelected = this.roundSelectedT.set(hasRound && this.roundSelected); + final float roundHeight = getRoundHeight() * roundT; + if (roundT > 0) { + float left, right; + if (hasVideo) { + left = px + ph + (roundOffset - scroll + lerp(roundLeft, 0, roundSelected) * roundDuration) / (float) scrollDuration * sw; + right = px + ph + (roundOffset - scroll + lerp(roundRight, 1, roundSelected) * roundDuration) / (float) scrollDuration * sw; + } else { + left = px + ph + (roundOffset - scroll) / (float) scrollDuration * sw; + right = px + ph + (roundOffset - scroll + roundDuration) / (float) scrollDuration * sw; + } + + final float bottom = h - py - videoHeight - p * videoT; + roundBounds.set(left - ph, bottom - roundHeight, right + ph, bottom); + roundClipPath.rewind(); + roundClipPath.addRoundRect(roundBounds, dp(8), dp(8), Path.Direction.CW); + canvas.save(); + canvas.clipPath(roundClipPath); + if (roundThumbs != null) { + final float roundStartX = (roundDuration <= 0 ? 0 : px + ph + (roundOffset - scroll) / (float) scrollDuration * sw) - ph; + final float roundEndX = (roundDuration <= 0 ? 0 : px + ph + (roundOffset + roundDuration - scroll) / (float) scrollDuration * sw) + ph; + + float x = roundStartX; + final int frameWidth = roundThumbs.getFrameWidth(); + final float L; + if (hasVideo) { + L = px + ph + (roundOffset - scroll) / (float) scrollDuration * sw; + } else { + L = px; + } + final int fromFrame = (int) Math.max(0, Math.floor((roundStartX - L) / frameWidth)); + final int toFrame = (int) Math.min(roundThumbs.count, Math.ceil((roundEndX - roundStartX) / frameWidth) + 1); + + final int y = (int) roundBounds.top; + + boolean allLoaded = roundThumbs.frames.size() >= toFrame; + boolean fullyCovered = allLoaded; + if (fullyCovered) { + for (int i = fromFrame; i < Math.min(roundThumbs.frames.size(), toFrame); ++i) { + VideoThumbsLoader.BitmapFrame frame = roundThumbs.frames.get(i); + if (frame.bitmap == null) { + fullyCovered = false; + break; + } + } + } + + if (!fullyCovered) { + if (blurPaint == null) { + canvas.drawColor(0x40000000); + } else { + canvas.drawRect(roundBounds, blurPaint); + canvas.drawColor(0x33000000); + } + } + + for (int i = fromFrame; i < Math.min(roundThumbs.frames.size(), toFrame); ++i) { + VideoThumbsLoader.BitmapFrame frame = roundThumbs.frames.get(i); + if (frame.bitmap != null) { + videoFramePaint.setAlpha((int) (0xFF * frame.getAlpha())); + canvas.drawBitmap(frame.bitmap, x, y - (int) ((frame.bitmap.getHeight() - roundHeight) / 2f), videoFramePaint); + } + x += frameWidth; + } + + if (!allLoaded) { + roundThumbs.load(); + } + } + selectedVideoClipPath.rewind(); + AndroidUtilities.rectTmp.set( + px + ph + (roundLeft * roundDuration - scroll + roundOffset) / (float) scrollDuration * sw - (roundLeft <= 0 ? ph : 0) - ph * (1f - roundSelected), + roundBounds.top, + px + ph + (roundRight * roundDuration - scroll + roundOffset) / (float) scrollDuration * sw + (roundRight >= 1 ? ph : 0) + ph * (1f - roundSelected), + roundBounds.bottom + ); + selectedVideoClipPath.addRoundRect( + AndroidUtilities.rectTmp, + selectedVideoRadii, + Path.Direction.CW + ); + canvas.clipPath(selectedVideoClipPath, Region.Op.DIFFERENCE); + canvas.drawColor(0x50000000); + canvas.restore(); + } + // draw audio float audioT = this.audioT.set(hasAudio); float audioSelected = this.audioSelectedT.set(hasAudio && this.audioSelected); - final float p = dp(4); final float audioHeight = getAudioHeight() * audioT; if (audioT > 0) { final Paint audioBlurPaint = audioBlur.getPaint(audioT); canvas.save(); float left, right; - if (hasVideo) { + if (hasVideo || hasRound) { left = px + ph + (audioOffset - scroll + lerp(audioLeft, 0, audioSelected) * audioDuration) / (float) scrollDuration * sw; right = px + ph + (audioOffset - scroll + lerp(audioRight, 1, audioSelected) * audioDuration) / (float) scrollDuration * sw; } else { @@ -1046,7 +1560,7 @@ protected void dispatchDraw(Canvas canvas) { right = px + ph + (audioOffset - scroll + audioDuration) / (float) scrollDuration * sw; } - final float bottom = h - py - videoHeight - p * videoT; + final float bottom = h - py - videoHeight - p * videoT - roundHeight - p * roundT; audioBounds.set(left - ph, bottom - audioHeight, right + ph, bottom); audioClipPath.rewind(); audioClipPath.addRoundRect(audioBounds, dp(8), dp(8), Path.Direction.CW); @@ -1128,16 +1642,31 @@ protected void dispatchDraw(Canvas canvas) { } // draw region - final float regionTop = lerp(h - py - videoHeight, h - py - videoHeight - p * videoT - audioHeight, hasVideo ? audioSelected : 1); - final float regionBottom = lerp(h - py, h - py - videoHeight - p * videoT, audioSelected); - final float left = lerp(videoLeft * videoDuration, audioOffset + audioLeft * audioDuration, hasVideo ? audioSelected : 1); - final float right = lerp(videoRight * videoDuration, audioOffset + audioRight * audioDuration, hasVideo ? audioSelected : 1); + final float audio = audioT * (hasVideo || hasRound ? audioSelected : 1); + final float round = roundT * (hasVideo || hasAudio ? roundSelected : 1); + final float video = videoSelected; + float regionTop = 0; + regionTop += (h - py - videoHeight - p * videoT - roundHeight - p * roundT - audioHeight) * audio; + regionTop += (h - py - videoHeight - p * videoT - roundHeight) * round; + regionTop += (h - py - videoHeight) * video; + float regionBottom = 0; + regionBottom += (h - py - videoHeight - p * videoT - roundHeight - p * roundT) * audio; + regionBottom += (h - py - videoHeight - p * videoT) * round; + regionBottom += (h - py) * video; + float left = 0; + left += (audioOffset + audioLeft * audioDuration) * audio; + left += (roundOffset + roundLeft * roundDuration) * round; + left += (videoLeft * videoDuration) * video; + float right = 0; + right += (audioOffset + audioRight * audioDuration) * audio; + right += (roundOffset + roundRight * roundDuration) * round; + right += (videoRight * videoDuration) * video; float leftX = px + ph + (left - scroll) / (float) scrollDuration * sw; float rightX = px + ph + (right - scroll) / (float) scrollDuration * sw; - float progressAlpha = (hasAudio && !hasVideo ? audioT : videoT); - if (audioT > 0. || videoT > 0.) { - drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, (hasVideo ? 1 : lerp(.6f, 1f, audioSelected) * audioT) * progressAlpha); - if (hasVideo && hasAudio && audioSelected > 0) { + float progressAlpha = (hasAudio && !hasVideo ? audioT : Math.max(videoT, roundT)); + if (audioT > 0. || roundT > 0. || videoT > 0.) { + drawRegion(canvas, blurPaint, regionTop, regionBottom, leftX, rightX, (hasVideo || hasRound ? 1 : lerp(.6f, 1f, audioSelected) * audioT) * progressAlpha); + if (hasVideo && (hasAudio || hasRound) && (audioSelected > 0 || roundSelected > 0)) { drawRegion( canvas, blurPaint, @@ -1151,10 +1680,20 @@ protected void dispatchDraw(Canvas canvas) { // draw progress float loopT = loopProgress.set(0); - final float y1 = h - py - videoHeight - (audioHeight + p * videoT) * audioT - dpf2(4.3f); + final float y1 = h - py - videoHeight - (audioHeight + p * Math.max(roundT, videoT)) * audioT - (roundHeight + p * videoT) * roundT - dpf2(4.3f); final float y2 = h - py + dpf2(4.3f); if (loopT > 0) { - drawProgress(canvas, y1, y2, loopProgressFrom != -1 ? loopProgressFrom : (long) (hasVideo ? videoDuration * videoRight : audioDuration * audioRight), loopT * progressAlpha); + final long end; + if (loopProgressFrom != -1) { + end = loopProgressFrom; + } else if (hasVideo) { + end = (long) (videoDuration * videoRight); + } else if (hasRound) { + end = (long) (roundDuration * roundRight); + } else { + end = (long) (audioDuration * audioRight); + } + drawProgress(canvas, y1, y2, end, loopT * progressAlpha); } drawProgress(canvas, y1, y2, progress, (1f - loopT) * progressAlpha); } @@ -1195,7 +1734,9 @@ protected void dispatchDraw(Canvas canvas) { long wasOffset = audioOffset; if (this.audioSelected && hasVideo) { audioOffset = Utilities.clamp(audioOffset - direction * Δd, (long) ((videoRight * videoDuration) - (audioLeft * audioDuration)), (long) ((videoLeft * videoDuration) - (audioRight * audioDuration))); - } else { + } else if (this.roundSelected && hasRound) { + audioOffset = Utilities.clamp(audioOffset - direction * Δd, (long) ((roundRight * roundDuration) - (audioLeft * audioDuration)), (long) ((roundLeft * roundDuration) - (audioRight * audioDuration))); + } else{ audioOffset = Utilities.clamp(audioOffset - direction * Δd, 0, (long) -(audioDuration - Math.min(getBaseDuration(), MAX_SCROLL_DURATION))); } float d = -(audioOffset - wasOffset) / (float) audioDuration; @@ -1284,6 +1825,10 @@ private void drawProgress(Canvas canvas, float y1, float y2, long progress, floa private int sw; private int w, h, ph, px, py; + public static int heightDp() { + return 5 + 38 + 4 + 28 + 4 + 28 + 5; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { audioAuthorPaint.setTextSize(dp(12)); @@ -1291,7 +1836,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { waveformRadii[0] = waveformRadii[1] = waveformRadii[2] = waveformRadii[3] = dp(2); waveformRadii[4] = waveformRadii[5] = waveformRadii[6] = waveformRadii[7] = 0; setPadding(px = dp(12), py = dp(5), dp(12), dp(5)); - setMeasuredDimension(w = MeasureSpec.getSize(widthMeasureSpec), h = dp(80)); + setMeasuredDimension(w = MeasureSpec.getSize(widthMeasureSpec), h = dp(heightDp())); ph = dp(10); sw = w - 2 * ph - 2 * px; if (videoPath != null && this.thumbs == null) { @@ -1313,10 +1858,16 @@ private class VideoThumbsLoader { private final int frameWidth; private final int frameHeight; + private final boolean isRound; private boolean destroyed; - public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { + public VideoThumbsLoader(boolean isRound, String path, int uiWidth, int uiHeight, Long overrideDuration) { + this(isRound, path, uiWidth, uiHeight, overrideDuration, MAX_SCROLL_DURATION); + } + + 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; @@ -1349,6 +1900,9 @@ public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { metadataRetriever = null; FileLog.e(e); } + if (overrideDuration != null) { + this.duration = duration = overrideDuration; + } float aspectRatio = 1; if (width != 0 && height != 0) { aspectRatio = width / (float) height; @@ -1356,7 +1910,7 @@ public VideoThumbsLoader(String path, int uiWidth, int uiHeight) { aspectRatio = Utilities.clamp(aspectRatio, 4 / 3f, 9f / 16f); frameHeight = Math.max(1, uiHeight); frameWidth = Math.max(1, (int) Math.ceil(uiHeight * aspectRatio)); - final float uiScrollWidth = Math.max(duration, MAX_SCROLL_DURATION) / (float) MAX_SCROLL_DURATION * uiWidth; + final float uiScrollWidth = Math.max(duration, maxDuration) / (float) maxDuration * uiWidth; count = (int) Math.ceil(uiScrollWidth / frameWidth); frameIterator = (long) (duration / (float) count); nextFrame = -frameIterator; @@ -1402,6 +1956,7 @@ public void load() { private final Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + private Path clipPath; private void retrieveFrame() { if (metadataRetriever == null) { return; @@ -1421,6 +1976,14 @@ private void retrieveFrame() { (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; @@ -1516,7 +2079,7 @@ public AudioWaveformLoader(String path, int uiWidth) { FileLog.e(e); } - final float videoScrollWidth = Math.min(hasVideo ? videoDuration : duration * 1000, MAX_SCROLL_DURATION); + final float videoScrollWidth = Math.min(hasVideo ? videoDuration : (hasRound ? roundDuration : duration * 1000), MAX_SCROLL_DURATION); final float uiScrollWidth = (duration * 1000) / videoScrollWidth * uiWidth; final int sampleWidth = Math.round(dpf2(3.3333f)); count = Math.round(uiScrollWidth / sampleWidth); @@ -1697,4 +2260,8 @@ public int getCount() { return count; } } + + public int getContentHeight() { + return (int) (py + (hasVideo ? getVideoHeight() + dp(4) : 0) + (hasRound ? getRoundHeight() + dp(4) : 0) + (hasAudio ? getAudioHeight() + dp(4) : 0) + py); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java b/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java index 9fa7630ba5..b1f5f1190a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SuggestUserPhotoView.java @@ -28,7 +28,7 @@ public class SuggestUserPhotoView extends View { public SuggestUserPhotoView(Context context) { super(context); - avatarDrawable.setInfo(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser()); + avatarDrawable.setInfo(UserConfig.selectedAccount, UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser()); currentPhoto.setForUserOrChat(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(), avatarDrawable); newPhoto.setForUserOrChat(UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(), avatarDrawable); arrowDrawable = ContextCompat.getDrawable(context, R.drawable.msg_arrow_avatar); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index 717b8cacf3..600e9f4363 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -2206,7 +2206,7 @@ public boolean onInterceptTouchEvent(MotionEvent e) { view = new AppIconsSelectorCell(mContext, ThemeActivity.this, currentAccount); break; case TYPE_CHOOSE_COLOR: - view = new PeerColorActivity.ChangeNameColorCell(false, mContext, getResourceProvider()); + view = new PeerColorActivity.ChangeNameColorCell(currentAccount, 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 d6b06b8437..edc2a6518f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -8,6 +8,9 @@ package org.telegram.ui; +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -22,14 +25,21 @@ import android.content.res.Configuration; import android.database.DataSetObserver; import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; @@ -38,10 +48,14 @@ 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.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; -import android.util.Log; +import android.util.SparseIntArray; +import android.util.StateSet; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; @@ -68,13 +82,16 @@ 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; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; @@ -87,10 +104,12 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.tgnet.ConnectionsManager; 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; @@ -100,7 +119,6 @@ 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; @@ -108,39 +126,68 @@ 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.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; import org.telegram.ui.Components.ShareAlert; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.UndoView; import org.telegram.ui.Components.WallpaperCheckBoxView; import org.telegram.ui.Components.WallpaperParallaxEffect; +import org.telegram.ui.Stories.recorder.PreviewView; +import org.telegram.ui.Stories.recorder.SliderView; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class ThemePreviewActivity extends BaseFragment implements DownloadController.FileDownloadProgressListener, NotificationCenter.NotificationCenterDelegate { + public final ThemeDelegate themeDelegate = new ThemeDelegate() { + @Override + public boolean isDark() { + if (onSwitchDayNightDelegate != null) { + return onSwitchDayNightDelegate.isDark(); + } + return super.isDark(); + } + }; + + @Override + public void setResourceProvider(Theme.ResourcesProvider resourceProvider) { + themeDelegate.parentProvider = resourceProvider; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return themeDelegate; + } + public static final int SCREEN_TYPE_PREVIEW = 0; public static final int SCREEN_TYPE_ACCENT_COLOR = 1; public static final int SCREEN_TYPE_CHANGE_BACKGROUND = 2; private static final int OPTION_DAY_NIGHT = 6; private static final int OPTION_PHOTO_EDIT = 7; - private static final int BRIGHTNESS_CONTROL_HEIGHT = 88; private final int screenType; private Scroller scroller; @@ -263,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; @@ -276,8 +324,8 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private Bitmap originalBitmap; private float parallaxScale = 1.0f; - private TextView bottomOverlayChatText; - private RadialProgressView buttonProgressView; + private BlurButton applyButton1; + private BlurButton applyButton2; private String loadingFile = null; private File loadingFileObject = null; @@ -299,16 +347,16 @@ public class ThemePreviewActivity extends BaseFragment implements DownloadContro private WallpaperActivityDelegate delegate; long dialogId; + boolean self = true; private boolean shouldShowDayNightIcon; private boolean shouldShowBrightnessControll; private RLottieDrawable sunDrawable; private ActionBarMenuItem dayNightItem; - private float changeDayNightViewProgress; - private ValueAnimator changeDayNightViewAnimator; - private HeaderCell dimmingHeaderCell; - private BrightnessControlCell brightnessControlCell; + private ValueAnimator changeDayNightViewAnimator2; + private FrameLayout dimmingSliderContainer; + private SliderView dimmingSlider; - GestureDetector2 gestureDetector2 = new GestureDetector2(new GestureDetector2.OnGestureListener() { + GestureDetector2 gestureDetector2 = new GestureDetector2(getContext(), new GestureDetector2.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { if (scroller != null) { @@ -338,6 +386,7 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d scroller.abortAnimation(); } currentScrollOffset = Utilities.clamp(currentScrollOffset + distanceX, maxScrollOffset, 0); + invalidateBlur(); backgroundImage.invalidate(); return true; } @@ -358,6 +407,21 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve } }); + 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; @@ -425,9 +489,14 @@ public boolean isDark() { } @Override - public void switchDayNight() { + public boolean supportsAnimation() { + return true; + } + + @Override + public void switchDayNight(boolean animated) { forceDark = !forceDark; - chatActivity.themeDelegate.setCurrentTheme(chatActivity.themeDelegate.getCurrentTheme(), chatActivity.themeDelegate.getCurrentWallpaper(), true, forceDark); + chatActivity.themeDelegate.setCurrentTheme(chatActivity.themeDelegate.getCurrentTheme(), chatActivity.themeDelegate.getCurrentWallpaper(), animated, forceDark); } }); chatActivity.presentFragment(wallpaperActivity); @@ -441,6 +510,7 @@ private void setCurrentServerWallpaper(MessageObject messageObject) { public void setDialogId(long dialogId) { this.dialogId = dialogId; + this.self = dialogId == 0 || dialogId == getUserConfig().getClientUserId(); } public void setOnSwitchDayNightDelegate(DayNightSwitchDelegate delegate) { @@ -448,7 +518,7 @@ public void setOnSwitchDayNightDelegate(DayNightSwitchDelegate delegate) { } public interface WallpaperActivityDelegate { - void didSetNewBackground(); + void didSetNewBackground(TLRPC.WallPaper wallpaper); } public ThemePreviewActivity(Object wallPaper, Bitmap bitmap) { @@ -576,7 +646,7 @@ public View createView(Context context) { } hintView.setBackgroundColor(0xea272f38, 0xffffffff); hintView.showForView(dayNightItem, true); - hintView.setExtraTranslationY(-AndroidUtilities.dp(14)); + hintView.setExtraTranslationY(-dp(14)); }, 2000); } @@ -647,7 +717,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { listView.setLayoutAnimation(null); listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); - listView.setPadding(0, 0, 0, AndroidUtilities.dp(screenType != SCREEN_TYPE_PREVIEW ? 12 : 0)); + listView.setPadding(0, 0, 0, dp(screenType != SCREEN_TYPE_PREVIEW ? 12 : 0)); listView.setOnItemClickListener((view, position) -> { }); @@ -656,12 +726,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { floatingButton = new ImageView(context); floatingButton.setScaleType(ImageView.ScaleType.CENTER); - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_chats_actionBackground), getThemedColor(Theme.key_chats_actionPressedBackground)); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(dp(56), getThemedColor(Theme.key_chats_actionBackground), getThemedColor(Theme.key_chats_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.SRC_IN)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); - combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + combinedDrawable.setIconSize(dp(56), dp(56)); drawable = combinedDrawable; } floatingButton.setBackgroundDrawable(drawable); @@ -669,14 +739,14 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { floatingButton.setImageResource(R.drawable.floating_pencil); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); - animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); - animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, dp(2), dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton, View.TRANSLATION_Z, dp(4), dp(2)).setDuration(200)); floatingButton.setStateListAnimator(animator); floatingButton.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + outline.setOval(0, 0, dp(56), dp(56)); } }); } @@ -718,17 +788,44 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView2.getLayoutParams(); layoutParams.topMargin = actionBarHeight; + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + } listView2.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize - layoutParams.bottomMargin, MeasureSpec.EXACTLY)); layoutParams = (FrameLayout.LayoutParams) backgroundImage.getLayoutParams(); layoutParams.topMargin = actionBarHeight; backgroundImage.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)); + if (dimmingSliderContainer != null) { + layoutParams = (FrameLayout.LayoutParams) dimmingSliderContainer.getLayoutParams(); + layoutParams.topMargin = actionBarHeight; + dimmingSliderContainer.measure( + MeasureSpec.makeMeasureSpec(dp(190 + 32), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(44 + 32), MeasureSpec.EXACTLY) + ); + } + if (bottomOverlayChat != null) { + bottomOverlayChat.setPadding(dp(12), dp(12), dp(12), dp(12) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + layoutParams = (FrameLayout.LayoutParams) bottomOverlayChat.getLayoutParams(); + layoutParams.height = dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); measureChildWithMargins(bottomOverlayChat, widthMeasureSpec, 0, heightMeasureSpec, 0); } + if (sheetDrawable != null) { + sheetDrawable.getPadding(AndroidUtilities.rectTmp2); + } for (int a = 0; a < patternLayout.length; a++) { if (patternLayout[a] != null) { + layoutParams = (FrameLayout.LayoutParams) patternLayout[a].getLayoutParams(); + layoutParams.height = dp(a == 0 ? (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 321 : 273) : 316); + if (insideBottomSheet()) { + layoutParams.height += AndroidUtilities.navigationBarHeight; + } + if (a == 0) { + layoutParams.height += dp(12) + AndroidUtilities.rectTmp2.top; + } + patternLayout[a].setPadding(0, a == 0 ? dp(12) + AndroidUtilities.rectTmp2.top : 0, 0, insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); measureChildWithMargins(patternLayout[a], widthMeasureSpec, 0, heightMeasureSpec, 0); } } @@ -860,47 +957,51 @@ protected void onSend(LongSparseArray dids, int count, TLRPC.TL_fo 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(); - - if (onSwitchDayNightDelegate.isDark() && shouldShowBrightnessControll) { - dimmingHeaderCell.setVisibility(View.VISIBLE); - brightnessControlCell.setVisibility(View.VISIBLE); - } - } - if (shouldShowBrightnessControll) { - 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(); - dimmingHeaderCell.setAlpha(progressToDarkTheme); - brightnessControlCell.setAlpha(progressToDarkTheme); - listView2.setTranslationY(-AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * progressToDarkTheme); - }); - changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (!onSwitchDayNightDelegate.isDark()) { - dimmingHeaderCell.setVisibility(View.GONE); - brightnessControlCell.setVisibility(View.GONE); + if (!onSwitchDayNightDelegate.supportsAnimation()) { + toggleTheme(); + } else { + onSwitchDayNightDelegate.switchDayNight(true); + sunDrawable.setPlayInDirectionOfCustomEndFrame(true); + if (isDark) { + sunDrawable.setCustomEndFrame(0); + } else { + sunDrawable.setCustomEndFrame(36); + } + 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(); } - }); - changeDayNightViewAnimator.setDuration(250); - changeDayNightViewAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - changeDayNightViewAnimator.start(); + } } } else if (id == OPTION_PHOTO_EDIT) { if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { @@ -913,6 +1014,7 @@ public void onAnimationEnd(Animator animation) { photoEntry.thumbPath = null; ArrayList arrayList = new ArrayList<>(); arrayList.add(photoEntry); + PhotoViewer.getInstance().setParentActivity(getParentActivity()); PhotoViewer.getInstance().openPhotoForSelect(arrayList, 0, PhotoViewer.SELECT_TYPE_WALLPAPER, false, new PhotoViewer.EmptyPhotoViewerProvider() { @Override public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, boolean forceDocument) { @@ -939,6 +1041,11 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea updateBlurred(); } } + + @Override + public boolean allowCaption() { + return false; + } }, null); // AndroidUtilities.runOnUIThread(() -> { // PhotoViewer.getInstance().switchToEditMode(PhotoViewer.EDIT_MODE_FILTER); @@ -959,31 +1066,18 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea backgroundImage.setVisibility(View.VISIBLE); backgroundImages[1].setVisibility(View.GONE); - if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { backgroundImage.getImageReceiver().setDelegate((imageReceiver, set, thumb, memCache) -> { if (!(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper)) { Drawable dr = imageReceiver.getDrawable(); if (set && dr != null) { - // if (!Theme.hasThemeKey(Theme.key_chat_serviceBackground) || backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { - Theme.applyChatServiceMessageColor(AndroidUtilities.calcDrawableColor(dr), dr); - // } - listView2.invalidateViews(); - if (backgroundButtonsContainer != null) { - for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { - backgroundButtonsContainer.getChildAt(a).invalidate(); - } - } - if (messagesButtonsContainer != null) { - for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { - messagesButtonsContainer.getChildAt(a).invalidate(); - } - } + themeDelegate.applyChatServiceMessageColor(AndroidUtilities.calcDrawableColor(dr), checkBlur(dr), dr, currentIntensity); if (!thumb && isBlurred && blurredBitmap == null) { backgroundImage.getImageReceiver().setCrossfadeWithOldImage(false); updateBlurred(); backgroundImage.getImageReceiver().setCrossfadeWithOldImage(true); } + invalidateBlur(); } } }); @@ -1007,10 +1101,10 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea } } if (dialogId == 0 && (BuildVars.DEBUG_PRIVATE_VERSION && Theme.getActiveTheme().getAccent(false) != null || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper && !Theme.DEFAULT_BACKGROUND_SLUG.equals(((WallpapersListActivity.ColorWallpaper) currentWallpaper).slug) || currentWallpaper instanceof TLRPC.TL_wallPaper)) { - menu2.addItem(5, R.drawable.msg_share_filled); + menu2.addItem(5, R.drawable.msg_header_share); } if (dialogId != 0 && shouldShowDayNightIcon) { - sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, AndroidUtilities.dp(28), AndroidUtilities.dp(28), true, null); + sunDrawable = new RLottieDrawable(R.raw.sun, "" + R.raw.sun, dp(28), dp(28), true, null); dayNightItem = menu2.addItem(OPTION_DAY_NIGHT, sunDrawable); sunDrawable.setPlayInDirectionOfCustomEndFrame(true); @@ -1062,8 +1156,8 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { Drawable dropDownDrawable = context.getResources().getDrawable(R.drawable.ic_arrow_drop_down).mutate(); dropDownDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultTitle), PorterDuff.Mode.MULTIPLY)); dropDown.setCompoundDrawablesWithIntrinsicBounds(null, null, dropDownDrawable, null); - dropDown.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - dropDown.setPadding(0, 0, AndroidUtilities.dp(10), 0); + dropDown.setCompoundDrawablePadding(dp(4)); + dropDown.setPadding(0, 0, dp(10), 0); dropDownContainer.addView(dropDown, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 0, 0, 1)); } else { String name = applyingTheme.info != null ? applyingTheme.info.title : applyingTheme.getName(); @@ -1098,7 +1192,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { nextPosition = p - 1; holder = listView2.findViewHolderForAdapterPosition(nextPosition); if (holder != null) { - imageReceiver.setImageY(-AndroidUtilities.dp(1000)); + imageReceiver.setImageY(-dp(1000)); imageReceiver.draw(canvas); return result; } @@ -1124,7 +1218,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { holder = listView2.findViewHolderForAdapterPosition(prevPosition); if (holder != null) { top = holder.itemView.getTop(); - if (y - AndroidUtilities.dp(48) < holder.itemView.getBottom()) { + if (y - dp(48) < holder.itemView.getBottom()) { tx = Math.min(holder.itemView.getTranslationX(), tx); } if (holder.itemView instanceof ChatMessageCell) { @@ -1141,14 +1235,14 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { } } } - if (y - AndroidUtilities.dp(48) < top) { - y = top + AndroidUtilities.dp(48); + if (y - dp(48) < top) { + y = top + dp(48); } if (tx != 0) { canvas.save(); canvas.translate(tx, 0); } - imageReceiver.setImageY(y - AndroidUtilities.dp(44)); + imageReceiver.setImageY(y - dp(44)); imageReceiver.draw(canvas); if (tx != 0) { canvas.restore(); @@ -1209,14 +1303,22 @@ public boolean onTouchEvent(MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { lastX = startX = e.getX(); lastY = startY = e.getY(); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + scrollingBackground = true; } else if (e.getAction() == MotionEvent.ACTION_MOVE) { if (!scrollingBackground && Math.abs(startX - e.getX()) > AndroidUtilities.touchSlop) { - getParent().requestDisallowInterceptTouchEvent(true); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } scrollingBackground = true; } } else if (e.getAction() == MotionEvent.ACTION_CANCEL || e.getAction() == MotionEvent.ACTION_UP) { scrollingBackground = false; - getParent().requestDisallowInterceptTouchEvent(false); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(false); + } } gestureDetector2.onTouchEvent(e); } @@ -1231,6 +1333,12 @@ private void checkMotionEvent(MotionEvent e) { wasScroll = false; } } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + invalidateBlur(); + } }; DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { @Override @@ -1243,11 +1351,11 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { listView2.setVerticalScrollBarEnabled(true); listView2.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4 + 48)); + listView2.setPadding(0, dp(4), 0, dp(12 + 48 + 12 + (!self && dialogId > 0 ? 48 + 10 : 0)) - 12 + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); } else if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(16)); + listView2.setPadding(0, dp(4), 0, dp(16)); } else { - listView2.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4)); + listView2.setPadding(0, dp(4), 0, dp(4)); } listView2.setClipToPadding(false); listView2.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)); @@ -1305,376 +1413,159 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (screenType == SCREEN_TYPE_ACCENT_COLOR || screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { + final boolean drawShadow = insideBottomSheet(); bottomOverlayChat = new FrameLayout(context) { - final Paint dividerPaint = new Paint(); - final Paint backgroundPaint = new Paint(); - + + private LinearGradient gradient; + private int gradientHeight; + private final Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + { gradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } + + private final ColorFilter colorFilter; + { + ColorMatrix colorMatrix = new ColorMatrix(); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.4f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.65f); + colorFilter = new ColorMatrixColorFilter(colorMatrix); + } + @Override protected void dispatchDraw(Canvas canvas) { - int offset = (int) (AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * (1f - progressToDarkTheme)); - int bottom = Theme.chat_composeShadowDrawable.getIntrinsicHeight(); - Theme.chat_composeShadowDrawable.setBounds(0, offset, getMeasuredWidth(), offset + bottom); - Theme.chat_composeShadowDrawable.draw(canvas); - backgroundPaint.setColor(getThemedColor(Theme.key_chat_messagePanelBackground)); - canvas.drawRect(0, offset + bottom, getMeasuredWidth(), getMeasuredHeight(), backgroundPaint); - if (shouldShowBrightnessControll) { - dividerPaint.setColor(getThemedColor(Theme.key_divider)); - dividerPaint.setAlpha((int) (dividerPaint.getAlpha() * progressToDarkTheme)); - int y = getMeasuredHeight() - AndroidUtilities.dp(53); - canvas.drawRect(0, y, getMeasuredWidth(), y + 1, dividerPaint); - } - canvas.save(); - canvas.clipRect(0, offset, getMeasuredWidth(), getMeasuredHeight()); - super.dispatchDraw(canvas); - canvas.restore(); - } - }; - bottomOverlayChat.setWillNotDraw(false); - bottomOverlayChat.setPadding(0, AndroidUtilities.dp(3), 0, 0); - page2.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51 + BRIGHTNESS_CONTROL_HEIGHT, Gravity.BOTTOM)); - - - bottomOverlayChatText = new TextView(context); - bottomOverlayChatText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - bottomOverlayChatText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - bottomOverlayChatText.setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); - if (dialogId != 0) { - bottomOverlayChatText.setText(LocaleController.getString("ApplyBackgroundForThisChat", R.string.ApplyBackgroundForThisChat)); - } else { - bottomOverlayChatText.setText(LocaleController.getString("SetBackground", R.string.SetBackground)); - } - FrameLayout textContainer = new FrameLayout(getContext()); - - buttonProgressView = new RadialProgressView(getContext()); - buttonProgressView.setSize(AndroidUtilities.dp(18)); - textContainer.addView(buttonProgressView, LayoutHelper.createFrame(28, 28, Gravity.CENTER)); - textContainer.setBackground(Theme.createSimpleSelectorRoundRectDrawable(0, Color.TRANSPARENT, ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_fieldOverlayText), (int) (0.3f * 255)))); - textContainer.addView(bottomOverlayChatText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); - bottomOverlayChat.addView(textContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.BOTTOM)); - textContainer.setOnClickListener(view -> { - boolean done; - boolean sameFile = false; - Theme.ThemeInfo theme = Theme.getActiveTheme(); - String originalFileName = theme.generateWallpaperName(null, isBlurred); - String fileName = isBlurred ? theme.generateWallpaperName(null, false) : originalFileName; - File toFile = new File(ApplicationLoader.getFilesDirFixed(), originalFileName); - if (currentWallpaper instanceof TLRPC.TL_wallPaper) { - if (originalBitmap != null) { - try { - FileOutputStream stream = new FileOutputStream(toFile); - originalBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Exception e) { - done = false; - FileLog.e(e); + if (drawShadow) { + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + final ColorFilter wasColorFilter = paint.getColorFilter(); + paint.setColorFilter(colorFilter); + float intensityDim = 1f; + if (backgroundImage != null && backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { + intensityDim = currentIntensity >= 0 ? 1f : .33f; } - } else { - ImageReceiver imageReceiver = backgroundImage.getImageReceiver(); - if (imageReceiver.hasNotThumb() || imageReceiver.hasStaticThumb()) { - Bitmap bitmap = imageReceiver.getBitmap(); - try { - FileOutputStream stream = new FileOutputStream(toFile); - bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } else { - done = false; + final int wasAlpha = paint.getAlpha(); + paint.setAlpha((int) (wasAlpha * intensityDim)); + canvas.drawRect(AndroidUtilities.rectTmp, paint); + paint.setAlpha(wasAlpha); + paint.setColorFilter(wasColorFilter); + + if (shouldShowBrightnessControll && dimAmount > 0) { + canvas.drawColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); } - } - if (!done) { - TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; - File f = FileLoader.getInstance(currentAccount).getPathToAttach(wallPaper.document, true); - try { - done = AndroidUtilities.copyFile(f, toFile); - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } - } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - if (selectedPattern != null) { - try { - WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - Bitmap bitmap = backgroundImage.getImageReceiver().getBitmap(); - @SuppressLint("DrawAllocation") - Bitmap dst = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(dst); - if (backgroundGradientColor2 != 0) { - - } else if (backgroundGradientColor1 != 0) { - GradientDrawable gradientDrawable = new GradientDrawable(BackgroundGradientDrawable.getGradientOrientation(backgroundRotation), new int[]{backgroundColor, backgroundGradientColor1}); - gradientDrawable.setBounds(0, 0, dst.getWidth(), dst.getHeight()); - gradientDrawable.draw(canvas); - } else { - canvas.drawColor(backgroundColor); - } - Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); - paint.setColorFilter(new PorterDuffColorFilter(patternColor, blendMode)); - paint.setAlpha((int) (255 * Math.abs(currentIntensity))); - canvas.drawBitmap(bitmap, 0, 0, paint); - - FileOutputStream stream = new FileOutputStream(toFile); - if (backgroundGradientColor2 != 0) { - dst.compress(Bitmap.CompressFormat.PNG, 100, stream); - } else { - dst.compress(Bitmap.CompressFormat.JPEG, 87, stream); - } - stream.close(); - done = true; - } catch (Throwable e) { - FileLog.e(e); - done = false; - } - } else { - done = true; - } - } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { - WallpapersListActivity.FileWallpaper wallpaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; - if (wallpaper.resId != 0 || Theme.THEME_BACKGROUND_SLUG.equals(wallpaper.slug)) { - done = true; - } else { - try { - File fromFile; - if (hasScrollingBackground && currentScrollOffset != defaultScrollOffset) { - Bitmap bitmap = Bitmap.createBitmap((int) croppedWidth, currentWallpaperBitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - float k = currentScrollOffset / (float) maxScrollOffset * (currentWallpaperBitmap.getWidth() - bitmap.getWidth()); - canvas.translate(-k, 0); - canvas.drawBitmap(currentWallpaperBitmap, 0, 0, null); - - wallpaper.path = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.random.nextInt() + ".jpg"); - FileOutputStream stream = new FileOutputStream(wallpaper.path); - bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - - stream.close(); - bitmap.recycle(); - - fromFile = wallpaper.path; - } else { - fromFile = wallpaper.originalPath != null ? wallpaper.originalPath : wallpaper.path; - } - if (sameFile = fromFile.equals(toFile)) { - done = true; - } else { - done = AndroidUtilities.copyFile(fromFile, toFile); - } - } catch (Exception e) { - done = false; - FileLog.e(e); + canvas.save(); + if (gradient == null || gradientHeight != getHeight()) { + gradient = new LinearGradient(0, 0, 0, gradientHeight = getHeight(), new int[]{0xffffffff, 0}, new float[]{0, 1f}, Shader.TileMode.CLAMP); + gradientPaint.setShader(gradient); } + canvas.drawRect(AndroidUtilities.rectTmp, gradientPaint); + canvas.restore(); + canvas.restore(); } - } else if (currentWallpaper instanceof MediaController.SearchImage) { - MediaController.SearchImage wallpaper = (MediaController.SearchImage) currentWallpaper; - File f; - if (wallpaper.photo != null) { - TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallpaper.photo.sizes, maxWallpaperSize, true); - f = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); - } else { - f = ImageLoader.getHttpFilePath(wallpaper.imageUrl, "jpg"); - } - try { - done = AndroidUtilities.copyFile(f, toFile); - } catch (Exception e) { - done = false; - FileLog.e(e); - } - } else { - done = false; - } - if (isBlurred) { - try { - File blurredFile = new File(ApplicationLoader.getFilesDirFixed(), fileName); - FileOutputStream stream = new FileOutputStream(blurredFile); - blurredBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); - stream.close(); - done = true; - } catch (Throwable e) { - FileLog.e(e); - done = false; - } + + super.dispatchDraw(canvas); } - String slug; - int rotation = 45; - int color = 0; - int gradientColor1 = 0; - int gradientColor2 = 0; - int gradientColor3 = 0; - File path = null; - if (currentWallpaper instanceof TLRPC.TL_wallPaper) { - TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; - slug = wallPaper.slug; - } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - if (Theme.DEFAULT_BACKGROUND_SLUG.equals(wallPaper.slug)) { - slug = Theme.DEFAULT_BACKGROUND_SLUG; - color = 0; - } else { - if (selectedPattern != null) { - slug = selectedPattern.slug; - } else { - slug = Theme.COLOR_BACKGROUND_SLUG; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child.getMeasuredWidth() > dp(420)) { + child.measure(MeasureSpec.makeMeasureSpec(dp(420), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY)); } - color = backgroundColor; - gradientColor1 = backgroundGradientColor1; - gradientColor2 = backgroundGradientColor2; - gradientColor3 = backgroundGradientColor3; - rotation = backgroundRotation; - } - } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { - WallpapersListActivity.FileWallpaper wallPaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; - slug = wallPaper.slug; - path = wallPaper.path; - } else if (currentWallpaper instanceof MediaController.SearchImage) { - MediaController.SearchImage wallPaper = (MediaController.SearchImage) currentWallpaper; - if (wallPaper.photo != null) { - TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallPaper.photo.sizes, maxWallpaperSize, true); - path = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); - } else { - path = ImageLoader.getHttpFilePath(wallPaper.imageUrl, "jpg"); } - slug = ""; - } else { - color = 0; - slug = Theme.DEFAULT_BACKGROUND_SLUG; - } - - Theme.OverrideWallpaperInfo wallpaperInfo = new Theme.OverrideWallpaperInfo(); - wallpaperInfo.fileName = fileName; - wallpaperInfo.originalFileName = originalFileName; - wallpaperInfo.slug = slug; - wallpaperInfo.isBlurred = isBlurred; - wallpaperInfo.isMotion = isMotion; - wallpaperInfo.color = color; - wallpaperInfo.gradientColor1 = gradientColor1; - wallpaperInfo.gradientColor2 = gradientColor2; - wallpaperInfo.gradientColor3 = gradientColor3; - wallpaperInfo.rotation = rotation; - if (shouldShowBrightnessControll && dimAmount >= 0) { - wallpaperInfo.intensity = dimAmount; - } else { - wallpaperInfo.intensity = currentIntensity; } - if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { - WallpapersListActivity.ColorWallpaper colorWallpaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; - String slugStr; - if (!Theme.COLOR_BACKGROUND_SLUG.equals(slug) && !Theme.THEME_BACKGROUND_SLUG.equals(slug) && !Theme.DEFAULT_BACKGROUND_SLUG.equals(slug)) { - slugStr = slug; - } else { - slugStr = null; - } - float intensity = colorWallpaper.intensity; - if (intensity < 0 && !Theme.getActiveTheme().isDark()) { - intensity *= -1; - } - if (colorWallpaper.parentWallpaper != null && colorWallpaper.color == color && - colorWallpaper.gradientColor1 == gradientColor1 && colorWallpaper.gradientColor2 == gradientColor2 && colorWallpaper.gradientColor3 == gradientColor3 && TextUtils.equals(colorWallpaper.slug, slugStr) && - colorWallpaper.gradientRotation == rotation && (selectedPattern == null || Math.abs(intensity - currentIntensity) < 0.001f)) { - wallpaperInfo.wallpaperId = colorWallpaper.parentWallpaper.id; - wallpaperInfo.accessHash = colorWallpaper.parentWallpaper.access_hash; - } - } - wallpaperInfo.dialogId = dialogId; - if (dialogId != 0) { - TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); - if (userFull != null) { - wallpaperInfo.prevUserWallpaper = userFull.wallpaper; - } + }; + bottomOverlayChat.setWillNotDraw(false); + bottomOverlayChat.setPadding(dp(12), dp(12), dp(12), dp(12) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); + page2.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 0, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL)); + + applyButton1 = new BlurButton(context); + ScaleStateListAnimator.apply(applyButton1, 0.033f, 1.2f); + updateApplyButton1(false); + applyButton1.setOnClickListener(view -> applyWallpaperBackground(false)); + + if (dialogId > 0 && !self && serverWallpaper == null) { + applyButton2 = new BlurButton(context); + ScaleStateListAnimator.apply(applyButton2, 0.033f, 1.2f); + TLRPC.User user = getMessagesController().getUser(dialogId); + SpannableStringBuilder text = new SpannableStringBuilder(""); + if (!getUserConfig().isPremium()) { + text.append("l "); + text.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock3), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - MessagesController.getInstance(currentAccount).saveWallpaperToServer(path, wallpaperInfo, slug != null && dialogId == 0, 0); - - boolean needFinishFragment = true; - if (done) { - if (dialogId != 0) { - needFinishFragment = false; - - if (path != null && getMessagesController().uploadingWallpaperInfo == wallpaperInfo) { - TLRPC.WallPaper wallPaper = new TLRPC.TL_wallPaper(); - wallPaper.settings = new TLRPC.TL_wallPaperSettings(); - wallPaper.settings.intensity = (int) (wallpaperInfo.intensity * 100); - wallPaper.settings.blur = wallpaperInfo.isBlurred; - wallPaper.settings.motion = wallpaperInfo.isMotion; - wallPaper.uploadingImage = path.getAbsolutePath(); - Bitmap bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - float s = Math.max(50 / (float) backgroundImage.getMeasuredWidth(), 50 / (float) backgroundImage.getMeasuredHeight()); - canvas.scale(s, s); - if (backgroundImage.getMeasuredHeight() > backgroundImage.getMeasuredWidth()) { - canvas.translate(0, -(backgroundImage.getMeasuredHeight() - backgroundImage.getMeasuredWidth()) / 2f); - } else { - canvas.translate(-(backgroundImage.getMeasuredWidth() - backgroundImage.getMeasuredHeight()) / 2f, 0); - } - float currentDim = dimAmount; - dimAmount = 0; - backgroundImage.draw(canvas); - dimAmount = currentDim; - Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); - wallPaper.stripedThumb = bitmap; - - createServiceMessageLocal(wallPaper); - - TLRPC.UserFull fullUser = getMessagesController().getUserFull(dialogId); - if (fullUser != null) { - fullUser.wallpaper = wallPaper; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, dialogId, fullUser); - } - } else { - ChatThemeController.getInstance(currentAccount).setWallpaperToUser(dialogId, null, wallpaperInfo, serverWallpaper, () -> { + text.append(LocaleController.formatString(R.string.ApplyWallpaperForMeAndPeer, UserObject.getUserName(user))); + applyButton2.setText(text); + try { + applyButton2.setText(Emoji.replaceEmoji(applyButton2.getText(), applyButton2.text.getFontMetricsInt(), false)); + } catch (Exception ignore) {} + applyButton2.setOnClickListener(view -> applyWallpaperBackground(true)); + bottomOverlayChat.addView(applyButton1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 48 + 10)); + bottomOverlayChat.addView(applyButton2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + } else { + bottomOverlayChat.addView(applyButton1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 0)); + } - }); - } - setupFinished = true; - if (delegate != null) { - delegate.didSetNewBackground(); - } - finishFragment(); - } else { - Theme.serviceMessageColorBackup = getThemedColor(Theme.key_chat_serviceBackground); - if (Theme.THEME_BACKGROUND_SLUG.equals(wallpaperInfo.slug)) { - wallpaperInfo = null; - } - Theme.getActiveTheme().setOverrideWallpaper(wallpaperInfo); - Theme.reloadWallpaper(true); - if (!sameFile) { - ImageLoader.getInstance().removeImage(ImageLoader.getHttpFileName(toFile.getAbsolutePath()) + "@100_100"); + if (shouldShowBrightnessControll) { + dimmingSliderContainer = new FrameLayout(getContext()) { + private final Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + @Override + protected void dispatchDraw(Canvas canvas) { + AndroidUtilities.rectTmp.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + final float r = dp(8); + + shadowPaint.setColor(0); + shadowPaint.setShadowLayer(dpf2(1), 0, dpf2(.33f), ColorUtils.setAlphaComponent(0xff000000, (int) (27 * dimmingSlider.getAlpha()))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, shadowPaint); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + final int wasAlpha1 = paint.getAlpha(); + paint.setAlpha((int) (wasAlpha1 * dimmingSlider.getAlpha())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, paint); + paint.setAlpha(wasAlpha1); + + if (shouldShowBrightnessControll && dimAmount > 0) { + dimPaint2.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint2); } - } - } - if (needFinishFragment) { - if (delegate != null) { - delegate.didSetNewBackground(); - } - finishFragment(); - } - }); - AndroidUtilities.updateViewVisibilityAnimated(buttonProgressView, false, 0.5f, false); - AndroidUtilities.updateViewVisibilityAnimated(bottomOverlayChatText, true, 0.8f, false); + dimPaint.setColor(0x1effffff); + dimPaint.setAlpha((int) (0x1e * dimmingSlider.getAlpha())); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); - if (shouldShowBrightnessControll) { - dimmingHeaderCell = new HeaderCell(getContext(), getResourceProvider()); - dimmingHeaderCell.setText(LocaleController.getString("BackgroundDimming", R.string.BackgroundDimming)); - brightnessControlCell = new BrightnessControlCell(getContext(), BrightnessControlCell.TYPE_WALLPAPER_DIM, getResourceProvider()) { + super.dispatchDraw(canvas); + } + }; + dimmingSliderContainer.setPadding(dp(16), dp(16), dp(16), dp(16)); + page2.addView(dimmingSliderContainer, LayoutHelper.createFrame(190 + 32, 44 + 32, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); + + dimmingSlider = new SliderView(getContext(), SliderView.TYPE_DIMMING) { @Override - protected void didChangedValue(float value) { - dimAmount = value; - backgroundImage.invalidate(); + public boolean dispatchTouchEvent(MotionEvent event) { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return super.dispatchTouchEvent(event); } }; - brightnessControlCell.setProgress(dimAmount); - bottomOverlayChat.addView(dimmingHeaderCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); - bottomOverlayChat.addView(brightnessControlCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, BRIGHTNESS_CONTROL_HEIGHT, Gravity.BOTTOM, 0, 0, 0, 56)); + dimmingSlider.setValue(dimAmount); + dimmingSlider.setMinMax(0, .90f); + dimmingSlider.setOnValueChange(value -> { + dimAmount = value; + backgroundImage.invalidate(); + invalidateBlur(); + }); + dimmingSliderContainer.addView(dimmingSlider); if (onSwitchDayNightDelegate != null) { - dimmingHeaderCell.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); - brightnessControlCell.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); - listView2.setTranslationY(-AndroidUtilities.dp(BRIGHTNESS_CONTROL_HEIGHT) * progressToDarkTheme); + dimmingSlider.setVisibility(onSwitchDayNightDelegate.isDark() ? View.VISIBLE : View.GONE); + dimmingSlider.setAlpha(onSwitchDayNightDelegate.isDark() ? 1f : 0f); + dimmingSlider.setValue(onSwitchDayNightDelegate.isDark() ? dimAmount : 0); } } } @@ -1685,9 +1576,9 @@ protected void didChangedValue(float value) { sheetDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhite), PorterDuff.Mode.MULTIPLY)); TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - textPaint.setTextSize(AndroidUtilities.dp(14)); + textPaint.setTextSize(dp(14)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - { + if (!(currentWallpaper instanceof WallpapersListActivity.EmojiWallpaper)) { int textsCount; if (screenType == SCREEN_TYPE_ACCENT_COLOR || currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { textsCount = 3; @@ -1730,10 +1621,10 @@ protected void didChangedValue(float value) { @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - Theme.applyServiceShaderMatrixForView(backgroundPlayAnimationView, backgroundImage); - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundPaint); + Theme.applyServiceShaderMatrixForView(backgroundPlayAnimationView, backgroundImage, themeDelegate); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackground)); if (Theme.hasGradientService()) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackgroundDarken)); } } }; @@ -1750,15 +1641,24 @@ protected void onDraw(Canvas canvas) { @Override public void onClick(View v) { - Drawable background = backgroundImage.getBackground(); backgroundPlayAnimationImageView.setRotation(rotation); rotation -= 45; backgroundPlayAnimationImageView.animate().rotationBy(-45).setDuration(300).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); - if (background instanceof MotionBackgroundDrawable) { - MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; - motionBackgroundDrawable.switchToNextPosition(); - } else { - onColorsRotate(); + if (backgroundImages[0] != null) { + Drawable background = backgroundImages[0].getBackground(); + if (background instanceof MotionBackgroundDrawable) { + MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; + motionBackgroundDrawable.switchToNextPosition(); + } else { + onColorsRotate(); + } + } + if (backgroundImages[1] != null) { + Drawable background = backgroundImages[1].getBackground(); + if (background instanceof MotionBackgroundDrawable) { + MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) background; + motionBackgroundDrawable.switchToNextPosition(); + } } } }); @@ -1771,7 +1671,7 @@ public void onClick(View v) { for (int a = 0; a < textsCount; a++) { final int num = a; - backgroundCheckBoxView[a] = new WallpaperCheckBoxView(context, screenType != SCREEN_TYPE_ACCENT_COLOR && !(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) || a != 0, backgroundImage, getResourceProvider()); + backgroundCheckBoxView[a] = new WallpaperCheckBoxView(context, screenType != SCREEN_TYPE_ACCENT_COLOR && !(currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) || a != 0, backgroundImage, themeDelegate); backgroundCheckBoxView[a].setBackgroundColor(backgroundColor); backgroundCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); @@ -1784,20 +1684,20 @@ public void onClick(View v) { } else { backgroundCheckBoxView[a].setChecked(a == 0 ? isBlurred : isMotion, false); } - int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); + int width = maxTextSize + dp(14 * 2 + 28); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.gravity = Gravity.CENTER; if (textsCount == 3) { if (a == 0 || a == 2) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } } else { if (a == 1) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } } backgroundButtonsContainer.addView(backgroundCheckBoxView[a], layoutParams); @@ -1886,10 +1786,10 @@ public void onClick(View v) { @Override protected void onDraw(Canvas canvas) { rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - Theme.applyServiceShaderMatrixForView(messagesPlayAnimationView, backgroundImage); - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundPaint); + Theme.applyServiceShaderMatrixForView(messagesPlayAnimationView, backgroundImage, themeDelegate); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackground)); if (Theme.hasGradientService()) { - canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, Theme.chat_actionBackgroundGradientDarkenPaint); + canvas.drawRoundRect(rect, getMeasuredHeight() / 2, getMeasuredHeight() / 2, themeDelegate.getPaint(Theme.key_paint_chatActionBackgroundDarken)); } } }; @@ -1948,19 +1848,19 @@ public void onClick(View v) { for (int a = 0; a < 2; a++) { final int num = a; - messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage, getResourceProvider()); + messagesCheckBoxView[a] = new WallpaperCheckBoxView(context, a == 0, backgroundImage, themeDelegate); messagesCheckBoxView[a].setText(texts[a], textSizes[a], maxTextSize); if (a == 0) { messagesCheckBoxView[a].setChecked(accent.myMessagesAnimated, false); } - int width = maxTextSize + AndroidUtilities.dp(14 * 2 + 28); + int width = maxTextSize + dp(14 * 2 + 28); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.gravity = Gravity.CENTER; if (a == 1) { - layoutParams.leftMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.leftMargin = width / 2 + dp(10); } else { - layoutParams.rightMargin = width / 2 + AndroidUtilities.dp(10); + layoutParams.rightMargin = width / 2 + dp(10); } messagesButtonsContainer.addView(messagesCheckBoxView[a], layoutParams); WallpaperCheckBoxView view = messagesCheckBoxView[a]; @@ -2007,10 +1907,15 @@ public void onDraw(Canvas canvas) { } else { layoutParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? 273 : 316, Gravity.LEFT | Gravity.BOTTOM); } + layoutParams.height = dp(a == 0 ? (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 321 : 273) : 316); + if (insideBottomSheet()) { + layoutParams.height += AndroidUtilities.navigationBarHeight; + } if (a == 0) { - layoutParams.height += AndroidUtilities.dp(12) + paddings.top; - patternLayout[a].setPadding(0, AndroidUtilities.dp(12) + paddings.top, 0, 0); + sheetDrawable.getPadding(AndroidUtilities.rectTmp2); + layoutParams.height += dp(12) + AndroidUtilities.rectTmp2.top; } + patternLayout[a].setPadding(0, a == 0 ? dp(12) + paddings.top : 0, 0, insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0); page2.addView(patternLayout[a], layoutParams); if (a == 1 || screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { @@ -2027,7 +1932,7 @@ public void onDraw(Canvas canvas) { } }; patternsButtonsContainer[a].setWillNotDraw(false); - patternsButtonsContainer[a].setPadding(0, AndroidUtilities.dp(3), 0, 0); + patternsButtonsContainer[a].setPadding(0, dp(3), 0, 0); patternsButtonsContainer[a].setClickable(true); patternLayout[a].addView(patternsButtonsContainer[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); @@ -2037,7 +1942,7 @@ public void onDraw(Canvas canvas) { patternsCancelButton[a].setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); patternsCancelButton[a].setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); patternsCancelButton[a].setGravity(Gravity.CENTER); - patternsCancelButton[a].setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + patternsCancelButton[a].setPadding(dp(21), 0, dp(21), 0); patternsCancelButton[a].setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 0)); patternsButtonsContainer[a].addView(patternsCancelButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); patternsCancelButton[a].setOnClickListener(v -> { @@ -2086,7 +1991,7 @@ public void onDraw(Canvas canvas) { patternsSaveButton[a].setTextColor(getThemedColor(Theme.key_chat_fieldOverlayText)); patternsSaveButton[a].setText(LocaleController.getString("ApplyTheme", R.string.ApplyTheme).toUpperCase()); patternsSaveButton[a].setGravity(Gravity.CENTER); - patternsSaveButton[a].setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + patternsSaveButton[a].setPadding(dp(21), 0, dp(21), 0); patternsSaveButton[a].setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 0)); patternsButtonsContainer[a].addView(patternsSaveButton[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.TOP)); patternsSaveButton[a].setOnClickListener(v -> { @@ -2110,7 +2015,7 @@ public void onDraw(Canvas canvas) { patternTitleView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); patternTitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); patternTitleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - patternTitleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(6), AndroidUtilities.dp(21), AndroidUtilities.dp(8)); + patternTitleView.setPadding(dp(21), dp(6), dp(21), dp(8)); patternTitleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); patternTitleView.setGravity(Gravity.CENTER_VERTICAL); @@ -2131,10 +2036,10 @@ public boolean onTouchEvent(MotionEvent event) { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); - outRect.left = AndroidUtilities.dp(12); + outRect.left = dp(12); outRect.bottom = outRect.top = 0; if (position == state.getItemCount() - 1) { - outRect.right = AndroidUtilities.dp(12); + outRect.right = dp(12); } } }); @@ -2152,7 +2057,7 @@ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, Recycle int left = view.getLeft(); int right = view.getRight(); - int extra = AndroidUtilities.dp(52); + int extra = dp(52); if (left - extra < 0) { patternsListView.smoothScrollBy(left - extra, 0); } else if (right + extra > patternsListView.getMeasuredWidth()) { @@ -2387,14 +2292,14 @@ public void unregisterDataSetObserver(DataSetObserver observer) { frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, screenType == SCREEN_TYPE_PREVIEW ? 48 : 0)); undoView = new UndoView(context, this); - undoView.setAdditionalTranslationY(AndroidUtilities.dp(51)); + undoView.setAdditionalTranslationY(dp(51)); frameLayout.addView(undoView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 8, 0, 8, 8)); if (screenType == SCREEN_TYPE_PREVIEW) { View shadow = new View(context); shadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM); - layoutParams.bottomMargin = AndroidUtilities.dp(48); + layoutParams.bottomMargin = dp(48); frameLayout.addView(shadow, layoutParams); saveButtonsContainer = new FrameLayout(context); @@ -2411,7 +2316,7 @@ protected void onDraw(Canvas canvas) { paint.setColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); for (int a = 0; a < 2; a++) { paint.setAlpha(a == selected ? 255 : 127); - canvas.drawCircle(AndroidUtilities.dp(3 + 15 * a), AndroidUtilities.dp(4), AndroidUtilities.dp(3), paint); + canvas.drawCircle(dp(3 + 15 * a), dp(4), dp(3), paint); } } }; @@ -2422,7 +2327,7 @@ protected void onDraw(Canvas canvas) { cancelButton.setTextColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); cancelButton.setGravity(Gravity.CENTER); cancelButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); - cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + cancelButton.setPadding(dp(29), 0, dp(29), 0); cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); saveButtonsContainer.addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); @@ -2433,7 +2338,7 @@ protected void onDraw(Canvas canvas) { doneButton.setTextColor(getButtonsColor(Theme.key_chat_fieldOverlayText)); doneButton.setGravity(Gravity.CENTER); doneButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x0f000000, 0)); - doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + doneButton.setPadding(dp(29), 0, dp(29), 0); doneButton.setText(LocaleController.getString("ApplyTheme", R.string.ApplyTheme).toUpperCase()); doneButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); saveButtonsContainer.addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); @@ -2487,11 +2392,18 @@ protected void onDraw(Canvas canvas) { if (parentLayout != null && parentLayout.getBottomSheet() != null) { parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } } return fragmentView; } + public boolean insideBottomSheet() { + return parentLayout != null && parentLayout.getBottomSheet() != null; + } + private void updateIntensity() { backgroundImage.getImageReceiver().setAlpha(Math.abs(currentIntensity)); backgroundImage.invalidate(); @@ -2510,11 +2422,393 @@ private void updateIntensity() { backgroundImage.getImageReceiver().setGradientBitmap(motionBackgroundDrawable.getBitmap()); } } + themeDelegate.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); + 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 showProgress() { - AndroidUtilities.updateViewVisibilityAnimated(buttonProgressView, true, 0.5f, true); - AndroidUtilities.updateViewVisibilityAnimated(bottomOverlayChatText, false, 0.8f, true); + 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; + Theme.ThemeInfo theme = Theme.getActiveTheme(); + String originalFileName = theme.generateWallpaperName(null, isBlurred); + String fileName = isBlurred ? theme.generateWallpaperName(null, false) : originalFileName; + File toFile = new File(ApplicationLoader.getFilesDirFixed(), originalFileName); + if (currentWallpaper instanceof TLRPC.TL_wallPaper) { + if (originalBitmap != null) { + try { + FileOutputStream stream = new FileOutputStream(toFile); + originalBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + ImageReceiver imageReceiver = backgroundImage.getImageReceiver(); + if (imageReceiver.hasNotThumb() || imageReceiver.hasStaticThumb()) { + Bitmap bitmap = imageReceiver.getBitmap(); + try { + FileOutputStream stream = new FileOutputStream(toFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + done = false; + } + } + + if (!done) { + TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; + File f = FileLoader.getInstance(currentAccount).getPathToAttach(wallPaper.document, true); + try { + done = AndroidUtilities.copyFile(f, toFile); + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } + } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + if (selectedPattern != null) { + try { + WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; + Bitmap bitmap = backgroundImage.getImageReceiver().getBitmap(); + @SuppressLint("DrawAllocation") + Bitmap dst = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(dst); + if (backgroundGradientColor2 != 0) { + + } else if (backgroundGradientColor1 != 0) { + GradientDrawable gradientDrawable = new GradientDrawable(BackgroundGradientDrawable.getGradientOrientation(backgroundRotation), new int[]{backgroundColor, backgroundGradientColor1}); + gradientDrawable.setBounds(0, 0, dst.getWidth(), dst.getHeight()); + gradientDrawable.draw(canvas); + } else { + canvas.drawColor(backgroundColor); + } + Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); + paint.setColorFilter(new PorterDuffColorFilter(patternColor, blendMode)); + paint.setAlpha((int) (255 * Math.abs(currentIntensity))); + canvas.drawBitmap(bitmap, 0, 0, paint); + + FileOutputStream stream = new FileOutputStream(toFile); + if (backgroundGradientColor2 != 0) { + dst.compress(Bitmap.CompressFormat.PNG, 100, stream); + } else { + dst.compress(Bitmap.CompressFormat.JPEG, 87, stream); + } + stream.close(); + done = true; + } catch (Throwable e) { + FileLog.e(e); + done = false; + } + } else { + done = true; + } + } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { + WallpapersListActivity.FileWallpaper wallpaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; + if (wallpaper.resId != 0 || Theme.THEME_BACKGROUND_SLUG.equals(wallpaper.slug)) { + done = true; + } else { + try { + File fromFile; + if (hasScrollingBackground && currentScrollOffset != defaultScrollOffset) { + Bitmap bitmap = Bitmap.createBitmap((int) croppedWidth, currentWallpaperBitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + float k = currentScrollOffset / (float) maxScrollOffset * (currentWallpaperBitmap.getWidth() - bitmap.getWidth()); + canvas.translate(-k, 0); + canvas.drawBitmap(currentWallpaperBitmap, 0, 0, null); + + wallpaper.path = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.random.nextInt() + ".jpg"); + FileOutputStream stream = new FileOutputStream(wallpaper.path); + bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + + stream.close(); + bitmap.recycle(); + + fromFile = wallpaper.path; + } else { + fromFile = wallpaper.originalPath != null ? wallpaper.originalPath : wallpaper.path; + } + if (sameFile = fromFile.equals(toFile)) { + done = true; + } else { + done = AndroidUtilities.copyFile(fromFile, toFile); + } + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } + } else if (currentWallpaper instanceof MediaController.SearchImage) { + MediaController.SearchImage wallpaper = (MediaController.SearchImage) currentWallpaper; + File f; + if (wallpaper.photo != null) { + TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallpaper.photo.sizes, maxWallpaperSize, true); + f = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); + } else { + f = ImageLoader.getHttpFilePath(wallpaper.imageUrl, "jpg"); + } + try { + done = AndroidUtilities.copyFile(f, toFile); + } catch (Exception e) { + done = false; + FileLog.e(e); + } + } else { + done = false; + } + if (isBlurred) { + try { + File blurredFile = new File(ApplicationLoader.getFilesDirFixed(), fileName); + FileOutputStream stream = new FileOutputStream(blurredFile); + blurredBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); + stream.close(); + done = true; + } catch (Throwable e) { + FileLog.e(e); + done = false; + } + } + String slug; + int rotation = 45; + int color = 0; + int gradientColor1 = 0; + int gradientColor2 = 0; + int gradientColor3 = 0; + File path = null; + + TLRPC.WallPaper tlwallPaper = null; + if (currentWallpaper instanceof TLRPC.TL_wallPaper) { + 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)) { + slug = Theme.DEFAULT_BACKGROUND_SLUG; + color = 0; + } else { + if (selectedPattern != null) { + slug = selectedPattern.slug; + } else { + slug = Theme.COLOR_BACKGROUND_SLUG; + } + color = backgroundColor; + gradientColor1 = backgroundGradientColor1; + gradientColor2 = backgroundGradientColor2; + gradientColor3 = backgroundGradientColor3; + rotation = backgroundRotation; + } + } else if (currentWallpaper instanceof WallpapersListActivity.FileWallpaper) { + WallpapersListActivity.FileWallpaper wallPaper = (WallpapersListActivity.FileWallpaper) currentWallpaper; + slug = wallPaper.slug; + path = wallPaper.path; + } else if (currentWallpaper instanceof MediaController.SearchImage) { + MediaController.SearchImage wallPaper = (MediaController.SearchImage) currentWallpaper; + if (wallPaper.photo != null) { + TLRPC.PhotoSize image = FileLoader.getClosestPhotoSizeWithSize(wallPaper.photo.sizes, maxWallpaperSize, true); + path = FileLoader.getInstance(currentAccount).getPathToAttach(image, true); + } else { + path = ImageLoader.getHttpFilePath(wallPaper.imageUrl, "jpg"); + } + slug = ""; + } else { + color = 0; + slug = Theme.DEFAULT_BACKGROUND_SLUG; + } + + Theme.OverrideWallpaperInfo wallpaperInfo = new Theme.OverrideWallpaperInfo(); + wallpaperInfo.fileName = fileName; + wallpaperInfo.originalFileName = originalFileName; + wallpaperInfo.slug = slug; + wallpaperInfo.isBlurred = isBlurred; + wallpaperInfo.isMotion = isMotion; + wallpaperInfo.color = color; + wallpaperInfo.gradientColor1 = gradientColor1; + wallpaperInfo.gradientColor2 = gradientColor2; + wallpaperInfo.gradientColor3 = gradientColor3; + wallpaperInfo.rotation = rotation; + if (shouldShowBrightnessControll && dimAmount >= 0) { + wallpaperInfo.intensity = dimAmount; + } else { + wallpaperInfo.intensity = currentIntensity; + } + if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { + WallpapersListActivity.ColorWallpaper colorWallpaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; + String slugStr; + if (!Theme.COLOR_BACKGROUND_SLUG.equals(slug) && !Theme.THEME_BACKGROUND_SLUG.equals(slug) && !Theme.DEFAULT_BACKGROUND_SLUG.equals(slug)) { + slugStr = slug; + } else { + slugStr = null; + } + float intensity = colorWallpaper.intensity; + if (intensity < 0 && !Theme.getActiveTheme().isDark()) { + intensity *= -1; + } + if (colorWallpaper.parentWallpaper != null && colorWallpaper.color == color && + colorWallpaper.gradientColor1 == gradientColor1 && colorWallpaper.gradientColor2 == gradientColor2 && colorWallpaper.gradientColor3 == gradientColor3 && TextUtils.equals(colorWallpaper.slug, slugStr) && + colorWallpaper.gradientRotation == rotation && (selectedPattern == null || Math.abs(intensity - currentIntensity) < 0.001f)) { + wallpaperInfo.wallpaperId = colorWallpaper.parentWallpaper.id; + wallpaperInfo.accessHash = colorWallpaper.parentWallpaper.access_hash; + } + } + wallpaperInfo.dialogId = dialogId; + if (dialogId != 0) { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + wallpaperInfo.prevUserWallpaper = userFull.wallpaper; + } + } + wallpaperInfo.forBoth = forBoth; + MessagesController.getInstance(currentAccount).saveWallpaperToServer(path, wallpaperInfo, slug != null && dialogId == 0, 0); + + boolean needFinishFragment = true; + if (done) { + if (dialogId != 0) { + needFinishFragment = false; + + if (path != null && getMessagesController().uploadingWallpaperInfo == wallpaperInfo) { + 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()); + canvas.scale(s, s); + if (backgroundImage.getMeasuredHeight() > backgroundImage.getMeasuredWidth()) { + canvas.translate(0, -(backgroundImage.getMeasuredHeight() - backgroundImage.getMeasuredWidth()) / 2f); + } else { + canvas.translate(-(backgroundImage.getMeasuredWidth() - backgroundImage.getMeasuredHeight()) / 2f, 0); + } + float currentDim = dimAmount; + dimAmount = 0; + backgroundImage.draw(canvas); + dimAmount = currentDim; + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + tlwallPaper.stripedThumb = bitmap; + + createServiceMessageLocal(tlwallPaper, forBoth); + + 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).setWallpaperToPeer(dialogId, null, wallpaperInfo, serverWallpaper, () -> { + + }); + } + setupFinished = true; + if (delegate != null) { + delegate.didSetNewBackground(tlwallPaper); + } + finishFragment(); + } else { + Theme.serviceMessageColorBackup = getThemedColor(Theme.key_chat_serviceBackground); + if (Theme.THEME_BACKGROUND_SLUG.equals(wallpaperInfo.slug)) { + wallpaperInfo = null; + } + Theme.getActiveTheme().setOverrideWallpaper(wallpaperInfo); + Theme.reloadWallpaper(true); + if (!sameFile) { + ImageLoader.getInstance().removeImage(ImageLoader.getHttpFileName(toFile.getAbsolutePath()) + "@100_100"); + } + } + } + if (needFinishFragment) { + if (delegate != null) { + delegate.didSetNewBackground(tlwallPaper); + } + finishFragment(); + } } private void onColorsRotate() { @@ -2685,7 +2979,7 @@ private void selectColorType(int id, boolean ask) { } else { messagesAdapter.notifyItemChanged(0); } - listView2.smoothScrollBy(0, AndroidUtilities.dp(60)); + listView2.smoothScrollBy(0, dp(60)); break; } case 3: { @@ -2720,7 +3014,7 @@ private void selectColorType(int id, boolean ask) { } else if (prevType == 2) { messagesAdapter.notifyItemRemoved(0); } - listView2.smoothScrollBy(0, AndroidUtilities.dp(60)); + listView2.smoothScrollBy(0, dp(60)); showAnimationHint(); break; } @@ -3019,7 +3313,7 @@ public void onFragmentDestroy() { blurredBitmap.recycle(); blurredBitmap = null; } - Theme.applyChatServiceMessageColor(); + themeDelegate.applyChatServiceMessageColor(); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); } else if (screenType == SCREEN_TYPE_ACCENT_COLOR || screenType == SCREEN_TYPE_PREVIEW) { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); @@ -3030,6 +3324,115 @@ public void onFragmentDestroy() { } super.onFragmentDestroy(); + checkBlur(null); + } + + private WeakReference lastDrawableToBlur; + private BitmapDrawable blurredDrawable; + private BitmapDrawable checkBlur(Drawable d) { + if (lastDrawableToBlur != null && lastDrawableToBlur.get() == d) { + return blurredDrawable; + } + if (lastDrawableToBlur != null) { + lastDrawableToBlur.clear(); + } + lastDrawableToBlur = null; + if (d == null || d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) { + return blurredDrawable = null; + } + lastDrawableToBlur = new WeakReference<>(d); + + final int h = 24; + final int w = (int) ((float) d.getIntrinsicWidth() / d.getIntrinsicHeight() * h); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + d.setBounds(0, 0, w, h); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + final ColorFilter wasColorFilter = d.getColorFilter(); + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(1.3f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .94f); + d.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + d.draw(new Canvas(bitmap)); + d.setColorFilter(wasColorFilter); + } else { + d.draw(new Canvas(bitmap)); + } + Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes()); + blurredDrawable = new BitmapDrawable(getContext().getResources(), bitmap); + blurredDrawable.setFilterBitmap(true); + return blurredDrawable; + } + + private void invalidateBlur() { + if (dimmingSliderContainer != null) { + dimmingSliderContainer.invalidate(); + } + if (backgroundButtonsContainer != null) { + for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { + backgroundButtonsContainer.getChildAt(a).invalidate(); + } + } + if (messagesButtonsContainer != null) { + for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { + messagesButtonsContainer.getChildAt(a).invalidate(); + } + } + if (backgroundCheckBoxView != null) { + for (int i = 0; i < backgroundCheckBoxView.length; ++i) { + if (backgroundCheckBoxView[i] != null) { + backgroundCheckBoxView[i].setDimAmount(shouldShowBrightnessControll ? dimAmount * progressToDarkTheme : 0); + backgroundCheckBoxView[i].invalidate(); + } + } + } + if (listView != null) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (child instanceof ChatActionCell) { + setVisiblePart((ChatActionCell) child); + child.invalidate(); + } + } + } + if (listView2 != null) { + for (int i = 0; i < listView2.getChildCount(); ++i) { + View child = listView2.getChildAt(i); + if (child instanceof ChatActionCell) { + setVisiblePart((ChatActionCell) child); + child.invalidate(); + } + } + } + if (applyButton1 != null) { + applyButton1.invalidate(); + } + if (applyButton2 != null) { + applyButton2.invalidate(); + } + if (bottomOverlayChat != null) { + bottomOverlayChat.invalidate(); + } + } + + private void setVisiblePart(ChatActionCell cell) { + if (backgroundImage == null) { + return; + } + float tx = 0; + float ty = 0; + if (backgroundImage != null) { + if (themeDelegate.serviceBitmap != null) { + float bitmapWidth = themeDelegate.serviceBitmap.getWidth(); + float bitmapHeight = themeDelegate.serviceBitmap.getHeight(); + float maxScale = Math.max(backgroundImage.getMeasuredWidth() / bitmapWidth, backgroundImage.getMeasuredHeight() / bitmapHeight); + float width = bitmapWidth * maxScale; + tx += ((backgroundImage.getMeasuredWidth() - width) / 2) + currentScrollOffset; + } else { + tx += currentScrollOffset; + } + ty += -backgroundImage.ty; + } + cell.setVisiblePart(cell.getY() - ty, tx, backgroundImage.getMeasuredHeight(), shouldShowBrightnessControll ? dimAmount * progressToDarkTheme : 0); } @Override @@ -3037,12 +3440,23 @@ public void onTransitionAnimationStart(boolean isOpen, boolean backward) { super.onTransitionAnimationStart(isOpen, backward); if (!isOpen) { if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - Theme.applyChatServiceMessageColor(); + themeDelegate.applyChatServiceMessageColor(); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetNewWallpapper); } } } + @Override + public void onBottomSheetCreated() { + super.onBottomSheetCreated(); + if (parentLayout != null && parentLayout.getBottomSheet() != null) { + parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } + } + } + @Override public void onResume() { super.onResume(); @@ -3069,7 +3483,13 @@ public void onPause() { @Override public boolean isSwipeBackEnabled(MotionEvent event) { - return false; + if (screenType != SCREEN_TYPE_CHANGE_BACKGROUND) { + return false; + } + if (hasScrollingBackground && event != null && event.getY() > AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight()) { + return false; + } + return true; } @Override @@ -3171,12 +3591,12 @@ public void didReceivedNotification(int id, int account, Object... args) { patterns.add(wallPaper); patternsDict.put(wallPaper.document.id, wallPaper); } - if (accent != null && accent.patternSlug.equals(wallPaper.slug)) { + if (accent != null && accent.patternSlug != null && accent.patternSlug.equals(wallPaper.slug)) { selectedPattern = (TLRPC.TL_wallPaper) wallPaper; added = true; setCurrentImage(false); updateButtonState(false, false); - } else if (accent == null && selectedPattern != null && selectedPattern.slug.equals(wallPaper.slug)) { + } else if (accent == null && selectedPattern != null && selectedPattern.slug != null && selectedPattern.slug.equals(wallPaper.slug)) { added = true; } } @@ -3212,12 +3632,12 @@ public void didReceivedNotification(int id, int account, Object... args) { patterns.add(wallPaper); patternsDict.put(wallPaper.document.id, wallPaper); } - if (accent != null && accent.patternSlug.equals(wallPaper.slug)) { + if (accent != null && accent.patternSlug != null && accent.patternSlug.equals(wallPaper.slug)) { selectedPattern = wallPaper; added2 = true; setCurrentImage(false); updateButtonState(false, false); - } else if (accent == null && selectedPattern != null && selectedPattern.slug.equals(wallPaper.slug)) { + } else if (accent == null && selectedPattern != null && selectedPattern.slug != null && selectedPattern.slug.equals(wallPaper.slug)) { added2 = true; } } @@ -3535,7 +3955,12 @@ private void updateButtonState(boolean ifSame, boolean animated) { doneButton.setAlpha(fileExists ? 1.0f : 0.5f); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { bottomOverlayChat.setEnabled(fileExists); - bottomOverlayChatText.setAlpha(fileExists ? 1.0f : 0.5f); + if (applyButton1 != null) { + applyButton1.setAlpha(fileExists ? 1.0f : 0.5f); + } + if (applyButton2 != null) { + applyButton2.setAlpha(fileExists ? 1.0f : 0.5f); + } } else { saveItem.setEnabled(fileExists); saveItem.setAlpha(fileExists ? 1.0f : 0.5f); @@ -3578,7 +4003,7 @@ private void showAnimationHint() { animationHint.setAlpha(0); animationHint.setVisibility(View.INVISIBLE); animationHint.setText(LocaleController.getString("BackgroundAnimateInfo", R.string.BackgroundAnimateInfo)); - animationHint.setExtraTranslationY(AndroidUtilities.dp(6)); + animationHint.setExtraTranslationY(dp(6)); frameLayout.addView(animationHint, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); } AndroidUtilities.runOnUIThread(() -> { @@ -3633,7 +4058,7 @@ public void onAnimationEnd(Animator animation) { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) backgroundCheckBoxView[1].getLayoutParams(); AnimatorSet animatorSet = new AnimatorSet(); - int offset = (layoutParams.width + AndroidUtilities.dp(9)) / 2; + int offset = (layoutParams.width + dp(9)) / 2; animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, selectedPattern != null ? 1.0f : 0.0f)); animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, selectedPattern != null ? 0.0f : offset)); animatorSet.playTogether(ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, selectedPattern != null ? 0.0f : -offset)); @@ -3688,7 +4113,7 @@ private void showPatternsView(int num, boolean show, boolean animated) { } else { index = patterns.indexOf(selectedPattern) + (screenType == SCREEN_TYPE_CHANGE_BACKGROUND ? 1 : 0); } - patternsLayoutManager.scrollToPositionWithOffset(index, (patternsListView.getMeasuredWidth() - AndroidUtilities.dp(100 + 24)) / 2); + patternsLayoutManager.scrollToPositionWithOffset(index, (patternsListView.getMeasuredWidth() - dp(100 + 24)) / 2); } } } @@ -3706,7 +4131,7 @@ private void showPatternsView(int num, boolean show, boolean animated) { if (show) { patternLayout[num].setVisibility(View.VISIBLE); if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, num == 1 ? -AndroidUtilities.dp(21) : 0)); + animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, num == 1 ? -dp(21) : 0)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.ALPHA, showMotion ? 1.0f : 0.0f)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, showMotion ? 0.0f : 1.0f)); if (num == 1) { @@ -3717,10 +4142,10 @@ private void showPatternsView(int num, boolean show, boolean animated) { } colorPicker.hideKeyboard(); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, -patternLayout[num].getMeasuredHeight() + AndroidUtilities.dp(48))); + animators.add(ObjectAnimator.ofFloat(listView2, View.TRANSLATION_Y, -patternLayout[num].getMeasuredHeight() + dp(12 + 48 + 12 + (applyButton2 != null ? 48 + 10 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0))); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.ALPHA, showMotion ? 1.0f : 0.0f)); animators.add(ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.ALPHA, showMotion ? 0.0f : 1.0f)); - animators.add(ObjectAnimator.ofFloat(backgroundImage, View.ALPHA, 0.0f)); +// animators.add(ObjectAnimator.ofFloat(backgroundImage, View.ALPHA, 0.0f)); if (patternLayout[otherNum].getVisibility() == View.VISIBLE) { animators.add(ObjectAnimator.ofFloat(patternLayout[otherNum], View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(patternLayout[num], View.ALPHA, 0.0f, 1.0f)); @@ -3772,7 +4197,7 @@ public void onAnimationEnd(Animator animation) { if (show) { patternLayout[num].setVisibility(View.VISIBLE); if (screenType == SCREEN_TYPE_ACCENT_COLOR) { - listView2.setTranslationY(num == 1 ? -AndroidUtilities.dp(21) : 0); + listView2.setTranslationY(num == 1 ? -dp(21) : 0); backgroundCheckBoxView[2].setAlpha(showMotion ? 1.0f : 0.0f); backgroundCheckBoxView[0].setAlpha(showMotion ? 0.0f : 1.0f); if (num == 1) { @@ -3783,10 +4208,10 @@ public void onAnimationEnd(Animator animation) { } colorPicker.hideKeyboard(); } else if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND) { - listView2.setTranslationY(-AndroidUtilities.dp(num == 0 ? 343 : 316) + AndroidUtilities.dp(48)); + listView2.setTranslationY(-dp(num == 0 ? 343 : 316) + dp(48 + 12 + 12 + (applyButton2 != null ? 10 + 48 : 0)) + (insideBottomSheet() ? AndroidUtilities.navigationBarHeight : 0)); backgroundCheckBoxView[2].setAlpha(showMotion ? 1.0f : 0.0f); backgroundCheckBoxView[0].setAlpha(showMotion ? 0.0f : 1.0f); - backgroundImage.setAlpha(0.0f); +// backgroundImage.setAlpha(0.0f); if (patternLayout[otherNum].getVisibility() == View.VISIBLE) { patternLayout[otherNum].setAlpha(0.0f); patternLayout[num].setAlpha(1.0f); @@ -3914,9 +4339,9 @@ private void updatePlayAnimationView(boolean animated) { ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.ALPHA, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.SCALE_X, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(backgroundPlayAnimationView, View.SCALE_Y, visible ? 1.0f : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, visible ? -AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f)); + ObjectAnimator.ofFloat(backgroundCheckBoxView[0], View.TRANSLATION_X, visible ? dp(34) : 0.0f), + ObjectAnimator.ofFloat(backgroundCheckBoxView[1], View.TRANSLATION_X, visible ? -dp(34) : 0.0f), + ObjectAnimator.ofFloat(backgroundCheckBoxView[2], View.TRANSLATION_X, visible ? dp(34) : 0.0f)); backgroundPlayViewAnimator.setDuration(180); backgroundPlayViewAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -3933,9 +4358,9 @@ public void onAnimationEnd(Animator animation) { backgroundPlayAnimationView.setAlpha(visible ? 1.0f : 0.0f); backgroundPlayAnimationView.setScaleX(visible ? 1.0f : 0.0f); backgroundPlayAnimationView.setScaleY(visible ? 1.0f : 0.0f); - backgroundCheckBoxView[0].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); - backgroundCheckBoxView[1].setTranslationX(visible ? -AndroidUtilities.dp(34) : 0.0f); - backgroundCheckBoxView[2].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); + backgroundCheckBoxView[0].setTranslationX(visible ? dp(34) : 0.0f); + backgroundCheckBoxView[1].setTranslationX(visible ? -dp(34) : 0.0f); + backgroundCheckBoxView[2].setTranslationX(visible ? dp(34) : 0.0f); } } } @@ -3956,8 +4381,8 @@ public void onAnimationEnd(Animator animation) { ObjectAnimator.ofFloat(messagesPlayAnimationView, View.ALPHA, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(messagesPlayAnimationView, View.SCALE_X, visible ? 1.0f : 0.0f), ObjectAnimator.ofFloat(messagesPlayAnimationView, View.SCALE_Y, visible ? 1.0f : 0.0f), - ObjectAnimator.ofFloat(messagesCheckBoxView[0], View.TRANSLATION_X, visible ? -AndroidUtilities.dp(34) : 0.0f), - ObjectAnimator.ofFloat(messagesCheckBoxView[1], View.TRANSLATION_X, visible ? AndroidUtilities.dp(34) : 0.0f)); + ObjectAnimator.ofFloat(messagesCheckBoxView[0], View.TRANSLATION_X, visible ? -dp(34) : 0.0f), + ObjectAnimator.ofFloat(messagesCheckBoxView[1], View.TRANSLATION_X, visible ? dp(34) : 0.0f)); messagesPlayViewAnimator.setDuration(180); messagesPlayViewAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -3974,8 +4399,8 @@ public void onAnimationEnd(Animator animation) { messagesPlayAnimationView.setAlpha(visible ? 1.0f : 0.0f); messagesPlayAnimationView.setScaleX(visible ? 1.0f : 0.0f); messagesPlayAnimationView.setScaleY(visible ? 1.0f : 0.0f); - messagesCheckBoxView[0].setTranslationX(visible ? -AndroidUtilities.dp(34) : 0.0f); - messagesCheckBoxView[1].setTranslationX(visible ? AndroidUtilities.dp(34) : 0.0f); + messagesCheckBoxView[0].setTranslationX(visible ? -dp(34) : 0.0f); + messagesCheckBoxView[1].setTranslationX(visible ? dp(34) : 0.0f); } } } @@ -4027,10 +4452,10 @@ private void setBackgroundColor(int color, int num, boolean applyNow, boolean an patternColor = checkColor = AndroidUtilities.getPatternColor(backgroundColor); } if (!Theme.hasThemeKey(Theme.key_chat_serviceBackground) || backgroundImage.getBackground() instanceof MotionBackgroundDrawable) { - Theme.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground()); + themeDelegate.applyChatServiceMessageColor(new int[]{checkColor, checkColor, checkColor, checkColor}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); } else if (Theme.getCachedWallpaperNonBlocking() instanceof MotionBackgroundDrawable) { int c = getThemedColor(Theme.key_chat_serviceBackground); - Theme.applyChatServiceMessageColor(new int[]{c, c, c, c}, backgroundImage.getBackground()); + themeDelegate.applyChatServiceMessageColor(new int[]{c, c, c, c}, backgroundImage.getBackground(), backgroundImage.getBackground(), currentIntensity); } if (backgroundPlayAnimationImageView != null) { backgroundPlayAnimationImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_serviceText), PorterDuff.Mode.MULTIPLY)); @@ -4081,7 +4506,11 @@ private void setCurrentImage(boolean setThumb) { if (currentWallpaper instanceof TLRPC.TL_wallPaper) { TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) currentWallpaper; TLRPC.PhotoSize thumb = setThumb ? FileLoader.getClosestPhotoSizeWithSize(wallPaper.document.thumbs, 100) : null; - backgroundImage.setImage(ImageLocation.getForDocument(wallPaper.document), imageFilter, ImageLocation.getForDocument(thumb, wallPaper.document), "100_100_b", "jpg", wallPaper.document.size, 1, wallPaper); + Drawable thumbDrawable = null; + if (thumb instanceof TLRPC.TL_photoStrippedSize) { + thumbDrawable = new BitmapDrawable(ImageLoader.getStrippedPhotoBitmap(thumb.bytes, "b")); + } + backgroundImage.setImage(ImageLocation.getForDocument(wallPaper.document), imageFilter, ImageLocation.getForDocument(thumb, wallPaper.document), "100_100_b", thumbDrawable, "jpg", wallPaper.document.size, 1, wallPaper); } else if (currentWallpaper instanceof WallpapersListActivity.ColorWallpaper) { WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) currentWallpaper; backgroundRotation = wallPaper.gradientRotation; @@ -4132,6 +4561,11 @@ private void setCurrentImage(boolean setThumb) { } 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) { @@ -4258,16 +4692,7 @@ public void onSizeReady(int width, int height) { if (messagesPlayAnimationImageView != null) { messagesPlayAnimationImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_serviceText), PorterDuff.Mode.MULTIPLY)); } - if (backgroundButtonsContainer != null) { - for (int a = 0, N = backgroundButtonsContainer.getChildCount(); a < N; a++) { - backgroundButtonsContainer.getChildAt(a).invalidate(); - } - } - if (messagesButtonsContainer != null) { - for (int a = 0, N = messagesButtonsContainer.getChildCount(); a < N; a++) { - messagesButtonsContainer.getChildAt(a).invalidate(); - } - } + invalidateBlur(); } rotatePreview = false; } @@ -4452,50 +4877,86 @@ public MessagesAdapter(Context context) { 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); @@ -4504,9 +4965,12 @@ public MessagesAdapter(Context context) { 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; @@ -4865,7 +5329,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewT view = new ChatMessageCell(mContext, false, null, new Theme.ResourcesProvider() { @Override public int getColor(int key) { - return getThemedColor(key); + return themeDelegate.getColor(key); } @Override @@ -4882,16 +5346,41 @@ public Drawable getDrawable(String drawableKey) { 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); } @@ -4902,7 +5391,7 @@ public void applyServiceShaderMatrix(int w, int h, float translationX, float tra }); } else if (viewType == 1) { - view = new ChatActionCell(mContext); + view = new ChatActionCell(mContext, false, themeDelegate); ((ChatActionCell) view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { }); @@ -4913,7 +5402,7 @@ public void applyServiceShaderMatrix(int w, int h, float translationX, float tra FrameLayout frameLayout = new FrameLayout(mContext) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(60), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(60), MeasureSpec.EXACTLY)); } }; frameLayout.addView(backgroundButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 76, Gravity.CENTER)); @@ -4922,7 +5411,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(4), MeasureSpec.EXACTLY)); } }; } else { @@ -4932,7 +5421,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { FrameLayout frameLayout = new FrameLayout(mContext) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(60), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dp(60), MeasureSpec.EXACTLY)); } }; frameLayout.addView(messagesButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 76, Gravity.CENTER)); @@ -4971,13 +5460,14 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } 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) { ChatActionCell actionCell = (ChatActionCell) view; actionCell.setMessageObject(message); actionCell.setAlpha(1.0f); + invalidateBlur(); } } } @@ -5138,13 +5628,12 @@ public ArrayList getThemeDescriptionsInternal() { if (bottomOverlayChat != null) { bottomOverlayChat.invalidate(); } - if (brightnessControlCell != null) { - brightnessControlCell.invalidate(); - brightnessControlCell.seekBarView.invalidate(); - } if (onSwitchDayNightDelegate != null) { if (parentLayout != null && parentLayout.getBottomSheet() != null) { parentLayout.getBottomSheet().fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + if (screenType == SCREEN_TYPE_CHANGE_BACKGROUND && dialogId != 0) { + parentLayout.getBottomSheet().setOverlayNavBarColor(0xff000000); + } } else { setNavigationBarColor(getThemedColor(Theme.key_dialogBackground)); } @@ -5219,7 +5708,6 @@ public ArrayList getThemeDescriptionsInternal() { items.add(new ThemeDescription(bottomOverlayChat, 0, null, null, new Drawable[]{Theme.chat_composeShadowDrawable}, null, Theme.key_chat_messagePanelShadow)); items.add(new ThemeDescription(bottomOverlayChat, 0, null, Theme.chat_composeBackgroundPaint, null, null, Theme.key_chat_messagePanelBackground)); - items.add(new ThemeDescription(bottomOverlayChatText, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_fieldOverlayText)); for (int a = 0; a < patternsSaveButton.length; a++) { items.add(new ThemeDescription(patternsSaveButton[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_fieldOverlayText)); @@ -5264,7 +5752,6 @@ public ArrayList getThemeDescriptionsInternal() { items.add(new ThemeDescription(listView2, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_inTimeSelectedText)); items.add(new ThemeDescription(listView2, 0, new Class[]{ChatMessageCell.class}, null, null, null, Theme.key_chat_outTimeSelectedText)); } - items.add(new ThemeDescription(dimmingHeaderCell, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_divider)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_dialogBackground)); items.add(new ThemeDescription(null, 0, null, null, null, null, descriptionDelegate, Theme.key_windowBackgroundWhiteBlackText)); @@ -5287,7 +5774,7 @@ public ArrayList getThemeDescriptions() { } } - private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { + private void createServiceMessageLocal(TLRPC.WallPaper wallPaper, boolean forBoth) { TLRPC.TL_messageService message = new TLRPC.TL_messageService(); message.random_id = SendMessagesHelper.getInstance(currentAccount).getNextRandomId(); @@ -5295,15 +5782,24 @@ private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { 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; setChatWallPaper.wallpaper = wallPaper; + setChatWallPaper.for_both = forBoth; ArrayList objArr = new ArrayList<>(); objArr.add(new MessageObject(currentAccount, message, false, false)); @@ -5316,12 +5812,14 @@ private void createServiceMessageLocal(TLRPC.WallPaper wallPaper) { public interface DayNightSwitchDelegate { boolean isDark(); - void switchDayNight(); + boolean supportsAnimation(); + + void switchDayNight(boolean animated); } - private class BackgroundView extends BackupImageView { + public class BackgroundView extends BackupImageView { - private Drawable background; + public Drawable background; boolean drawBackground = true; public BackgroundView(Context context) { @@ -5351,6 +5849,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { maxScrollOffset = currentScrollOffset * 2f; setSize(scaledWidth, getMeasuredHeight()); drawFromStart = true; + invalidateBlur(); } } if (!hasScrollingBackground) { @@ -5361,8 +5860,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { lastSizeHash = sizeHash; } + public float tx, ty; + @Override protected void onDraw(Canvas canvas) { + tx = 0; + ty = 0; if (drawBackground) { if (background instanceof ColorDrawable || background instanceof GradientDrawable || background instanceof MotionBackgroundDrawable) { background.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -5385,6 +5888,7 @@ protected void onDraw(Canvas canvas) { int height = (int) Math.ceil(background.getIntrinsicHeight() * scale * parallaxScale); int x = (getMeasuredWidth() - width) / 2; int y = (viewHeight - height) / 2; + ty = y; background.setBounds(x, y, x + width, y + height); background.draw(canvas); } @@ -5396,17 +5900,19 @@ protected void onDraw(Canvas canvas) { if (scroller.getStartX() < maxScrollOffset && scroller.getStartX() > 0) { currentScrollOffset = scroller.getCurrX(); } + invalidateBlur(); invalidate(); } } canvas.save(); + tx = -currentScrollOffset; canvas.translate(-currentScrollOffset, 0); super.onDraw(canvas); canvas.restore(); } else { super.onDraw(canvas); } - if (shouldShowBrightnessControll && dimAmount > 0 && onSwitchDayNightDelegate != null && onSwitchDayNightDelegate.isDark()) { + if (shouldShowBrightnessControll && dimAmount > 0) { canvas.drawColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); } } @@ -5419,6 +5925,14 @@ public Drawable getBackground() { @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); } } @@ -5443,4 +5957,483 @@ public void setTop(int top, int backgroundWidth, int backgroundHeight, int heigh super.setTop(top, backgroundWidth, backgroundHeight, heightOffset, blurredViewTopOffset, blurredViewBottomOffset, topNear, bottomNear); } } + + private class BlurButton extends View { + + private Text text; + private 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; + + public BlurButton(Context context) { + super(context); + rippleDrawable.setCallback(this); + + ColorMatrix colorMatrix = new ColorMatrix(); + AndroidUtilities.adjustSaturationColorMatrix(colorMatrix, +.35f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, 0.9f); + colorFilter = new ColorMatrixColorFilter(colorMatrix); + } + + public void setText(CharSequence text) { + 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; + } + + private CircularProgressDrawable loadingDrawable; + private final Paint dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint dimPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void onDraw(Canvas canvas) { + final float r = dp(8); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + + Theme.applyServiceShaderMatrixForView(this, backgroundImage, themeDelegate); + + Paint paint = themeDelegate.getPaint(Theme.key_paint_chatActionBackground); + + final ColorFilter wasColorFilter = paint.getColorFilter(); + paint.setColorFilter(colorFilter); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, paint); + paint.setColorFilter(wasColorFilter); + + if (shouldShowBrightnessControll && dimAmount > 0) { + dimPaint2.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * dimAmount * progressToDarkTheme))); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint2); + } + + dimPaint.setColor(0x1effffff); + canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, dimPaint); + + final int textColor = Color.WHITE; + + if (loadingT > 0) { + if (loadingDrawable == null) { + loadingDrawable = new CircularProgressDrawable(textColor); + } + int y = (int) ((1f - loadingT) * dp(-24)); + loadingDrawable.setBounds(0, y, getWidth(), y + getHeight()); + loadingDrawable.setAlpha((int) (0xFF * loadingT)); + loadingDrawable.draw(canvas); + invalidate(); + } + + 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) - 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()); + rippleDrawable.draw(canvas); + } + + + private float loadingT = 0; + private boolean loading; + private ValueAnimator loadingAnimator; + public void setLoading(boolean loading) { + if (this.loading != loading) { + if (loadingAnimator != null) { + loadingAnimator.cancel(); + loadingAnimator = null; + } + + loadingAnimator = ValueAnimator.ofFloat(loadingT, (this.loading = loading) ? 1 : 0); + loadingAnimator.addUpdateListener(anm -> { + loadingT = (float) anm.getAnimatedValue(); + invalidate(); + }); + loadingAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + loadingT = loading ? 1 : 0; + invalidate(); + } + }); + loadingAnimator.setDuration(320); + loadingAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + loadingAnimator.start(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean r = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + r = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + rippleDrawable.setHotspot(event.getX(), event.getY()); + } + rippleDrawable.setState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}); + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + rippleDrawable.setState(StateSet.NOTHING); + } + return super.onTouchEvent(event) || r; + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == rippleDrawable || super.verifyDrawable(who); + } + } + + public class ThemeDelegate implements Theme.ResourcesProvider { + + public Theme.ResourcesProvider parentProvider; + + private final SparseIntArray currentColors = new SparseIntArray(); + + public final Paint chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + public final Paint chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + + public final TextPaint chat_actionTextPaint = new TextPaint(); + public final TextPaint chat_actionTextPaint2 = new TextPaint(); + public final TextPaint chat_botButtonPaint = new TextPaint(); + + private Bitmap serviceBitmap; + public BitmapShader serviceBitmapShader; + private Matrix serviceBitmapMatrix; + public int serviceMessageColorBackup; + public int serviceSelectedMessageColorBackup; + + public ThemeDelegate() { + chat_actionTextPaint.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_actionTextPaint2.setTextSize(AndroidUtilities.dp(Math.max(16, SharedConfig.fontSize) - 2)); + chat_botButtonPaint.setTextSize(AndroidUtilities.dp(15)); + chat_botButtonPaint.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + chat_actionBackgroundGradientDarkenPaint.setColor(0x15000000); + } + + @Override + public int getColor(int key) { + if (parentProvider != null) { + return parentProvider.getColor(key); + } + return Theme.getColor(key); + } + + @Override + public Drawable getDrawable(String drawableKey) { + if (parentProvider != null) { + return parentProvider.getDrawable(drawableKey); + } + return Theme.getThemeDrawable(drawableKey); + } + + @Override + public int getCurrentColor(int key) { + if (parentProvider != null) { + return parentProvider.getCurrentColor(key); + } + return Theme.ResourcesProvider.super.getCurrentColor(key); + } + + @Override + public Paint getPaint(String paintKey) { + switch (paintKey) { + case Theme.key_paint_chatActionBackground: return chat_actionBackgroundPaint; + case Theme.key_paint_chatActionBackgroundSelected: return chat_actionBackgroundSelectedPaint; + case Theme.key_paint_chatActionBackgroundDarken: return chat_actionBackgroundGradientDarkenPaint; + case Theme.key_paint_chatActionText: return chat_actionTextPaint; + case Theme.key_paint_chatActionText2: return chat_actionTextPaint2; + case Theme.key_paint_chatBotButton: return chat_botButtonPaint; + } + if (parentProvider != null) { + return parentProvider.getPaint(paintKey); + } + return Theme.ResourcesProvider.super.getPaint(paintKey); + } + + @Override + public boolean hasGradientService() { + if (parentProvider != null) { + return parentProvider.hasGradientService(); + } + return Theme.hasGradientService(); + } + + public void applyChatServiceMessageColor() { + applyChatServiceMessageColor(null, null, null, null); + } + + public void applyChatServiceMessageColor(int[] custom, Drawable wallpaperOverride, Drawable currentWallpaper, Float overrideIntensity) { + int serviceColor = getColor(Theme.key_chat_serviceBackground); + int servicePressedColor = getColor(Theme.key_chat_serviceBackgroundSelected); + Drawable drawable = wallpaperOverride != null ? wallpaperOverride : currentWallpaper; + boolean drawServiceGradient = (drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable) && SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW && LiteMode.isEnabled(LiteMode.FLAG_CHAT_BACKGROUND); + if (drawServiceGradient) { + Bitmap newBitmap = null; + if (drawable instanceof MotionBackgroundDrawable) { + newBitmap = ((MotionBackgroundDrawable) drawable).getBitmap(); + } else if (drawable instanceof BitmapDrawable) { + newBitmap = ((BitmapDrawable) drawable).getBitmap(); + } + if (serviceBitmap != newBitmap) { + serviceBitmap = newBitmap; + serviceBitmapShader = new BitmapShader(serviceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (serviceBitmapMatrix == null) { + serviceBitmapMatrix = new Matrix(); + } + } + chat_actionTextPaint.setColor(0xffffffff); + chat_actionTextPaint2.setColor(0xffffffff); + chat_actionTextPaint.linkColor = 0xffffffff; + chat_botButtonPaint.setColor(0xffffffff); + } else { + serviceBitmap = null; + serviceBitmapShader = null; + chat_actionTextPaint.setColor(getColor(Theme.key_chat_serviceText)); + chat_actionTextPaint2.setColor(getColor(Theme.key_chat_serviceText)); + chat_actionTextPaint.linkColor = getColor(Theme.key_chat_serviceLink); + } + + chat_actionBackgroundPaint.setColor(serviceColor); + chat_actionBackgroundSelectedPaint.setColor(servicePressedColor); + + if (serviceBitmapShader != null && (currentColors.indexOfKey(Theme.key_chat_serviceBackground) < 0 || drawable instanceof MotionBackgroundDrawable || drawable instanceof BitmapDrawable)) { + ColorMatrix colorMatrix = new ColorMatrix(); + if (drawable instanceof MotionBackgroundDrawable) { + float intensity = ((MotionBackgroundDrawable) drawable).getIntensity(); + if (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) { + intensity = overrideIntensity; + } + if (intensity >= 0) { + colorMatrix.setSaturation(1.8f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .97f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.03f); + } else { + colorMatrix.setSaturation(0.5f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .35f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.03f); + } + } else { + colorMatrix.setSaturation(1.6f); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .97f); + AndroidUtilities.adjustBrightnessColorMatrix(colorMatrix, +.06f); + } + + chat_actionBackgroundPaint.setShader(serviceBitmapShader); + chat_actionBackgroundPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + chat_actionBackgroundPaint.setAlpha(0xff); + + chat_actionBackgroundSelectedPaint.setShader(serviceBitmapShader); + colorMatrix = new ColorMatrix(colorMatrix); + AndroidUtilities.multiplyBrightnessColorMatrix(colorMatrix, .85f); + chat_actionBackgroundSelectedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + chat_actionBackgroundSelectedPaint.setAlpha(0xff); + } else { + chat_actionBackgroundPaint.setColorFilter(null); + chat_actionBackgroundPaint.setShader(null); + chat_actionBackgroundSelectedPaint.setColorFilter(null); + chat_actionBackgroundSelectedPaint.setShader(null); + } + } + + @Override + public void applyServiceShaderMatrix(int w, int h, float translationX, float translationY) { + if (/*backgroundDrawable == null || */serviceBitmap == null || serviceBitmapShader == null) { + Theme.ResourcesProvider.super.applyServiceShaderMatrix(w, h, translationX, translationY); + } else { + Theme.applyServiceShaderMatrix(serviceBitmap, serviceBitmapShader, serviceBitmapMatrix, w, h, translationX, translationY); + } + } + + @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/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 0bc4c2fd0a..6d164451fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -52,8 +52,6 @@ import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -132,6 +130,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.concurrent.CountDownLatch; import tw.nekomimi.nekogram.BackButtonMenuRecent; import tw.nekomimi.nekogram.NekoConfig; @@ -196,6 +195,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private static final int show_id = 13; private boolean removeFragmentOnTransitionEnd; + private boolean finishDialogRightSlidingPreviewOnTransitionEnd; TLRPC.ChatFull chatFull; boolean canShowCreateTopic; private UnreadCounterTextView bottomOverlayChatText; @@ -292,6 +292,32 @@ public TopicsFragment(Bundle bundle) { canShowProgress = !getUserConfig().getPreferences().getBoolean("topics_end_reached_" + chatId, false); } + public static BaseFragment getTopicsOrChat(BaseFragment parentFragment, Bundle args) { + return getTopicsOrChat(parentFragment.getMessagesController(), parentFragment.getMessagesStorage(), args); + } + + public static BaseFragment getTopicsOrChat(LaunchActivity launchActivity, Bundle args) { + return getTopicsOrChat(MessagesController.getInstance(launchActivity.currentAccount), MessagesStorage.getInstance(launchActivity.currentAccount), args); + } + + private static BaseFragment getTopicsOrChat(MessagesController messagesController, MessagesStorage messagesStorage, Bundle args) { + long chatId = args.getLong("chat_id"); + if (chatId != 0L) { + TLRPC.Dialog dialog = messagesController.getDialog(-chatId); + if (dialog != null && dialog.view_forum_as_messages) { + return new ChatActivity(args); + } + TLRPC.ChatFull chatFull = messagesController.getChatFull(chatId); + if (chatFull == null) { + chatFull = messagesStorage.loadChatInfo(chatId, true, new CountDownLatch(1), false, false); + } + if (chatFull != null && chatFull.view_forum_as_messages) { + return new ChatActivity(args); + } + } + return new TopicsFragment(args); + } + public static void prepareToSwitchAnimation(ChatActivity chatActivity) { if (chatActivity.getParentLayout() == null) { return; @@ -512,7 +538,13 @@ public void onItemClick(int id) { TLRPC.TL_forumTopic topic; switch (id) { case toggle_id: - switchToChat(false); + getMessagesController().getTopicsController().toggleViewForumAsMessages(chatId, true); + finishDialogRightSlidingPreviewOnTransitionEnd = true; + Bundle bundle = new Bundle(); + bundle.putLong("chat_id", chatId); + ChatActivity chatActivity = new ChatActivity(bundle); + chatActivity.setSwitchFromTopics(true); + presentFragment(chatActivity); break; case add_member_id: TLRPC.ChatFull chatFull = getMessagesController().getChatFull(chatId); @@ -1401,7 +1433,7 @@ private void openParentSearch() { parentAvatarImageView = new BackupImageView(getContext()); parentAvatarDrawable = new AvatarDrawable(); parentAvatarImageView.setRoundRadius(AndroidUtilities.dp(16)); - parentAvatarDrawable.setInfo(getCurrentChat()); + parentAvatarDrawable.setInfo(currentAccount, getCurrentChat()); parentAvatarImageView.setForUserOrChat(getCurrentChat(), parentAvatarDrawable); } parentDialogsActivity.getSearchItem().setSearchPaddingStart(52); @@ -3796,10 +3828,19 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { notificationsLocker.unlock(); - if (!isOpen && (opnendForSelect && removeFragmentOnTransitionEnd)) { - removeSelfFromStack(); - if (dialogsActivity != null) { - dialogsActivity.removeSelfFromStack(); + if (!isOpen) { + if (opnendForSelect && removeFragmentOnTransitionEnd) { + removeSelfFromStack(); + if (dialogsActivity != null) { + dialogsActivity.removeSelfFromStack(); + } + } else if (finishDialogRightSlidingPreviewOnTransitionEnd) { + removeSelfFromStack(); + if (parentDialogsActivity != null && parentDialogsActivity.rightSlidingDialogContainer != null) { + if (parentDialogsActivity.rightSlidingDialogContainer.hasFragment()) { + parentDialogsActivity.rightSlidingDialogContainer.finishPreview(); + } + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index ce563549cf..3fc5498e17 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.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.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.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,36 +77,51 @@ 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.EmojiTextView; -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 { @@ -115,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; @@ -143,6 +175,7 @@ public class VoIPFragment implements VoIPService.StateListener, NotificationCent private VoIPTextureView currentUserTextureView; private AcceptDeclineView acceptDeclineView; + private boolean isNearEar; View bottomShadow; View topShadow; @@ -155,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; @@ -189,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 -> { @@ -198,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; @@ -264,8 +301,8 @@ public static void show(Activity activity, boolean overlay, int account) { 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) { @@ -379,7 +416,7 @@ private void onBackPressed() { if (emojiExpanded) { expandEmoji(false); } else { - if (emojiRationalTextView.getVisibility() != View.GONE) { + if (emojiRationalLayout.getVisibility() != View.GONE) { return; } if (canSwitchToPip && !lockOnScreen) { @@ -398,9 +435,6 @@ public static void clearInstance() { 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) { @@ -429,17 +463,14 @@ private void setInsets(WindowInsets windowInsets) { ((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(); @@ -456,9 +487,11 @@ public VoIPFragment(int account) { 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() { @@ -466,9 +499,11 @@ private void destroy() { 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 @@ -496,13 +531,34 @@ public void didReceivedNotification(int id, int account, Object... args) { 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); } } @@ -545,25 +601,35 @@ public View createView(Context context) { 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(); @@ -667,6 +733,9 @@ public boolean onTouchEvent(MotionEvent ev) { } else if (canHideUI) { showUi(!uiVisible); previousState = currentState; + if (!uiVisible && tapToVideoTooltip != null && tapToVideoTooltip.shown()) { + tapToVideoTooltip.hide(); + } updateViewState(); } } @@ -679,11 +748,11 @@ public boolean onTouchEvent(MotionEvent ev) { @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) ) { @@ -705,16 +774,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 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); @@ -722,30 +783,19 @@ protected void onDraw(Canvas canvas) { 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(); - } - }); - 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); + gradientLayout.invalidate(); } }); - callingUserPhotoView.setImage(ImageLocation.getForUserOrChat(callingUser, ImageLocation.TYPE_BIG), null, gradientDrawable, callingUser); - currentUserCameraFloatingLayout = new VoIPFloatingLayout(context); currentUserCameraFloatingLayout.setDelegate((progress, value) -> currentUserTextureView.setScreenshareMiniProgress(progress, value)); currentUserCameraFloatingLayout.setRelativePosition(1f, 1f); @@ -779,7 +829,7 @@ public void onAllSizesReady() { 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) { @@ -797,17 +847,14 @@ public void onAllSizesReady() { 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 @@ -825,22 +872,60 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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 @@ -872,23 +957,26 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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 EmojiTextView(context); - callingUserTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); + callingUserTitle = new TextView(context); + 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)); @@ -896,18 +984,56 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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) { @@ -928,10 +1054,14 @@ public void onAccept() { 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); + } + } + }); } } } @@ -948,14 +1078,16 @@ public void onDecline() { } } }); - 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)); @@ -976,12 +1108,23 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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); } }); @@ -994,7 +1137,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { backIcon.setVisibility(View.GONE); } - notificationsLayout = new VoIPNotificationsLayout(context); + notificationsLayout = new VoIPNotificationsLayout(context, backgroundProvider); notificationsLayout.setGravity(Gravity.BOTTOM); notificationsLayout.setOnViewsUpdated(() -> { previousState = currentState; @@ -1002,11 +1145,30 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { }); 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(); @@ -1021,6 +1183,105 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 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; @@ -1111,9 +1372,6 @@ public void switchToPip() { 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(); @@ -1187,7 +1445,6 @@ public void startTransitionFromPiP() { topShadow.setAlpha(0f); speakerPhoneIcon.setAlpha(0f); notificationsLayout.setAlpha(0f); - callingUserPhotoView.setAlpha(0f); currentUserCameraFloatingLayout.switchingToPip = true; AndroidUtilities.runOnUIThread(() -> { @@ -1202,7 +1459,6 @@ public void startTransitionFromPiP() { 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 @@ -1286,12 +1542,6 @@ public Animator createPiPTransition(boolean enter) { 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); @@ -1328,11 +1578,6 @@ public Animator createPiPTransition(boolean enter) { currentUserTextureView.setScreenshareMiniProgress(v, false); } windowView.invalidate(); - callingUserPhotoView.setScaleX(callingUserScale); - callingUserPhotoView.setScaleY(callingUserScale); - callingUserPhotoView.setTranslationX(tx); - callingUserPhotoView.setTranslationY(ty); - callingUserPhotoView.setAlpha(1f - v); }); return animator; } @@ -1343,56 +1588,88 @@ private void expandEmoji(boolean expanded) { } emojiExpanded = expanded; if (expanded) { - AndroidUtilities.runOnUIThread(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); + if (SharedConfig.callEncryptionHintDisplayedCount < 2) { + SharedConfig.incrementCallEncryptionHintDisplayed(2); } - emojiRationalTextView.animate().alpha(1f).setDuration(150).start(); + encryptionTooltip.hide(); + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; - 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; } } } @@ -1406,26 +1683,19 @@ private void updateViewState() { 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; @@ -1434,13 +1704,17 @@ private void updateViewState() { 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); @@ -1457,14 +1731,96 @@ private void updateViewState() { 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); @@ -1534,6 +1890,7 @@ private void updateViewState() { 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; @@ -1549,7 +1906,7 @@ private void updateViewState() { if (callingUserIsVideo) { if (!switchingToPip) { - callingUserPhotoView.setAlpha(1f); + gradientLayout.setAlpha(1f); } if (animated) { callingUserTextureView.animate().alpha(1f).setDuration(250).start(); @@ -1563,10 +1920,9 @@ private void updateViewState() { } 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 { @@ -1581,8 +1937,8 @@ private void updateViewState() { 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); @@ -1590,26 +1946,24 @@ private void updateViewState() { 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 { @@ -1630,16 +1984,40 @@ private void updateViewState() { 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) { @@ -1653,20 +2031,25 @@ private void updateViewState() { 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"); } @@ -1675,7 +2058,9 @@ private void updateViewState() { 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(); } @@ -1711,7 +2096,14 @@ private void updateViewState() { 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); @@ -1730,29 +2122,42 @@ public void onAnimationEnd(Animator animation) { callingUserMiniFloatingLayout.restoreRelativePosition(); updateSpeakerPhoneIcon(); - } - private void fillNavigationBar(boolean fill, boolean animated) { - if (switchingToPip) { - return; + 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); + } + } + 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); } - if (!animated) { - if (naviagtionBarAnimator != null) { - naviagtionBarAnimator.cancel(); - } - 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; } private void showUi(boolean show) { @@ -1760,12 +2165,15 @@ private void showUi(boolean show) { 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); @@ -1775,12 +2183,15 @@ private void showUi(boolean show) { 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(); @@ -1793,7 +2204,7 @@ private void showUi(boolean show) { 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) { @@ -1878,17 +2289,33 @@ public void onAnimationEnd(Animator animation) { 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) { @@ -1900,9 +2327,11 @@ public void onAnimationEnd(Animator animation) { 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) { @@ -1927,18 +2356,39 @@ private void updateKeyView(boolean animated) { } 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); } @@ -1958,11 +2408,19 @@ private void checkEmojiLoaded(boolean animated) { 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); } } @@ -2003,91 +2461,123 @@ private void updateButtons(boolean animated) { 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; @@ -2105,7 +2595,7 @@ private void setMicrophoneAction(VoIPToggleButton bottomButton, VoIPService serv }); } - 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; @@ -2114,12 +2604,17 @@ private void setVideoAction(VoIPToggleButton bottomButton, VoIPService service, } 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 { @@ -2139,7 +2634,7 @@ private void setVideoAction(VoIPToggleButton bottomButton, VoIPService service, }); 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); } @@ -2150,9 +2645,10 @@ private void updateSpeakerPhoneIcon() { 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()) { @@ -2163,42 +2659,47 @@ private void updateSpeakerPhoneIcon() { } } - 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()) { @@ -2208,6 +2709,7 @@ private void setFrontalCameraAction(VoIPToggleButton bottomButton, VoIPService s } view.announceForAccessibility(text); } + bottomButton.setType(VoIpSwitchLayout.Type.CAMERA, !service.isFrontFaceCamera()); serviceInstance.switchCamera(); } }); @@ -2241,7 +2743,9 @@ private void toggleCameraInput() { 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; @@ -2252,6 +2756,10 @@ public void onDismiss(boolean screencast, boolean apply) { 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) { @@ -2261,6 +2769,34 @@ public void onDismiss(boolean screencast, boolean apply) { 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()); @@ -2302,7 +2838,11 @@ private void onRequestPermissionsResultInternal(int requestCode, String[] permis 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(); @@ -2362,9 +2902,6 @@ public void onPauseInternal() { 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(); @@ -2420,4 +2957,22 @@ private void requestInlinePermissions() { }).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 7b17cdf7c5..3ae3356b55 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 void onDraw(Canvas canvas) { 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 4f63455bd6..e51e9224a0 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; @@ -141,7 +143,7 @@ public class WallpapersListActivity extends BaseFragment implements Notification private HashMap patternsDict = new HashMap<>(); private boolean loadingWallpapers; - private LongSparseArray selectedWallPapers = new LongSparseArray<>(); + private final LongSparseArray selectedWallPapers = new LongSparseArray<>(); private boolean scrolling; private final static int forward = 3; @@ -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 WallpapersListActivity(int type, long dialogId) { @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 static void fillDefaultColors(ArrayList wallPapers, boolean isDar @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 void didSelectWallpaper(File file, Bitmap bitmap, boolean gallery) { 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 void needOpenColorPicker() { 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 void restoreSelfArgs(Bundle args) { } 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; @@ -963,19 +979,36 @@ private void onItemClick(WallpaperCell view, Object object, int index) { object = colorWallpaper; } } - ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false); + ThemePreviewActivity wallpaperActivity = new ThemePreviewActivity(object, null, true, false) { + @Override + public boolean insideBottomSheet() { + return true; + } + }; if (currentType == TYPE_COLOR || dialogId != 0) { - wallpaperActivity.setDelegate(WallpapersListActivity.this::removeSelfFromStack); + wallpaperActivity.setDelegate(wallPaper -> WallpapersListActivity.this.removeSelfFromStack()); } if (selectedBackgroundSlug.equals(slug)) { wallpaperActivity.setInitialModes(selectedBackgroundBlurred, selectedBackgroundMotion, selectedIntensity); } wallpaperActivity.setPatterns(patterns); wallpaperActivity.setDialogId(dialogId); - presentFragment(wallpaperActivity); + showAsSheet(wallpaperActivity); } } + private void showAsSheet(ThemePreviewActivity themePreviewActivity) { + BaseFragment.BottomSheetParams params = new BaseFragment.BottomSheetParams(); + params.transitionFromLeft = true; + params.allowNestedScroll = false; + themePreviewActivity.setResourceProvider(resourceProvider); + params.onOpenAnimationFinished = () -> { + PhotoViewer.getInstance().closePhoto(false, false); + }; + params.occupyNavigationBar = true; + showAsSheet(themePreviewActivity, params); + } + private String getWallPaperSlug(Object object) { if (object instanceof TLRPC.TL_wallPaper) { return ((TLRPC.TL_wallPaper) object).slug; @@ -1008,7 +1041,7 @@ public void didReceivedNotification(int id, int account, Object... args) { 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(); @@ -1028,7 +1061,7 @@ public void didReceivedNotification(int id, int account, Object... args) { 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; } @@ -1107,7 +1140,7 @@ private void loadWallpapers(boolean force) { 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(); @@ -1125,7 +1158,7 @@ private void loadWallpapers(boolean force) { 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; } @@ -1162,7 +1195,7 @@ private void loadWallpapers(boolean force) { } private void fillWallpapersWithCustom() { - if (currentType != TYPE_ALL) { + if (currentType != TYPE_ALL && currentType != TYPE_CHANNEL_PATTERNS) { return; } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -1357,10 +1390,20 @@ private void updateRows() { 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); @@ -1858,6 +1901,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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; } @@ -1865,6 +1911,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 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; } @@ -1939,11 +1987,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { @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/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java index 9110c86a48..6f863b3a92 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoChatSettingsActivity.java @@ -121,6 +121,7 @@ public class NekoChatSettingsActivity extends BaseNekoXSettingsActivity implemen private final AbstractConfigCell disableZalgoSymbolsRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getZalgoFilter(), LocaleController.getString("ZalgoFilterNotice", R.string.ZalgoFilterNotice))); private final AbstractConfigCell quickToggleAnonymousRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getQuickToggleAnonymous(), LocaleController.getString("QuickToggleAnonymousNotice", R.string.QuickToggleAnonymousNotice))); private final AbstractConfigCell showOnlineStatusRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowOnlineStatus(), LocaleController.getString("ShowOnlineStatusNotice", R.string.ShowOnlineStatusNotice))); + private final AbstractConfigCell showRecentOnlineStatusRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowRecentOnlineStatus())); private final AbstractConfigCell dividerChat = cellGroup.appendCell(new ConfigCellDivider()); // Interactions @@ -146,7 +147,6 @@ public class NekoChatSettingsActivity extends BaseNekoXSettingsActivity implemen private final AbstractConfigCell typeMessageHintUseGroupNameRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getTypeMessageHintUseGroupName())); private final AbstractConfigCell showSendAsUnderMessageHintRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowSendAsUnderMessageHint())); private final AbstractConfigCell hideBotButtonInInputFieldRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getHideBotButtonInInputField())); - private final AbstractConfigCell showForumAsNormalChatRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowForumAsNormalChat())); private final AbstractConfigCell doNotUnarchiveBySwipeRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getDoNotUnarchiveBySwipe())); private final AbstractConfigCell dividerInteractions = cellGroup.appendCell(new ConfigCellDivider()); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoGeneralSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoGeneralSettingsActivity.java index 484bbf08b1..7ee87b01c6 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoGeneralSettingsActivity.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoGeneralSettingsActivity.java @@ -93,6 +93,7 @@ public class NekoGeneralSettingsActivity extends BaseNekoXSettingsActivity { private final AbstractConfigCell largeAvatarInDrawerRow = cellGroup.appendCell(new ConfigCellSelectBox(null, NekoConfig.largeAvatarInDrawer, LocaleController.getString("valuesLargeAvatarInDrawer"), null)); private final AbstractConfigCell avatarBackgroundBlurRow = cellGroup.appendCell(new ConfigCellTextCheck(NekoConfig.avatarBackgroundBlur)); private final AbstractConfigCell avatarBackgroundDarkenRow = cellGroup.appendCell(new ConfigCellTextCheck(NekoConfig.avatarBackgroundDarken)); + private final AbstractConfigCell showSquareAvatarRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getShowSquareAvatar())); private final AbstractConfigCell hidePhoneRow = cellGroup.appendCell(new ConfigCellTextCheck(NekoConfig.hidePhone)); private final AbstractConfigCell divider0 = cellGroup.appendCell(new ConfigCellDivider()); diff --git a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt index afb2fa2950..21d225cb03 100644 --- a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt +++ b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt @@ -394,12 +394,6 @@ object NaConfig { ConfigItem.configTypeBool, false ) - val showForumAsNormalChat = - addConfig( - "ShowForumAsNormalChat", - ConfigItem.configTypeBool, - false - ) val chatDecoration = addConfig( "ChatDecoration", @@ -454,17 +448,23 @@ object NaConfig { ConfigItem.configTypeBool, false ) - val useLocalQuoteColorColor = + val useLocalQuoteColorData = addConfig( - "UseLocalQuoteColorColor", - ConfigItem.configTypeInt, - 0 + "useLocalQuoteColorData", + ConfigItem.configTypeString, + "" ) - val useLocalQuoteColorEmoji = + val showRecentOnlineStatus = addConfig( - "useLocalQuoteColorEmoji", - ConfigItem.configTypeLong, - 0L + "ShowRecentOnlineStatus", + ConfigItem.configTypeBool, + false + ) + val showSquareAvatar = + addConfig( + "ShowSquareAvatar", + ConfigItem.configTypeBool, + false ) private fun addConfig( diff --git a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/helper/PeerColorHelper.kt b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/helper/PeerColorHelper.kt index dd97ea4df4..44a549922a 100644 --- a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/helper/PeerColorHelper.kt +++ b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/helper/PeerColorHelper.kt @@ -1,15 +1,85 @@ package xyz.nextalone.nagram.helper +import com.google.gson.Gson +import org.telegram.tgnet.TLRPC import xyz.nextalone.nagram.NaConfig +data class LocalQuoteColorData ( + var colorId: Int?, + var emojiId: Long?, + var profileColorId: Int?, + var profileEmojiId: Long? +) + + object PeerColorHelper { + var loaded: Boolean = false + var data: LocalQuoteColorData? = null + + @JvmStatic + fun getColorId(user: TLRPC.User): Int? { + if (!NaConfig.useLocalQuoteColor.Bool()) return null + init() + if (user.self && data != null) { + return data!!.colorId + } + return null + } + + @JvmStatic + fun getEmojiId(user: TLRPC.User?): Long? { + if (!NaConfig.useLocalQuoteColor.Bool()) return null + init() + if (user != null && user.self && data != null) { + return data!!.emojiId + } + return null + } + + @JvmStatic + fun getProfileColorId(user: TLRPC.User): Int? { + if (!NaConfig.useLocalQuoteColor.Bool()) return null + init() + if (user.self && data != null) { + return data!!.profileColorId + } + return null + } + + @JvmStatic + fun getProfileEmojiId(user: TLRPC.User?): Long? { + if (!NaConfig.useLocalQuoteColor.Bool()) return null + init() + if (user != null && user.self && data != null) { + return data!!.profileEmojiId + } + return null + } + + @JvmStatic + fun init(force: Boolean = false) { + if (loaded && !force) return + loaded = true + try { + val gson = Gson() + data = gson.fromJson(NaConfig.useLocalQuoteColorData.String(), LocalQuoteColorData::class.java) + } catch (_: Exception) {} + } @JvmStatic - fun replaceColor(old: Int?): Int? { - if (NaConfig.useLocalQuoteColor.Bool()) { - return NaConfig.useLocalQuoteColorColor.Int() + fun apply(colorId: Int, emojiId: Long, profileColorId: Int, profileEmojiId: Long) { + if (!NaConfig.useLocalQuoteColor.Bool()) return + var localData = data + if (localData == null) { + localData = LocalQuoteColorData(colorId, emojiId, profileColorId, profileEmojiId) + } else { + localData.colorId = colorId + localData.emojiId = emojiId + localData.profileColorId = profileColorId + localData.profileEmojiId = profileEmojiId } - return old + NaConfig.useLocalQuoteColorData.setConfigString(Gson().toJson(localData)) + init(true) } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png new file mode 100644 index 0000000000..1f844a2736 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png new file mode 100644 index 0000000000..03b2d45ef7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png new file mode 100644 index 0000000000..2245861dc8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png new file mode 100644 index 0000000000..355c4f13f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png new file mode 100644 index 0000000000..808f9ae3ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png new file mode 100644 index 0000000000..709571fa61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_feature_color_name.png new file mode 100644 index 0000000000..662f51cafa 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 0000000000..dc32983922 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 0000000000..0f7e5f6281 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 0000000000..707a0f35e0 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 0000000000..3758211e17 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 0000000000..16e8585e1b 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 0000000000..aff27dbabe 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 0000000000..0b23197bc4 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 0000000000..daeb0abfd7 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 0000000000..1873851bb6 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 0000000000..ce511f8cf7 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 0000000000..0190535968 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 0000000000..ac87d66d33 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 0000000000..46c001119b 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/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story.png new file mode 100644 index 0000000000..c47e4e9e61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png new file mode 100644 index 0000000000..99bccfe6f4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png new file mode 100644 index 0000000000..be789e65a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png new file mode 100644 index 0000000000..6f5e67b253 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png new file mode 100644 index 0000000000..d40990d277 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_call_bluetooth.png new file mode 100644 index 0000000000..e467aa35d3 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 0000000000..846bd69498 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 0000000000..e0a9fd2740 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 0000000000..409f662ea1 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 0000000000..9f0fdec200 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-hdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_colors.png new file mode 100644 index 0000000000..1036f89206 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png new file mode 100644 index 0000000000..e803328fbb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png new file mode 100644 index 0000000000..d4deca8d7b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png new file mode 100644 index 0000000000..de4e490c91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png new file mode 100644 index 0000000000..d64b98a4b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png new file mode 100644 index 0000000000..8dc4d326de Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png new file mode 100644 index 0000000000..07bb83dbb6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png new file mode 100644 index 0000000000..af6140b39a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png new file mode 100644 index 0000000000..73c8be7f13 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_feature_color_name.png new file mode 100644 index 0000000000..49a4e707a1 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 0000000000..dd4933933f 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 0000000000..b43120dda8 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 0000000000..9ab59e359b 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 0000000000..b71a5e05a6 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 0000000000..07e4e8b6fc 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 0000000000..0952e8e4b8 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 0000000000..3db161145a 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 0000000000..aafa5eefa3 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 0000000000..2c8208d3f6 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 0000000000..02d9fa3e95 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 0000000000..2cecdc8566 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 0000000000..e8c64ff626 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 0000000000..a871596cfd 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/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story.png new file mode 100644 index 0000000000..14365619c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png new file mode 100644 index 0000000000..df8e932c5e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png new file mode 100644 index 0000000000..29916aec8e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png new file mode 100644 index 0000000000..efa599654f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png new file mode 100644 index 0000000000..dff98af839 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_call_bluetooth.png new file mode 100644 index 0000000000..dae338222d 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 0000000000..c4ed82f919 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 0000000000..c1a2ff8c95 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 0000000000..3075eb64f6 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 0000000000..8a16c35f2d 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-mdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_colors.png new file mode 100644 index 0000000000..a6abb3cc0d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png new file mode 100644 index 0000000000..4b8689ba05 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png new file mode 100644 index 0000000000..035182d87f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png new file mode 100644 index 0000000000..d33496c224 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png new file mode 100644 index 0000000000..2685bf33f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png new file mode 100644 index 0000000000..f80c8f39dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png new file mode 100644 index 0000000000..3b8ad4a6ee Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png new file mode 100644 index 0000000000..8efc78de49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png new file mode 100644 index 0000000000..44e726d83b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_feature_color_name.png new file mode 100644 index 0000000000..e0e0b64b21 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 0000000000..c323be6963 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 0000000000..1998d60f1f 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 0000000000..1ce9d9c8a6 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 0000000000..2bf1895d15 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 0000000000..6f7f647994 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 0000000000..4203ca32d6 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 0000000000..cb4008be77 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 0000000000..ea5f32b63e 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 0000000000..2c8ad96ea0 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 0000000000..ddec205892 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 0000000000..68b8b4279b 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 0000000000..ebe9271c2e 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 0000000000..475754e90e 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/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story.png new file mode 100644 index 0000000000..bd39b06b3e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png new file mode 100644 index 0000000000..9f47146735 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png new file mode 100644 index 0000000000..f2491c4130 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png new file mode 100644 index 0000000000..7e8c3c573e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png new file mode 100644 index 0000000000..fb85886d39 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_call_bluetooth.png new file mode 100644 index 0000000000..9453e9f6ee 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 0000000000..252f23fa0b 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 0000000000..80a9cd3cb8 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 0000000000..90e8453646 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 0000000000..88b012a680 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-xhdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_colors.png new file mode 100644 index 0000000000..4c3f94c910 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png new file mode 100644 index 0000000000..b4e6d2248b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png new file mode 100644 index 0000000000..ae3a4f79f0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png b/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png new file mode 100644 index 0000000000..b19cf84b35 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png new file mode 100644 index 0000000000..f8ddf1bd85 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png new file mode 100644 index 0000000000..d6367f3261 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/input_video_story_remove.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png new file mode 100644 index 0000000000..7072f83809 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/large_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png b/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png new file mode 100644 index 0000000000..6f541d8aa1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/media_repost.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png new file mode 100644 index 0000000000..9a2a0eebf8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_copy_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_name.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_feature_color_name.png new file mode 100644 index 0000000000..42c1824873 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 0000000000..e7bd4f1d09 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 0000000000..d330b2a1cf 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 0000000000..3ecd90676a 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 0000000000..f29163fb76 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 0000000000..5727755e4c 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 0000000000..3950e404e3 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 0000000000..07cdfec3d4 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 0000000000..9a7105fa91 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 0000000000..76661a8dca 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 0000000000..5fd55a426f 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 0000000000..c61144e183 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 0000000000..d939853aa6 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 0000000000..0e4a9ac8d9 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/mini_repost_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story.png new file mode 100644 index 0000000000..6eff47a6bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png new file mode 100644 index 0000000000..657125f357 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_repost_story2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png new file mode 100644 index 0000000000..bdb88fd40e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_likes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png new file mode 100644 index 0000000000..76d338c6f6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_stats_shares.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png new file mode 100644 index 0000000000..ab5f7e90e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_switch_lock.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_bluetooth.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_call_bluetooth.png new file mode 100644 index 0000000000..dba97c207e 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 0000000000..fb44e4cd1d 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 0000000000..6ca69d6746 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 0000000000..9ed27ff2b7 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 0000000000..cb7dc121d6 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-xxhdpi/premium_colors.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_colors.png new file mode 100644 index 0000000000..7b120b70bb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_colors.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png new file mode 100644 index 0000000000..f5a7aa28d4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png new file mode 100644 index 0000000000..4fa0ca759c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/premium_wallpaper.png differ diff --git a/TMessagesProj/src/main/res/drawable/icon_2_background.xml b/TMessagesProj/src/main/res/drawable/icon_2_background.xml index d1440713e5..279e6595ba 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 5a8cc155f0..be67c47904 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 424fc20ae4..0000000000 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 d00445b9dc..249080bb19 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 3e2c38cff4..b0d5d41e7a 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 72b85d15d6..0000000000 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 0000000000..314f0a65f7 --- /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 b65238aa66..0e4598e96e 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 b2ccb6d31a..b75253ac36 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 f89e3fc0aa..0000000000 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 0000000000..133636088f --- /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 9df3154c3b..25ea137141 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 7c2df592b1..430c084768 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 862664b5eb..0000000000 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 0000000000..353fba3a75 --- /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 2630ccb36b..749c55699f 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 deab3c4cbc..c0765ce063 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 6e3cfe2d8c..0000000000 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 0000000000..d5756c7525 --- /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 27feec4283..a2d43618a5 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 444b6f188d..4de8cca774 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 686a7d70e9..0000000000 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 0000000000..d3a1ae4cc9 --- /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 acbeff5e61..8afd524eb5 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 0000000000..eee84206d6 --- /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 0000000000..90a6ba022b --- /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 12649abb0f..0000000000 --- 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 0000000000..cbaa4c8bf9 --- /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 0000000000..5a24482b40 --- /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/stats.json b/TMessagesProj/src/main/res/raw/stats.json index cbba960997..c0ded68271 100644 --- a/TMessagesProj/src/main/res/raw/stats.json +++ b/TMessagesProj/src/main/res/raw/stats.json @@ -1 +1 @@ -{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":32,"w":512,"h":512,"nm":"Stats MAIN","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Column 1","sr":1,"ks":{"p":{"a":0,"k":[106,459.5,0]},"a":{"a":0,"k":[-150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":8,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-164.689,56.609],[-134.689,56.609],[-104.689,86.609],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-194.689,86.609]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":18,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-117.5],[-135,-117.5],[-105,-87.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-87.5]],"c":true}]},{"t":26,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Column 2","sr":1,"ks":{"p":{"a":0,"k":[256,459.5,0]},"a":{"a":0,"k":[0,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":12,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-45.5],[15,-45.5],[45,-15.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-15.5]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":21,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-233.5],[15,-233.5],[45,-203.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-203.5]],"c":true}]},{"t":29,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Column 3","sr":1,"ks":{"p":{"a":0,"k":[406,459.5,0]},"a":{"a":0,"k":[150,203.5,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":2,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]},{"i":{"x":0.78,"y":1},"o":{"x":0.7,"y":0},"t":14,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[134.289,-184.658],[164.289,-184.658],[194.289,-154.658],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[104.289,-154.658]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.4,"y":0},"t":23,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,29],[165,29],[195,59],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,59]],"c":true}]},{"t":31,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":49,"w":512,"h":512,"nm":"Stats Active 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Columns","sr":1,"ks":{"p":{"a":0,"k":[256,257,0]},"a":{"a":0,"k":[256,257,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106,459.5]},"a":{"a":0,"k":[-150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,459.5]},"a":{"a":0,"k":[0,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406,459.5]},"a":{"a":0,"k":[150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 3","bm":0,"hd":false}],"ip":0,"op":1,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Strokes","sr":1,"ks":{"p":{"a":0,"k":[256,248.776,0]},"a":{"a":0,"k":[256,248.776,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":8,"s":[{"i":[[-0.647,-0.34],[0,0],[0,2.573],[0,0],[0.647,0.34],[0,0],[0,-2.573],[0,0]],"o":[[0,0],[0.647,-0.34],[0,0],[0,-2.573],[0,0],[-0.647,0.34],[0,0],[0,2.573]],"v":[[-177.032,158],[-123.923,158],[-121.811,153.605],[-121.375,-6.535],[-123.487,-10.929],[-176.595,-10.929],[-178.707,-6.535],[-179.143,153.605]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[-0.535,-0.392],[0,0],[0,2.967],[0,0],[0.535,0.392],[0,0],[0,-2.967],[0,0]],"o":[[0,0],[0.535,-0.392],[0,0],[0,-2.967],[0,0],[-0.535,0.392],[0,0],[0,2.967]],"v":[[-172.43,171],[-128.497,171],[-126.75,165.933],[-126.982,-56.863],[-128.729,-61.929],[-172.661,-61.929],[-174.408,-56.863],[-174.176,165.933]],"c":true}]},{"t":23,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.578,0.382],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.578,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-174.176,168.209],[-126.732,168.209],[-124.846,163.264],[-124.846,-48.193],[-126.732,-53.138],[-174.175,-53.138],[-176.062,-48.193],[-176.062,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.5,-24.43],[-169.019,-66.827],[-133.164,-66.827],[-103.683,-24.193],[-103.065,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":8,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.361,-16.193],[-174,-58.827],[-126.128,-58.827],[-86.768,-16.193],[-87.157,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":15,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-214,-54.193],[-174.64,-96.827],[-126.768,-96.827],[-87.407,-54.193],[-87.157,163.264]],"c":true}]},{"t":23,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.75,-48.193],[-174.39,-90.827],[-126.518,-90.827],[-87.157,-48.193],[-87.157,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[105.546,313.535]},"a":{"a":0,"k":[-150.454,57.535]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":2,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[-0.645,-0.35],[0,0],[0,2.651],[0,0],[0.644,0.35],[0,0],[0,-2.651],[0,0]],"o":[[0,0],[0.644,-0.35],[0,0],[0,-2.651],[0,0],[-0.645,0.35],[0,0],[0,2.651]],"v":[[-26.504,155],[26.459,155],[28.565,150.472],[28.686,-131.919],[26.579,-136.447],[-26.384,-136.447],[-28.489,-131.919],[-28.61,150.472]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":17,"s":[{"i":[[-0.53,-0.391],[0,0],[0,2.957],[0,0],[0.53,0.39],[0,0],[0,-2.957],[0,0]],"o":[[0,0],[0.53,-0.391],[0,0],[0,-2.957],[0,0],[-0.53,0.39],[0,0],[0,2.957]],"v":[[-21.789,172],[21.768,172],[23.5,166.95],[23.271,-187.397],[21.539,-192.447],[-22.018,-192.447],[-23.75,-187.397],[-23.52,166.95]],"c":true}]},{"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.382],[0,0],[0,-2.895],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-23.722,168.209],[23.722,168.209],[25.608,163.264],[25.608,-177.711],[23.722,-182.656],[-23.722,-182.656],[-25.608,-177.711],[-25.608,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":2,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-47,-158.711],[-18.085,-201.344],[17.084,-201.344],[46,-158.711],[46.5,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":10,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.221,-144.711],[-23.861,-187.344],[24.011,-187.344],[63.371,-144.711],[63.296,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":17,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.546,-183.711],[-24.186,-226.344],[23.686,-226.344],[63.046,-183.711],[63.296,163.264]],"c":true}]},{"t":24,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.296,-177.711],[-23.936,-220.344],[23.936,-220.344],[63.296,-177.711],[63.296,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,248.776]},"a":{"a":0,"k":[0,-7.224]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":4,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[{"i":[[-0.603,-0.291],[0,0],[0,2.202],[0,0],[0.602,0.291],[0,0],[0,-2.202],[0,0]],"o":[[0,0],[0.602,-0.291],[0,0],[0,-2.202],[0,0],[-0.603,0.291],[0,0],[0,2.201]],"v":[[125.717,154],[175.175,154],[177.142,150.24],[177.548,62.589],[175.581,58.829],[126.123,58.829],[124.156,62.589],[123.75,150.24]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[-0.543,-0.402],[0,0],[0,3.042],[0,0],[0.542,0.402],[0,0],[0,-3.042],[0,0]],"o":[[0,0],[0.542,-0.402],[0,0],[0,-3.042],[0,0],[-0.543,0.402],[0,0],[0,3.041]],"v":[[128.165,172.329],[172.728,172.329],[174.5,167.133],[174.265,6.696],[172.493,1.5],[127.93,1.5],[126.158,6.696],[126.393,167.133]],"c":true}]},{"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.383],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.383],[0,0],[0,2.895]],"v":[[126.732,168.209],[174.176,168.209],[176.062,163.264],[176.062,16.565],[174.176,11.62],[126.732,11.62],[124.846,16.565],[124.846,163.264]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":4,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.68,38.837],[132.917,0.5],[167.262,0.5],[195.5,38.837],[195.773,166.059]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":12,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.548,49.565],[126.907,6.932],[174.779,6.932],[214.14,49.565],[213.75,163.264]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":18,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[86.908,10.565],[126.268,-32.068],[174.14,-32.068],[213.5,10.565],[213.75,163.264]],"c":true}]},{"t":24,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.158,16.565],[126.518,-26.068],[174.39,-26.068],[213.75,16.565],[213.75,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406.454,345.914]},"a":{"a":0,"k":[150.454,89.914]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 3","bm":0,"hd":false}],"ip":1,"op":24,"st":-4,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Columns 2","sr":1,"ks":{"p":{"a":0,"k":[256,257,0]},"a":{"a":0,"k":[256,257,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[-22.644,0],[0,0],[0,-16.681],[0,0],[22.644,0],[0,0],[0,16.681],[0,0]],"o":[[0,0],[22.644,0],[0,0],[0,16.681],[0,0],[-22.644,0],[0,0],[0,-16.681]],"v":[[-171,-92],[-130,-92],[-89,-51.297],[-89,171.797],[-130,205.5],[-171,205.5],[-212,171.797],[-212,-51.297]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-46.5],[-135,-46.5],[-105,-16.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-16.5]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-72.5],[-135,-72.5],[-105,-42.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-42.5]],"c":true}]},{"t":47,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-165,-66.5],[-135,-66.5],[-105,-36.5],[-105,173.5],[-135,203.5],[-165,203.5],[-195,173.5],[-195,-36.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[106,459.5]},"a":{"a":0,"k":[-150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[-22.46,0],[0,0],[0,-16.627],[0,0],[22.46,0],[0,0],[0,16.627],[0,0]],"o":[[0,0],[22.46,0],[0,0],[0,16.627],[0,0],[-22.46,0],[0,0],[0,-16.627]],"v":[[-20.333,-224.5],[20.333,-224.5],[61,-179.895],[61,171.395],[20.333,205],[-20.333,205],[-61,171.395],[-61,-179.895]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-181.5],[15,-181.5],[45,-151.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-151.5]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-207.5],[15,-207.5],[45,-177.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-177.5]],"c":true}]},{"t":48,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[-15,-201.5],[15,-201.5],[45,-171.5],[45,173.5],[15,203.5],[-15,203.5],[-45,173.5],[-45,-171.5]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle-","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,459.5]},"a":{"a":0,"k":[0,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[-23.012,0],[0,0],[0,-16.786],[0,0],[23.012,0],[0,0],[0,16.786],[0,0]],"o":[[0,0],[23.012,0],[0,0],[0,16.786],[0,0],[-23.012,0],[0,0],[0,-16.786]],"v":[[129.167,-25],[170.833,-25],[212.5,12.394],[212.5,172.606],[170.833,206.5],[129.167,206.5],[87.5,172.606],[87.5,12.394]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":37,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,11],[165,11],[195,41],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,41]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,-6],[165,-6],[195,24],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,24]],"c":true}]},{"t":48,"s":[{"i":[[-16.569,0],[0,0],[0,-16.569],[0,0],[16.569,0],[0,0],[0,16.569],[0,0]],"o":[[0,0],[16.569,0],[0,0],[0,16.569],[0,0],[-16.569,0],[0,0],[0,-16.569]],"v":[[135,1],[165,1],[195,31],[195,173.5],[165,203.5],[135,203.5],[105,173.5],[105,31]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle--","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406,459.5]},"a":{"a":0,"k":[150,203.5]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Column 3","bm":0,"hd":false}],"ip":35,"op":175,"st":55,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Strokes 2","sr":1,"ks":{"p":{"a":0,"k":[256,248.776,0]},"a":{"a":0,"k":[256,248.776,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.578,0.382],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.578,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-174.176,168.209],[-126.732,168.209],[-124.846,163.264],[-124.846,-48.193],[-126.732,-53.138],[-174.175,-53.138],[-176.062,-48.193],[-176.062,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[-0.003,0],[0,0],[0,0.004],[0,0],[0.003,0],[0,0],[0,-0.004],[0,0]],"o":[[0,0],[0.003,0],[0,0],[0,-0.004],[0,0],[-0.003,0],[0,0],[0,0.004]],"v":[[-151.356,67.674],[-151.074,67.674],[-151.062,67.668],[-151.063,67.403],[-151.075,67.397],[-151.357,67.397],[-151.368,67.403],[-151.368,67.668]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]},{"t":47,"s":[{"i":[[-0.019,-0.003],[0,0],[0,0.02],[0,0],[0.019,0.003],[0,0],[0,-0.02],[0,0]],"o":[[0,0],[0.019,-0.003],[0,0],[0,-0.02],[0,0],[-0.019,0.003],[0,0],[0,0.02]],"v":[[-151.81,79.8],[-150.25,79.8],[-150.188,79.765],[-150.193,78.306],[-150.255,78.271],[-151.815,78.271],[-151.877,78.306],[-151.872,79.765]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":24,"s":[{"i":[[21.704,0],[0,0],[0,23.508],[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.704,0],[0,0],[0,-23.508],[0,0],[21.704,0],[0,0],[0,23.508]],"v":[[-126.518,205.896],[-174.39,205.896],[-213.75,163.264],[-213.75,-48.193],[-174.39,-90.827],[-126.518,-90.827],[-87.157,-48.193],[-87.157,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":33,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.559,204.146],[-168.414,204.146],[-195.947,169.527],[-196.344,-5.43],[-168.863,-47.827],[-133.008,-47.827],[-103.527,-5.193],[-103.13,169.764]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.416,-36.68],[-168.935,-79.077],[-133.08,-79.077],[-103.599,-36.443],[-103.065,163.264]],"c":true}]},{"t":47,"s":[{"i":[[16.256,0],[0,0],[0,23.508],[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-16.256,0],[0,0],[0,-23.508],[0,0],[16.256,0],[0,0],[0,23.508]],"v":[[-132.546,205.896],[-168.401,205.896],[-195.882,163.027],[-196.5,-24.43],[-169.019,-66.827],[-133.164,-66.827],[-103.683,-24.193],[-103.065,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[105.546,313.535]},"a":{"a":0,"k":[-150.454,57.535]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.382],[0,0],[0,-2.895],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.382],[0,0],[0,2.896]],"v":[[-23.722,168.209],[23.722,168.209],[25.608,163.264],[25.608,-177.711],[23.722,-182.656],[-23.722,-182.656],[-25.608,-177.711],[-25.608,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[0.001,0],[0,0],[0,-0.001],[0,0],[-0.001,0],[0,0],[0,0.001],[0,0]],"o":[[0,0],[-0.001,0],[0,0],[0,0.001],[0,0],[0.001,0],[0,0],[0,-0.001]],"v":[[-0.563,51.745],[-0.623,51.745],[-0.625,51.746],[-0.625,51.807],[-0.623,51.808],[-0.563,51.808],[-0.561,51.807],[-0.561,51.746]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]},{"t":48,"s":[{"i":[[-0.045,-0.004],[0,0],[0,0.033],[0,0],[0.045,0.004],[0,0],[0,-0.033],[0,0]],"o":[[0,0],[0.045,-0.004],[0,0],[0,-0.033],[0,0],[-0.045,0.004],[0,0],[0,0.033]],"v":[[-2.5,72.75],[1.205,72.75],[1.353,72.694],[1.353,68.859],[1.205,68.803],[-2.5,68.803],[-2.647,68.859],[-2.647,72.694]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":26,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[23.936,205.896],[-23.936,205.896],[-63.296,163.264],[-63.296,-177.711],[-23.936,-220.344],[23.936,-220.344],[63.296,-177.711],[63.296,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.586,204.021],[-17.582,204.021],[-46.5,166.764],[-46.845,-139.711],[-17.929,-182.344],[17.24,-182.344],[46.156,-139.711],[46.5,166.764]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":41,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-46.916,-170.961],[-18,-213.594],[17.168,-213.594],[46.084,-170.961],[46.5,163.264]],"c":true}]},{"t":48,"s":[{"i":[[15.944,0],[0,0],[0,23.508],[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-15.944,0],[0,0],[0,-23.508],[0,0],[15.944,0],[0,0],[0,23.508]],"v":[[17.584,205.896],[-17.585,205.896],[-46.5,163.264],[-47,-158.711],[-18.085,-201.344],[17.084,-201.344],[46,-158.711],[46.5,163.264]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[256,248.776]},"a":{"a":0,"k":[0,-7.224]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[-0.578,-0.383],[0,0],[0,2.896],[0,0],[0.577,0.383],[0,0],[0,-2.896],[0,0]],"o":[[0,0],[0.577,-0.383],[0,0],[0,-2.896],[0,0],[-0.578,0.383],[0,0],[0,2.895]],"v":[[126.732,168.209],[174.176,168.209],[176.062,163.264],[176.062,16.565],[174.176,11.62],[126.732,11.62],[124.846,16.565],[124.846,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":36,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[150.095,92.397],[150.64,92.397],[150.662,92.318],[150.664,90.079],[150.642,90],[150.097,90],[150.075,90.079],[150.073,92.318]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]},{"t":48,"s":[{"i":[[-0.007,-0.006],[0,0],[0,0.046],[0,0],[0.007,0.006],[0,0],[0,-0.046],[0,0]],"o":[[0,0],[0.007,-0.006],[0,0],[0,-0.046],[0,0],[-0.007,0.006],[0,0],[0,0.046]],"v":[[149.999,80.897],[150.545,80.897],[150.566,80.818],[150.568,78.579],[150.547,78.5],[150.001,78.5],[149.979,78.579],[149.977,80.818]],"c":true}]}]},"nm":"Path 2","hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":28,"s":[{"i":[[21.703,0],[0,0],[0,23.508],[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0]],"o":[[0,0],[-21.703,0],[0,0],[0,-23.508],[0,0],[21.703,0],[0,0],[0,23.508]],"v":[[174.39,205.896],[126.518,205.896],[87.158,163.264],[87.158,16.565],[126.518,-26.068],[174.39,-26.068],[213.75,16.565],[213.75,163.264]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":36,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.836,47.837],[133.073,9.5],[167.418,9.5],[195.656,47.837],[195.773,166.059]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":42,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.672,203.896],[133.327,203.896],[104.976,168.309],[104.764,26.587],[133.001,-11.75],[167.346,-11.75],[195.584,26.587],[195.796,168.309]],"c":true}]},{"t":48,"s":[{"i":[[15.57,0],[0,0],[0,23.345],[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0]],"o":[[0,0],[-15.57,0],[0,0],[0,-23.345],[0,0],[15.57,0],[0,0],[0,23.345]],"v":[[167.648,205.896],[133.304,205.896],[104.953,166.059],[104.68,38.837],[132.917,0.5],[167.262,0.5],[195.5,38.837],[195.773,166.059]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[406.454,345.914]},"a":{"a":0,"k":[150.454,89.914]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Слой 3","bm":0,"hd":false}],"ip":24,"op":35,"st":20,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/story_repost.json b/TMessagesProj/src/main/res/raw/story_repost.json new file mode 100644 index 0000000000..673fc165dd --- /dev/null +++ b/TMessagesProj/src/main/res/raw/story_repost.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":36,"w":512,"h":512,"nm":"Repost Story 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":14.678,"s":[105,105,100]},{"t":32.7421875,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Big Path 4","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[0.5,0,0]},"a":{"a":0,"k":[0.5,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,27.658],[0,0],[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0]],"o":[[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0],[0,0],[0,27.658],[0,0]],"v":[[-75.799,100.158],[-125.878,50.079],[-125.878,-50.079],[-75.799,-100.158],[76.799,-100.158],[126.878,-50.079],[126.878,50.079],[76.799,100.158]],"c":true}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[13.2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.162,"s":[19]},{"t":20.322265625,"s":[13.2]}]},"e":{"a":0,"k":51.2},"o":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":20.322,"s":[196]},{"t":35,"s":[180]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":35},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-18","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 4","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.9],"y":[1]},"o":{"x":[0.199],"y":[0.138]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.1],"y":[0]},"t":9.033,"s":[115]},{"t":17,"s":[180]}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[94.281,-100.367,0],"to":[23.779,4.847,0],"ti":[0,-27.658,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4.516,"s":[124.378,-55.579,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9.033,"s":[126.878,50.079,0],"to":[0,27.658,0],"ti":[27.658,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11.291,"s":[76.799,100.158,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":16.936,"s":[-96.281,100.367,0],"to":[0.093,-0.023,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20.322,"s":[-126.031,100.617,0],"to":[0,0,0],"ti":[0,0,0]},{"t":35,"s":[-93.281,100.367,0]}]},"a":{"a":0,"k":[94.281,-100.367,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,2.327],[0,0],[-6.02,0],[-1.873,-1.38],[0,0],[3.571,-4.846],[0.881,-0.649],[0,0],[3.571,4.846]],"o":[[0,0],[0,-6.02],[2.327,0],[0,0],[4.846,3.571],[-0.649,0.881],[0,0],[-4.846,3.571],[-1.38,-1.873]],"v":[[49.121,-49.879],[49.121,-150.855],[60.021,-161.755],[66.486,-159.63],[135.006,-109.142],[137.315,-93.901],[135.006,-91.592],[66.486,-41.104],[51.246,-43.413]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-19","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Big Path 3","parent":1,"sr":1,"ks":{"p":{"a":0,"k":[0.5,0,0]},"a":{"a":0,"k":[0.5,0,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,27.658],[0,0],[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0]],"o":[[-27.658,0],[0,0],[0,-27.658],[0,0],[27.658,0],[0,0],[0,27.658],[0,0]],"v":[[-75.799,100.158],[-125.878,50.079],[-125.878,-50.079],[-75.799,-100.158],[76.799,-100.158],[126.878,-50.079],[126.878,50.079],[76.799,100.158]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":35},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[13.2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.162,"s":[19]},{"t":20.322265625,"s":[13.2]}]},"e":{"a":0,"k":51.2},"o":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[180]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":20.322,"s":[376]},{"t":35,"s":[360]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-18","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Arrow 3","parent":1,"sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.9],"y":[1]},"o":{"x":[0.199],"y":[0.138]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.1],"y":[0]},"t":9.033,"s":[115]},{"t":17,"s":[180]}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-93.281,100.367,0],"to":[0,0,0],"ti":[0,23.658,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4.516,"s":[-124.878,57.079,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9.033,"s":[-125.878,-55.079,0],"to":[0,-27.658,0],"ti":[-27.658,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11.291,"s":[-75.799,-100.158,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":16.936,"s":[94.281,-100.367,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":20.322,"s":[128.281,-100.367,0],"to":[0,0,0],"ti":[-0.217,0.091,0]},{"t":35,"s":[94.281,-100.367,0]}]},"a":{"a":0,"k":[-93.281,100.367,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,-2.327],[0,0],[6.02,0],[1.873,1.38],[0,0],[-3.571,4.846],[-0.881,0.649],[0,0],[-3.571,-4.846]],"o":[[0,0],[0,6.02],[-2.327,0],[0,0],[-4.846,-3.571],[0.649,-0.881],[0,0],[4.846,-3.571],[1.38,1.873]],"v":[[-48.121,49.879],[-48.121,150.855],[-59.021,161.755],[-65.486,159.63],[-134.006,109.142],[-136.315,93.901],[-134.006,91.592],[-65.486,41.104],[-50.246,43.413]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Path-19","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/thanos_fragment.glsl b/TMessagesProj/src/main/res/raw/thanos_fragment.glsl new file mode 100644 index 0000000000..0e9afc1d97 --- /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 0000000000..b7822055a6 --- /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/transcribe.json b/TMessagesProj/src/main/res/raw/transcribe.json new file mode 100644 index 0000000000..5065c247dc --- /dev/null +++ b/TMessagesProj/src/main/res/raw/transcribe.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Comp 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Intro Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":4,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":6,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":7,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":8,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":9,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":10,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":12,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":13,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":14,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":16,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":17,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":19,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":20,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":21,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":22,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":23,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":25,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":26,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":27,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":29,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":31,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":32,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":34,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":36,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":39,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":40,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":41,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":42,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":43,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":45,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":46,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":47,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":48,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":49,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":51,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":53,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":54,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":55,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":56,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":57,"s":[0]},{"i":{"x":[0.833],"y":[0.929]},"o":{"x":[0.167],"y":[0]},"t":58,"s":[0]},{"i":{"x":[0.833],"y":[0.327]},"o":{"x":[0.167],"y":[0.083]},"t":59,"s":[0]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.095]},"t":60,"s":[0.855]},{"i":{"x":[0.833],"y":[0.867]},"o":{"x":[0.167],"y":[0.133]},"t":61,"s":[6.909]},{"i":{"x":[0.833],"y":[0.736]},"o":{"x":[0.167],"y":[0.223]},"t":62,"s":[17.098]},{"i":{"x":[0.833],"y":[0.832]},"o":{"x":[0.167],"y":[0.122]},"t":63,"s":[23.179]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.165]},"t":64,"s":[36.342]},{"i":{"x":[0.833],"y":[0.762]},"o":{"x":[0.167],"y":[0.256]},"t":65,"s":[49.777]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.128]},"t":66,"s":[56.275]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.18]},"t":67,"s":[68.354]},{"i":{"x":[0.833],"y":[0.778]},"o":{"x":[0.167],"y":[0.277]},"t":68,"s":[78.788]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":69,"s":[83.289]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.197]},"t":70,"s":[90.78]},{"i":{"x":[0.833],"y":[0.802]},"o":{"x":[0.167],"y":[0.308]},"t":71,"s":[96.275]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.144]},"t":72,"s":[98.315]},{"i":{"x":[0.833],"y":[0.905]},"o":{"x":[0.167],"y":[0.261]},"t":73,"s":[101.11]},{"i":{"x":[0.833],"y":[1.079]},"o":{"x":[0.167],"y":[0.663]},"t":74,"s":[102.418]},{"i":{"x":[0.833],"y":[0.664]},"o":{"x":[0.167],"y":[0.04]},"t":75,"s":[102.606]},{"i":{"x":[0.833],"y":[0.86]},"o":{"x":[0.167],"y":[0.111]},"t":76,"s":[102.24]},{"i":{"x":[0.833],"y":[0.724]},"o":{"x":[0.167],"y":[0.207]},"t":77,"s":[101.129]},{"i":{"x":[0.833],"y":[0.826]},"o":{"x":[0.167],"y":[0.119]},"t":78,"s":[100.379]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.16]},"t":79,"s":[98.643]},{"i":{"x":[0.833],"y":[0.757]},"o":{"x":[0.167],"y":[0.25]},"t":80,"s":[96.764]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":81,"s":[95.824]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":82,"s":[94.027]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.271]},"t":83,"s":[92.42]},{"i":{"x":[0.833],"y":[0.853]},"o":{"x":[0.167],"y":[0.132]},"t":84,"s":[91.707]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.192]},"t":85,"s":[90.488]},{"i":{"x":[0.833],"y":[0.794]},"o":{"x":[0.167],"y":[0.297]},"t":86,"s":[89.551]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.14]},"t":87,"s":[89.186]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.23]},"t":88,"s":[88.651]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.411]},"t":89,"s":[88.347]},{"i":{"x":[0.833],"y":[1.177]},"o":{"x":[0.167],"y":[0.289]},"t":90,"s":[88.27]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.057]},"t":91,"s":[88.239]},{"i":{"x":[0.833],"y":[0.703]},"o":{"x":[0.167],"y":[0.18]},"t":92,"s":[88.337]},{"i":{"x":[0.833],"y":[0.819]},"o":{"x":[0.167],"y":[0.116]},"t":93,"s":[88.421]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.154]},"t":94,"s":[88.638]},{"i":{"x":[0.833],"y":[0.752]},"o":{"x":[0.167],"y":[0.243]},"t":95,"s":[88.893]},{"i":{"x":[0.833],"y":[0.839]},"o":{"x":[0.167],"y":[0.126]},"t":96,"s":[89.025]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.173]},"t":97,"s":[89.287]},{"i":{"x":[0.833],"y":[0.77]},"o":{"x":[0.167],"y":[0.267]},"t":98,"s":[89.529]},{"i":{"x":[0.833],"y":[0.85]},"o":{"x":[0.167],"y":[0.131]},"t":99,"s":[89.64]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.188]},"t":100,"s":[89.834]},{"i":{"x":[0.833],"y":[0.788]},"o":{"x":[0.167],"y":[0.29]},"t":101,"s":[89.989]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.137]},"t":102,"s":[90.051]},{"i":{"x":[0.833],"y":[0.891]},"o":{"x":[0.167],"y":[0.214]},"t":103,"s":[90.148]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.353]},"t":104,"s":[90.21]},{"i":{"x":[0.833],"y":[0.933]},"o":{"x":[0.167],"y":[0.171]},"t":105,"s":[90.229]},{"i":{"x":[0.833],"y":[0.727]},"o":{"x":[0.167],"y":[-0.345]},"t":106,"s":[90.247]},{"i":{"x":[0.833],"y":[0.656]},"o":{"x":[0.167],"y":[0.12]},"t":107,"s":[90.243]},{"i":{"x":[0.833],"y":[0.807]},"o":{"x":[0.167],"y":[0.11]},"t":108,"s":[90.235]},{"i":{"x":[0.833],"y":[0.871]},"o":{"x":[0.167],"y":[0.147]},"t":109,"s":[90.21]},{"i":{"x":[0.833],"y":[0.746]},"o":{"x":[0.167],"y":[0.235]},"t":110,"s":[90.177]},{"i":{"x":[0.833],"y":[0.836]},"o":{"x":[0.167],"y":[0.124]},"t":111,"s":[90.159]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.17]},"t":112,"s":[90.122]},{"i":{"x":[0.833],"y":[0.766]},"o":{"x":[0.167],"y":[0.262]},"t":113,"s":[90.086]},{"i":{"x":[0.833],"y":[0.848]},"o":{"x":[0.167],"y":[0.13]},"t":114,"s":[90.069]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.184]},"t":115,"s":[90.039]},{"i":{"x":[0.833],"y":[0.783]},"o":{"x":[0.167],"y":[0.283]},"t":116,"s":[90.014]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.135]},"t":117,"s":[90.004]},{"i":{"x":[0.833],"y":[0.888]},"o":{"x":[0.167],"y":[0.205]},"t":118,"s":[89.987]},{"i":{"x":[0.833],"y":[0.816]},"o":{"x":[0.167],"y":[0.326]},"t":119,"s":[89.975]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.153]},"t":120,"s":[89.971]},{"i":{"x":[0.833],"y":[0.947]},"o":{"x":[0.167],"y":[0.406]},"t":121,"s":[89.967]},{"i":{"x":[0.833],"y":[0.45]},"o":{"x":[0.167],"y":[-0.145]},"t":122,"s":[89.965]},{"i":{"x":[0.833],"y":[0.783]},"o":{"x":[0.167],"y":[0.098]},"t":123,"s":[89.966]},{"i":{"x":[0.833],"y":[0.816]},"o":{"x":[0.167],"y":[0.135]},"t":124,"s":[89.968]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.152]},"t":125,"s":[89.972]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.241]},"t":126,"s":[89.977]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":127,"s":[89.98]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.172]},"t":128,"s":[89.985]},{"i":{"x":[0.833],"y":[0.769]},"o":{"x":[0.167],"y":[0.265]},"t":129,"s":[89.99]},{"i":{"x":[0.833],"y":[0.849]},"o":{"x":[0.167],"y":[0.13]},"t":130,"s":[89.992]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.186]},"t":131,"s":[89.996]},{"i":{"x":[0.833],"y":[0.786]},"o":{"x":[0.167],"y":[0.287]},"t":132,"s":[89.999]},{"i":{"x":[0.833],"y":[0.862]},"o":{"x":[0.167],"y":[0.137]},"t":133,"s":[90.001]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.211]},"t":134,"s":[90.003]},{"i":{"x":[0.833],"y":[0.829]},"o":{"x":[0.167],"y":[0.342]},"t":135,"s":[90.004]},{"i":{"x":[0.833],"y":[0.915]},"o":{"x":[0.167],"y":[0.162]},"t":136,"s":[90.004]},{"i":{"x":[0.833],"y":[2.343]},"o":{"x":[0.167],"y":[5.161]},"t":137,"s":[90.005]},{"i":{"x":[0.833],"y":[0.624]},"o":{"x":[0.167],"y":[0.078]},"t":138,"s":[90.005]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.107]},"t":139,"s":[90.005]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.143]},"t":140,"s":[90.004]},{"i":{"x":[0.833],"y":[0.744]},"o":{"x":[0.167],"y":[0.232]},"t":141,"s":[90.004]},{"i":{"x":[0.833],"y":[0.835]},"o":{"x":[0.167],"y":[0.123]},"t":142,"s":[90.003]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.168]},"t":143,"s":[90.003]},{"i":{"x":[0.833],"y":[0.765]},"o":{"x":[0.167],"y":[0.26]},"t":144,"s":[90.002]},{"i":{"x":[0.833],"y":[0.847]},"o":{"x":[0.167],"y":[0.129]},"t":145,"s":[90.001]},{"i":{"x":[0.833],"y":[0.882]},"o":{"x":[0.167],"y":[0.183]},"t":146,"s":[90.001]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.281]},"t":147,"s":[90]},{"i":{"x":[0.833],"y":[0.858]},"o":{"x":[0.167],"y":[0.135]},"t":148,"s":[90]},{"i":{"x":[0.833],"y":[0.887]},"o":{"x":[0.167],"y":[0.202]},"t":149,"s":[90]},{"i":{"x":[0.833],"y":[0.812]},"o":{"x":[0.167],"y":[0.32]},"t":150,"s":[90]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.167],"y":[0.149]},"t":151,"s":[89.999]},{"i":{"x":[0.833],"y":[0.925]},"o":{"x":[0.167],"y":[0.331]},"t":152,"s":[89.999]},{"i":{"x":[0.833],"y":[-0.019]},"o":{"x":[0.167],"y":[-0.747]},"t":153,"s":[89.999]},{"i":{"x":[0.833],"y":[0.767]},"o":{"x":[0.167],"y":[0.091]},"t":154,"s":[89.999]},{"i":{"x":[0.833],"y":[0.866]},"o":{"x":[0.167],"y":[0.13]},"t":155,"s":[89.999]},{"i":{"x":[0.833],"y":[0.734]},"o":{"x":[0.167],"y":[0.221]},"t":156,"s":[89.999]},{"i":{"x":[0.833],"y":[0.831]},"o":{"x":[0.167],"y":[0.121]},"t":157,"s":[89.999]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.164]},"t":158,"s":[90]},{"i":{"x":[0.833],"y":[0.761]},"o":{"x":[0.167],"y":[0.255]},"t":159,"s":[90]},{"i":{"x":[0.833],"y":[0.844]},"o":{"x":[0.167],"y":[0.128]},"t":160,"s":[90]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.179]},"t":161,"s":[90]},{"i":{"x":[0.833],"y":[0.777]},"o":{"x":[0.167],"y":[0.276]},"t":162,"s":[90]},{"i":{"x":[0.833],"y":[0.855]},"o":{"x":[0.167],"y":[0.133]},"t":163,"s":[90]},{"i":{"x":[0.833],"y":[0.885]},"o":{"x":[0.167],"y":[0.196]},"t":164,"s":[90]},{"i":{"x":[0.833],"y":[0.801]},"o":{"x":[0.167],"y":[0.306]},"t":165,"s":[90]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.143]},"t":166,"s":[90]},{"i":{"x":[0.833],"y":[0.902]},"o":{"x":[0.167],"y":[0.254]},"t":167,"s":[90]},{"i":{"x":[0.833],"y":[1.006]},"o":{"x":[0.167],"y":[0.569]},"t":168,"s":[90]},{"i":{"x":[0.833],"y":[0.592]},"o":{"x":[0.167],"y":[0.006]},"t":169,"s":[90]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.105]},"t":170,"s":[90]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.203]},"t":171,"s":[90]},{"i":{"x":[0.833],"y":[0.825]},"o":{"x":[0.167],"y":[0.119]},"t":172,"s":[90]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.159]},"t":173,"s":[90]},{"i":{"x":[0.833],"y":[0.756]},"o":{"x":[0.167],"y":[0.249]},"t":174,"s":[90]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.127]},"t":175,"s":[90]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":176,"s":[90]},{"i":{"x":[0.833],"y":[0.773]},"o":{"x":[0.167],"y":[0.271]},"t":177,"s":[90]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.132]},"t":178,"s":[90]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.191]},"t":179,"s":[90]},{"t":180,"s":[90]}],"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[150,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":0,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":2,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":3,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":4,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":5,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":6,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":7,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":8,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":9,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":10,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":11,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":12,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":13,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":14,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":15,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":16,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":17,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":18,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":19,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":20,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":21,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":22,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":23,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":24,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":25,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":26,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":27,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":28,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":29,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":30,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":31,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":32,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":33,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":34,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":35,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":36,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":37,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":38,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":39,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":40,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":41,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":42,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":43,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":44,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":45,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":46,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":47,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":48,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":49,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":50,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":51,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":52,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":53,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":54,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":55,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":56,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":57,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.98,0.98,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":58,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.327,0.327,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.083,0.083,0]},"t":59,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.776,0.776,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.095,0.095,0]},"t":60,"s":[170.91,170.91,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":61,"s":[172.632,172.632,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.736,0.736,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.223,0.223,0]},"t":62,"s":[175.53,175.53,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":63,"s":[177.26,177.26,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.876,0.876,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.165,0.165,0]},"t":64,"s":[181.004,181.004,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.762,0.762,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":65,"s":[184.826,184.826,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.845,0.845,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":66,"s":[186.674,186.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.881,0.881,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":67,"s":[190.109,190.109,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.277,0.277,0]},"t":68,"s":[193.077,193.077,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.924,0.924,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":69,"s":[194.358,194.358,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.52,0.52,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.907,-0.907,0]},"t":70,"s":[196.245,196.245,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.641,0.641,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.101,0.101,0]},"t":71,"s":[196.086,196.086,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.804,0.804,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.109,0.109,0]},"t":72,"s":[195.331,195.331,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.871,0.871,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.145,0.145,0]},"t":73,"s":[192.834,192.834,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.745,0.745,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.234,0.234,0]},"t":74,"s":[189.462,189.462,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.836,0.836,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.124,0.124,0]},"t":75,"s":[187.594,187.594,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.169,0.169,0]},"t":76,"s":[183.741,183.741,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.766,0.766,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":77,"s":[179.989,179.989,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.847,0.847,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":78,"s":[178.227,178.227,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.183,0.183,0]},"t":79,"s":[175.034,175.034,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.782,0.782,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.282,0.282,0]},"t":80,"s":[172.369,172.369,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.859,0.859,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":81,"s":[171.251,171.251,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.203,0.203,0]},"t":82,"s":[169.447,169.447,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.814,0.814,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.322,0.322,0]},"t":83,"s":[168.195,168.195,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.892,0.892,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.151,0.151,0]},"t":84,"s":[167.758,167.758,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.934,0.934,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.36,0.36,0]},"t":85,"s":[167.22,167.22,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.307,0.307,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.328,-0.328,0]},"t":86,"s":[167.057,167.057,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.776,0.776,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.095,0.095,0]},"t":87,"s":[167.09,167.09,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":88,"s":[167.331,167.331,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.736,0.736,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.223,0.223,0]},"t":89,"s":[167.738,167.738,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":90,"s":[167.981,167.981,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.876,0.876,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.165,0.165,0]},"t":91,"s":[168.509,168.509,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.762,0.762,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.256,0.256,0]},"t":92,"s":[169.048,169.048,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.845,0.845,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.128,0.128,0]},"t":93,"s":[169.309,169.309,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.881,0.881,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":94,"s":[169.794,169.794,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.778,0.778,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.276,0.276,0]},"t":95,"s":[170.213,170.213,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.855,0.855,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":96,"s":[170.394,170.394,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.886,0.886,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.197,0.197,0]},"t":97,"s":[170.695,170.695,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.802,0.802,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.308,0.308,0]},"t":98,"s":[170.916,170.916,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.144,0.144,0]},"t":99,"s":[170.999,170.999,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.904,0.904,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":100,"s":[171.111,171.111,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.07,1.07,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.651,0.651,0]},"t":101,"s":[171.164,171.164,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.658,0.658,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.038,0.038,0]},"t":102,"s":[171.172,171.172,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.86,0.86,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.11,0.11,0]},"t":103,"s":[171.158,171.158,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.723,0.723,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.207,0.207,0]},"t":104,"s":[171.114,171.114,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.826,0.826,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.119,0.119,0]},"t":105,"s":[171.084,171.084,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.875,0.875,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.16,0.16,0]},"t":106,"s":[171.014,171.014,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.757,0.757,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.25,0.25,0]},"t":107,"s":[170.939,170.939,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.842,0.842,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.127,0.127,0]},"t":108,"s":[170.901,170.901,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.176,0.176,0]},"t":109,"s":[170.829,170.829,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.774,0.774,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.271,0.271,0]},"t":110,"s":[170.764,170.764,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.853,0.853,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":111,"s":[170.736,170.736,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.192,0.192,0]},"t":112,"s":[170.687,170.687,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.297,0.297,0]},"t":113,"s":[170.649,170.649,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.869,0.869,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":114,"s":[170.634,170.634,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.895,0.895,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.23,0.23,0]},"t":115,"s":[170.613,170.613,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.41,0.41,0]},"t":116,"s":[170.6,170.6,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.161,1.161,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.281,0.281,0]},"t":117,"s":[170.597,170.597,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.844,0.844,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.055,0.055,0]},"t":118,"s":[170.596,170.596,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.702,0.702,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.179,0.179,0]},"t":119,"s":[170.6,170.6,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.819,0.819,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.116,0.116,0]},"t":120,"s":[170.603,170.603,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.154,0.154,0]},"t":121,"s":[170.612,170.612,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.752,0.752,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.243,0.243,0]},"t":122,"s":[170.622,170.622,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.839,0.839,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":123,"s":[170.627,170.627,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.844,0.844,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.173,0.173,0]},"t":124,"s":[170.638,170.638,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.179,0.179,0]},"t":125,"s":[170.648,170.648,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.777,0.777,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.275,0.275,0]},"t":126,"s":[170.656,170.656,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.854,0.854,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":127,"s":[170.66,170.66,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.885,0.885,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.195,0.195,0]},"t":128,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.799,0.799,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.304,0.304,0]},"t":129,"s":[170.671,170.671,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.874,0.874,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.142,0.142,0]},"t":130,"s":[170.673,170.673,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.9,0.9,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.247,0.247,0]},"t":131,"s":[170.675,170.675,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.962,0.962,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.513,0.513,0]},"t":132,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.436,0.436,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.07,-0.07,0]},"t":133,"s":[170.677,170.677,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.857,0.857,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.098,0.098,0]},"t":134,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.718,0.718,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.199,0.199,0]},"t":135,"s":[170.676,170.676,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.824,0.824,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.118,0.118,0]},"t":136,"s":[170.675,170.675,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.874,0.874,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.158,0.158,0]},"t":137,"s":[170.674,170.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.756,0.756,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.248,0.248,0]},"t":138,"s":[170.672,170.672,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.841,0.841,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":139,"s":[170.672,170.672,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.879,0.879,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.175,0.175,0]},"t":140,"s":[170.67,170.67,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.773,0.773,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.27,0.27,0]},"t":141,"s":[170.669,170.669,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.852,0.852,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":142,"s":[170.668,170.668,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.19,0.19,0]},"t":143,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.792,0.792,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.294,0.294,0]},"t":144,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.139,0.139,0]},"t":145,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.894,0.894,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.224,0.224,0]},"t":146,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.862,0.862,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.384,0.384,0]},"t":147,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.012,1.012,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.209,0.209,0]},"t":148,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.831,0.831,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.011,0.011,0]},"t":149,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.691,0.691,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.164,0.164,0]},"t":150,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.816,0.816,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.114,0.114,0]},"t":151,"s":[170.665,170.665,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.152,0.152,0]},"t":152,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.75,0.75,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.241,0.241,0]},"t":153,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.838,0.838,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":154,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,0]},"t":155,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.769,0.769,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.265,0.265,0]},"t":156,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.849,0.849,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.13,0.13,0]},"t":157,"s":[170.666,170.666,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.883,0.883,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.186,0.186,0]},"t":158,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.786,0.786,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.287,0.287,0]},"t":159,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.862,0.862,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.137,0.137,0]},"t":160,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.89,0.89,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.211,0.211,0]},"t":161,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.828,0.828,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.341,0.341,0]},"t":162,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.915,0.915,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.162,0.162,0]},"t":163,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.822,1.822,1]},"o":{"x":[0.167,0.167,0.167],"y":[3.388,3.388,0]},"t":164,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.622,0.622,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.076,0.076,0]},"t":165,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.801,0.801,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.107,0.107,0]},"t":166,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.87,0.87,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.143,0.143,0]},"t":167,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.743,0.743,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.232,0.232,0]},"t":168,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.835,0.835,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.123,0.123,0]},"t":169,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.168,0.168,0]},"t":170,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.765,0.765,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.26,0.26,0]},"t":171,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.847,0.847,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":172,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.183,0.183,0]},"t":173,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.781,0.781,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.281,0.281,0]},"t":174,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.858,0.858,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":175,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.887,0.887,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.202,0.202,0]},"t":176,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.811,0.811,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.319,0.319,0]},"t":177,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.149,0.149,0]},"t":178,"s":[170.667,170.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.328,0.328,0]},"t":179,"s":[170.667,170.667,100]},{"t":180,"s":[170.667,170.667,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,120],[255,180]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":44,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,107.5],[255,192.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.6,"y":0},"t":64,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[255,132.5],[255,167.5]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[225,140],[225,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[50]},{"t":26,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[50]},{"t":26,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.306,0.306]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":69,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":70,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.705,0.705]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":71,"s":[101.609,101.609]},{"i":{"x":[0.833,0.833],"y":[0.818,0.818]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":72,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":73,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[0.242,0.242]},"t":74,"s":[109.01,109.01]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":75,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":76,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[0.267,0.267]},"t":77,"s":[117.647,117.647]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":78,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.907,0.907]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":79,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.278,1.278]},"o":{"x":[0.167,0.167],"y":[0.785,0.785]},"t":80,"s":[123.58,123.58]},{"i":{"x":[0.833,0.833],"y":[0.702,0.702]},"o":{"x":[0.167,0.167],"y":[0.064,0.064]},"t":81,"s":[123.796,123.796]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":82,"s":[122.86,122.86]},{"i":{"x":[0.833,0.833],"y":[0.721,0.721]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":83,"s":[120.447,120.447]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":84,"s":[118.825,118.825]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":85,"s":[115.024,115.024]},{"i":{"x":[0.833,0.833],"y":[0.756,0.756]},"o":{"x":[0.167,0.167],"y":[0.248,0.248]},"t":86,"s":[110.83,110.83]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":87,"s":[108.704,108.704]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":88,"s":[104.601,104.601]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":89,"s":[100.909,100.909]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":90,"s":[99.281,99.281]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":91,"s":[96.542,96.542]},{"i":{"x":[0.833,0.833],"y":[0.814,0.814]},"o":{"x":[0.167,0.167],"y":[0.317,0.317]},"t":92,"s":[94.549,94.549]},{"i":{"x":[0.833,0.833],"y":[0.897,0.897]},"o":{"x":[0.167,0.167],"y":[0.151,0.151]},"t":93,"s":[93.837,93.837]},{"i":{"x":[0.833,0.833],"y":[0.961,0.961]},"o":{"x":[0.167,0.167],"y":[0.43,0.43]},"t":94,"s":[92.96,92.96]},{"i":{"x":[0.833,0.833],"y":[0.484,0.484]},"o":{"x":[0.167,0.167],"y":[-0.073,-0.073]},"t":95,"s":[92.749,92.749]},{"i":{"x":[0.833,0.833],"y":[0.781,0.781]},"o":{"x":[0.167,0.167],"y":[0.099,0.099]},"t":96,"s":[92.861,92.861]},{"i":{"x":[0.833,0.833],"y":[0.867,0.867]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":97,"s":[93.444,93.444]},{"i":{"x":[0.833,0.833],"y":[0.734,0.734]},"o":{"x":[0.167,0.167],"y":[0.222,0.222]},"t":98,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":99,"s":[94.963,94.963]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.164,0.164]},"t":100,"s":[96.212,96.212]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":101,"s":[97.507,97.507]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":102,"s":[98.139,98.139]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":103,"s":[99.32,99.32]},{"i":{"x":[0.833,0.833],"y":[0.783,0.783]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":104,"s":[100.336,100.336]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":105,"s":[100.768,100.768]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.208,0.208]},"t":106,"s":[101.462,101.462]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.346,0.346]},"t":107,"s":[101.926,101.926]},{"i":{"x":[0.833,0.833],"y":[0.945,0.945]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":108,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[-0.16,-0.16]},"t":109,"s":[102.21,102.21]},{"i":{"x":[0.833,0.833],"y":[0.657,0.657]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":110,"s":[102.163,102.163]},{"i":{"x":[0.833,0.833],"y":[0.805,0.805]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":111,"s":[102.082,102.082]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":112,"s":[101.829,101.829]},{"i":{"x":[0.833,0.833],"y":[0.743,0.743]},"o":{"x":[0.167,0.167],"y":[0.233,0.233]},"t":113,"s":[101.49,101.49]},{"i":{"x":[0.833,0.833],"y":[0.835,0.835]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":114,"s":[101.301,101.301]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":115,"s":[100.908,100.908]},{"i":{"x":[0.833,0.833],"y":[0.766,0.766]},"o":{"x":[0.167,0.167],"y":[0.26,0.26]},"t":116,"s":[100.52,100.52]},{"i":{"x":[0.833,0.833],"y":[0.848,0.848]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":117,"s":[100.337,100.337]},{"i":{"x":[0.833,0.833],"y":[0.883,0.883]},"o":{"x":[0.167,0.167],"y":[0.185,0.185]},"t":118,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.79,0.79]},"o":{"x":[0.167,0.167],"y":[0.288,0.288]},"t":119,"s":[99.735,99.735]},{"i":{"x":[0.833,0.833],"y":[0.868,0.868]},"o":{"x":[0.167,0.167],"y":[0.138,0.138]},"t":120,"s":[99.625,99.625]},{"i":{"x":[0.833,0.833],"y":[0.896,0.896]},"o":{"x":[0.167,0.167],"y":[0.226,0.226]},"t":121,"s":[99.457,99.457]},{"i":{"x":[0.833,0.833],"y":[0.898,0.898]},"o":{"x":[0.167,0.167],"y":[0.416,0.416]},"t":122,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[1.583,1.583]},"o":{"x":[0.167,0.167],"y":[0.457,0.457]},"t":123,"s":[99.335,99.335]},{"i":{"x":[0.833,0.833],"y":[0.763,0.763]},"o":{"x":[0.167,0.167],"y":[0.073,0.073]},"t":124,"s":[99.329,99.329]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":125,"s":[99.373,99.373]},{"i":{"x":[0.833,0.833],"y":[0.73,0.73]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":126,"s":[99.454,99.454]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":127,"s":[99.505,99.505]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":128,"s":[99.618,99.618]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":129,"s":[99.738,99.738]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":130,"s":[99.798,99.798]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":131,"s":[99.911,99.911]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":132,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":133,"s":[100.052,100.052]},{"i":{"x":[0.833,0.833],"y":[0.889,0.889]},"o":{"x":[0.167,0.167],"y":[0.204,0.204]},"t":134,"s":[100.122,100.122]},{"i":{"x":[0.833,0.833],"y":[0.827,0.827]},"o":{"x":[0.167,0.167],"y":[0.332,0.332]},"t":135,"s":[100.17,100.17]},{"i":{"x":[0.833,0.833],"y":[0.919,0.919]},"o":{"x":[0.167,0.167],"y":[0.161,0.161]},"t":136,"s":[100.187,100.187]},{"i":{"x":[0.833,0.833],"y":[-0.283,-0.283]},"o":{"x":[0.167,0.167],"y":[-3.463,-3.463]},"t":137,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.621,0.621]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":138,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.798,0.798]},"o":{"x":[0.167,0.167],"y":[0.107,0.107]},"t":139,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":140,"s":[100.177,100.177]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.229,0.229]},"t":141,"s":[100.147,100.147]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":142,"s":[100.13,100.13]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":143,"s":[100.094,100.094]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.258,0.258]},"t":144,"s":[100.057,100.057]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":145,"s":[100.04,100.04]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":146,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.787,0.787]},"o":{"x":[0.167,0.167],"y":[0.285,0.285]},"t":147,"s":[99.981,99.981]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":148,"s":[99.97,99.97]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":149,"s":[99.953,99.953]},{"i":{"x":[0.833,0.833],"y":[0.867,0.867]},"o":{"x":[0.167,0.167],"y":[0.379,0.379]},"t":150,"s":[99.942,99.942]},{"i":{"x":[0.833,0.833],"y":[1.057,1.057]},"o":{"x":[0.167,0.167],"y":[0.222,0.222]},"t":151,"s":[99.939,99.939]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.034,0.034]},"t":152,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":153,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":154,"s":[99.943,99.943]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":155,"s":[99.952,99.952]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.238,0.238]},"t":156,"s":[99.962,99.962]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":157,"s":[99.967,99.967]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":158,"s":[99.978,99.978]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.264,0.264]},"t":159,"s":[99.989,99.989]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":160,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":161,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.295,0.295]},"t":162,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":163,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.244,0.244]},"t":164,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.008,1.008]},"o":{"x":[0.167,0.167],"y":[0.546,0.546]},"t":165,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.575,0.575]},"o":{"x":[0.167,0.167],"y":[0.008,0.008]},"t":166,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.104,0.104]},"t":167,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.715,0.715]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":168,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":169,"s":[100.016,100.016]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":170,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.754,0.754]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":171,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":172,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":173,"s":[100.004,100.004]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.27,0.27]},"t":174,"s":[100.001,100.001]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":175,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.195,0.195]},"t":176,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.309,0.309]},"t":177,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.323,0.323]},"t":179,"s":[99.994,99.994]},{"t":180,"s":[99.994,99.994]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,100],[220,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,87.5],[220,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,112.5],[220,187.5]],"c":false}]},{"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[220,100],[220,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":24,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[50]},{"t":24,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":16,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,70],[185,230]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,57.5],[185,242.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":56,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,82.5],[185,217.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":76,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[185,70],[185,230]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[175,70],[175,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[50]},{"t":22,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[50]},{"t":22,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.679,0.679]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.615,0.615]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":65,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.797,0.797]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":66,"s":[100.744,100.744]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":67,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":68,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":69,"s":[107.272,107.272]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":70,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":71,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":72,"s":[116.035,116.035]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":73,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.328,0.328]},"t":74,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.343,1.343]},"o":{"x":[0.167,0.167],"y":[0.35,0.35]},"t":75,"s":[122.653,122.653]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.067,0.067]},"t":76,"s":[122.932,122.932]},{"i":{"x":[0.833,0.833],"y":[0.699,0.699]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":77,"s":[121.508,121.508]},{"i":{"x":[0.833,0.833],"y":[0.816,0.816]},"o":{"x":[0.167,0.167],"y":[0.115,0.115]},"t":78,"s":[120.285,120.285]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.153,0.153]},"t":79,"s":[117.086,117.086]},{"i":{"x":[0.833,0.833],"y":[0.749,0.749]},"o":{"x":[0.167,0.167],"y":[0.24,0.24]},"t":80,"s":[113.237,113.237]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":81,"s":[111.193,111.193]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.172,0.172]},"t":82,"s":[107.092,107.092]},{"i":{"x":[0.833,0.833],"y":[0.771,0.771]},"o":{"x":[0.167,0.167],"y":[0.265,0.265]},"t":83,"s":[103.224,103.224]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":84,"s":[101.454,101.454]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":85,"s":[98.354,98.354]},{"i":{"x":[0.833,0.833],"y":[0.799,0.799]},"o":{"x":[0.167,0.167],"y":[0.299,0.299]},"t":86,"s":[95.934,95.934]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":87,"s":[94.998,94.998]},{"i":{"x":[0.833,0.833],"y":[0.906,0.906]},"o":{"x":[0.167,0.167],"y":[0.259,0.259]},"t":88,"s":[93.675,93.675]},{"i":{"x":[0.833,0.833],"y":[1.191,1.191]},"o":{"x":[0.167,0.167],"y":[0.762,0.762]},"t":89,"s":[93.047,93.047]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.058,0.058]},"t":90,"s":[92.97,92.97]},{"i":{"x":[0.833,0.833],"y":[0.86,0.86]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":91,"s":[93.224,93.224]},{"i":{"x":[0.833,0.833],"y":[0.72,0.72]},"o":{"x":[0.167,0.167],"y":[0.206,0.206]},"t":92,"s":[93.92,93.92]},{"i":{"x":[0.833,0.833],"y":[0.824,0.824]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":93,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.158,0.158]},"t":94,"s":[95.508,95.508]},{"i":{"x":[0.833,0.833],"y":[0.755,0.755]},"o":{"x":[0.167,0.167],"y":[0.247,0.247]},"t":95,"s":[96.744,96.744]},{"i":{"x":[0.833,0.833],"y":[0.841,0.841]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":96,"s":[97.373,97.373]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":97,"s":[98.589,98.589]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":98,"s":[99.686,99.686]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":99,"s":[100.171,100.171]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.197,0.197]},"t":100,"s":[100.99,100.99]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.315,0.315]},"t":101,"s":[101.589,101.589]},{"i":{"x":[0.833,0.833],"y":[0.895,0.895]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":102,"s":[101.804,101.804]},{"i":{"x":[0.833,0.833],"y":[0.952,0.952]},"o":{"x":[0.167,0.167],"y":[0.4,0.4]},"t":103,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.448,0.448]},"o":{"x":[0.167,0.167],"y":[-0.115,-0.115]},"t":104,"s":[102.143,102.143]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.098,0.098]},"t":105,"s":[102.113,102.113]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":106,"s":[101.947,101.947]},{"i":{"x":[0.833,0.833],"y":[0.733,0.733]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":107,"s":[101.671,101.671]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":108,"s":[101.504,101.504]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":109,"s":[101.136,101.136]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":110,"s":[100.753,100.753]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":111,"s":[100.566,100.566]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":112,"s":[100.216,100.216]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":113,"s":[99.913,99.913]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":114,"s":[99.784,99.784]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":115,"s":[99.576,99.576]},{"i":{"x":[0.833,0.833],"y":[0.836,0.836]},"o":{"x":[0.167,0.167],"y":[0.343,0.343]},"t":116,"s":[99.436,99.436]},{"i":{"x":[0.833,0.833],"y":[0.939,0.939]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":117,"s":[99.391,99.391]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[-0.226,-0.226]},"t":118,"s":[99.348,99.348]},{"i":{"x":[0.833,0.833],"y":[0.652,0.652]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":119,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.804,0.804]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":120,"s":[99.383,99.383]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.145,0.145]},"t":121,"s":[99.456,99.456]},{"i":{"x":[0.833,0.833],"y":[0.742,0.742]},"o":{"x":[0.167,0.167],"y":[0.232,0.232]},"t":122,"s":[99.555,99.555]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":123,"s":[99.61,99.61]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":124,"s":[99.727,99.727]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":125,"s":[99.841,99.841]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":126,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":127,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.194,0.194]},"t":128,"s":[100.075,100.075]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[0.308,0.308]},"t":129,"s":[100.136,100.136]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":130,"s":[100.159,100.159]},{"i":{"x":[0.833,0.833],"y":[0.923,0.923]},"o":{"x":[0.167,0.167],"y":[0.312,0.312]},"t":131,"s":[100.188,100.188]},{"i":{"x":[0.833,0.833],"y":[-0.267,-0.267]},"o":{"x":[0.167,0.167],"y":[-0.96,-0.96]},"t":132,"s":[100.199,100.199]},{"i":{"x":[0.833,0.833],"y":[0.758,0.758]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":133,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":134,"s":[100.186,100.186]},{"i":{"x":[0.833,0.833],"y":[0.729,0.729]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":135,"s":[100.163,100.163]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":136,"s":[100.148,100.148]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":137,"s":[100.114,100.114]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.251,0.251]},"t":138,"s":[100.079,100.079]},{"i":{"x":[0.833,0.833],"y":[0.843,0.843]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":139,"s":[100.061,100.061]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":140,"s":[100.028,100.028]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":141,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":142,"s":[99.986,99.986]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":143,"s":[99.965,99.965]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.33,0.33]},"t":144,"s":[99.95,99.95]},{"i":{"x":[0.833,0.833],"y":[0.915,0.915]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":145,"s":[99.945,99.945]},{"i":{"x":[0.833,0.833],"y":[2.34,2.34]},"o":{"x":[0.167,0.167],"y":[4.745,4.745]},"t":146,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.612,0.612]},"o":{"x":[0.167,0.167],"y":[0.078,0.078]},"t":147,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":148,"s":[99.941,99.941]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":149,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":150,"s":[99.956,99.956]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":151,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":152,"s":[99.972,99.972]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":153,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":154,"s":[99.988,99.988]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":155,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.786,0.786]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":156,"s":[100.005,100.005]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":157,"s":[100.009,100.009]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":158,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.863,0.863]},"o":{"x":[0.167,0.167],"y":[0.374,0.374]},"t":159,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.032,1.032]},"o":{"x":[0.167,0.167],"y":[0.212,0.212]},"t":160,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.023,0.023]},"t":161,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.685,0.685]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":162,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.812,0.812]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":163,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":164,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.237,0.237]},"t":165,"s":[100.011,100.011]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":166,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":167,"s":[100.007,100.007]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":168,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":169,"s":[100.002,100.002]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":170,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":171,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":172,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.901,0.901]},"o":{"x":[0.167,0.167],"y":[0.241,0.241]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.987,0.987]},"o":{"x":[0.167,0.167],"y":[0.521,0.521]},"t":174,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.523,0.523]},"o":{"x":[0.167,0.167],"y":[-0.016,-0.016]},"t":175,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.101,0.101]},"t":176,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.713,0.713]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":177,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.156,0.156]},"t":179,"s":[99.996,99.996]},{"t":180,"s":[99.997,99.997]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,100],[150,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":32,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,87.5],[150,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":52,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,112.5],[150,187.5]],"c":false}]},{"t":72,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150,100],[150,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[50]},{"t":20,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[50]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":8,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,70],[115,230]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,57.5],[115,242.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":48,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,82.5],[115,217.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":68,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115,70],[115,230]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[125,70],[125,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[50]},{"t":18,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[50]},{"t":18,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":60,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":61,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":62,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":63,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.679,0.679]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.615,0.615]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":65,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.797,0.797]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":66,"s":[100.744,100.744]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":67,"s":[102.741,102.741]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":68,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":69,"s":[107.272,107.272]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":70,"s":[110.792,110.792]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":71,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":72,"s":[116.035,116.035]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":73,"s":[119.15,119.15]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.328,0.328]},"t":74,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[1.343,1.343]},"o":{"x":[0.167,0.167],"y":[0.35,0.35]},"t":75,"s":[122.653,122.653]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.067,0.067]},"t":76,"s":[122.932,122.932]},{"i":{"x":[0.833,0.833],"y":[0.699,0.699]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":77,"s":[121.508,121.508]},{"i":{"x":[0.833,0.833],"y":[0.816,0.816]},"o":{"x":[0.167,0.167],"y":[0.115,0.115]},"t":78,"s":[120.285,120.285]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.153,0.153]},"t":79,"s":[117.086,117.086]},{"i":{"x":[0.833,0.833],"y":[0.749,0.749]},"o":{"x":[0.167,0.167],"y":[0.24,0.24]},"t":80,"s":[113.237,113.237]},{"i":{"x":[0.833,0.833],"y":[0.838,0.838]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":81,"s":[111.193,111.193]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.172,0.172]},"t":82,"s":[107.092,107.092]},{"i":{"x":[0.833,0.833],"y":[0.771,0.771]},"o":{"x":[0.167,0.167],"y":[0.265,0.265]},"t":83,"s":[103.224,103.224]},{"i":{"x":[0.833,0.833],"y":[0.852,0.852]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":84,"s":[101.454,101.454]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.19,0.19]},"t":85,"s":[98.354,98.354]},{"i":{"x":[0.833,0.833],"y":[0.799,0.799]},"o":{"x":[0.167,0.167],"y":[0.299,0.299]},"t":86,"s":[95.934,95.934]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":87,"s":[94.998,94.998]},{"i":{"x":[0.833,0.833],"y":[0.906,0.906]},"o":{"x":[0.167,0.167],"y":[0.259,0.259]},"t":88,"s":[93.675,93.675]},{"i":{"x":[0.833,0.833],"y":[1.191,1.191]},"o":{"x":[0.167,0.167],"y":[0.762,0.762]},"t":89,"s":[93.047,93.047]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.058,0.058]},"t":90,"s":[92.97,92.97]},{"i":{"x":[0.833,0.833],"y":[0.86,0.86]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":91,"s":[93.224,93.224]},{"i":{"x":[0.833,0.833],"y":[0.72,0.72]},"o":{"x":[0.167,0.167],"y":[0.206,0.206]},"t":92,"s":[93.92,93.92]},{"i":{"x":[0.833,0.833],"y":[0.824,0.824]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":93,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.158,0.158]},"t":94,"s":[95.508,95.508]},{"i":{"x":[0.833,0.833],"y":[0.755,0.755]},"o":{"x":[0.167,0.167],"y":[0.247,0.247]},"t":95,"s":[96.744,96.744]},{"i":{"x":[0.833,0.833],"y":[0.841,0.841]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":96,"s":[97.373,97.373]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.176,0.176]},"t":97,"s":[98.589,98.589]},{"i":{"x":[0.833,0.833],"y":[0.776,0.776]},"o":{"x":[0.167,0.167],"y":[0.272,0.272]},"t":98,"s":[99.686,99.686]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":99,"s":[100.171,100.171]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.197,0.197]},"t":100,"s":[100.99,100.99]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.315,0.315]},"t":101,"s":[101.589,101.589]},{"i":{"x":[0.833,0.833],"y":[0.895,0.895]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":102,"s":[101.804,101.804]},{"i":{"x":[0.833,0.833],"y":[0.952,0.952]},"o":{"x":[0.167,0.167],"y":[0.4,0.4]},"t":103,"s":[102.072,102.072]},{"i":{"x":[0.833,0.833],"y":[0.448,0.448]},"o":{"x":[0.167,0.167],"y":[-0.115,-0.115]},"t":104,"s":[102.143,102.143]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.098,0.098]},"t":105,"s":[102.113,102.113]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":106,"s":[101.947,101.947]},{"i":{"x":[0.833,0.833],"y":[0.733,0.733]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":107,"s":[101.671,101.671]},{"i":{"x":[0.833,0.833],"y":[0.83,0.83]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":108,"s":[101.504,101.504]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":109,"s":[101.136,101.136]},{"i":{"x":[0.833,0.833],"y":[0.761,0.761]},"o":{"x":[0.167,0.167],"y":[0.254,0.254]},"t":110,"s":[100.753,100.753]},{"i":{"x":[0.833,0.833],"y":[0.845,0.845]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":111,"s":[100.566,100.566]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.18,0.18]},"t":112,"s":[100.216,100.216]},{"i":{"x":[0.833,0.833],"y":[0.782,0.782]},"o":{"x":[0.167,0.167],"y":[0.279,0.279]},"t":113,"s":[99.913,99.913]},{"i":{"x":[0.833,0.833],"y":[0.861,0.861]},"o":{"x":[0.167,0.167],"y":[0.135,0.135]},"t":114,"s":[99.784,99.784]},{"i":{"x":[0.833,0.833],"y":[0.89,0.89]},"o":{"x":[0.167,0.167],"y":[0.207,0.207]},"t":115,"s":[99.576,99.576]},{"i":{"x":[0.833,0.833],"y":[0.836,0.836]},"o":{"x":[0.167,0.167],"y":[0.343,0.343]},"t":116,"s":[99.436,99.436]},{"i":{"x":[0.833,0.833],"y":[0.939,0.939]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":117,"s":[99.391,99.391]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[-0.226,-0.226]},"t":118,"s":[99.348,99.348]},{"i":{"x":[0.833,0.833],"y":[0.652,0.652]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":119,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.804,0.804]},"o":{"x":[0.167,0.167],"y":[0.11,0.11]},"t":120,"s":[99.383,99.383]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.145,0.145]},"t":121,"s":[99.456,99.456]},{"i":{"x":[0.833,0.833],"y":[0.742,0.742]},"o":{"x":[0.167,0.167],"y":[0.232,0.232]},"t":122,"s":[99.555,99.555]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":123,"s":[99.61,99.61]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":124,"s":[99.727,99.727]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":125,"s":[99.841,99.841]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.269,0.269]},"t":126,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":127,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.194,0.194]},"t":128,"s":[100.075,100.075]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[0.308,0.308]},"t":129,"s":[100.136,100.136]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.146,0.146]},"t":130,"s":[100.159,100.159]},{"i":{"x":[0.833,0.833],"y":[0.923,0.923]},"o":{"x":[0.167,0.167],"y":[0.312,0.312]},"t":131,"s":[100.188,100.188]},{"i":{"x":[0.833,0.833],"y":[-0.267,-0.267]},"o":{"x":[0.167,0.167],"y":[-0.96,-0.96]},"t":132,"s":[100.199,100.199]},{"i":{"x":[0.833,0.833],"y":[0.758,0.758]},"o":{"x":[0.167,0.167],"y":[0.089,0.089]},"t":133,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":134,"s":[100.186,100.186]},{"i":{"x":[0.833,0.833],"y":[0.729,0.729]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":135,"s":[100.163,100.163]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":136,"s":[100.148,100.148]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":137,"s":[100.114,100.114]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.251,0.251]},"t":138,"s":[100.079,100.079]},{"i":{"x":[0.833,0.833],"y":[0.843,0.843]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":139,"s":[100.061,100.061]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":140,"s":[100.028,100.028]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":141,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":142,"s":[99.986,99.986]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.203,0.203]},"t":143,"s":[99.965,99.965]},{"i":{"x":[0.833,0.833],"y":[0.825,0.825]},"o":{"x":[0.167,0.167],"y":[0.33,0.33]},"t":144,"s":[99.95,99.95]},{"i":{"x":[0.833,0.833],"y":[0.915,0.915]},"o":{"x":[0.167,0.167],"y":[0.159,0.159]},"t":145,"s":[99.945,99.945]},{"i":{"x":[0.833,0.833],"y":[2.34,2.34]},"o":{"x":[0.167,0.167],"y":[4.745,4.745]},"t":146,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.612,0.612]},"o":{"x":[0.167,0.167],"y":[0.078,0.078]},"t":147,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.796,0.796]},"o":{"x":[0.167,0.167],"y":[0.106,0.106]},"t":148,"s":[99.941,99.941]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":149,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.739,0.739]},"o":{"x":[0.167,0.167],"y":[0.228,0.228]},"t":150,"s":[99.956,99.956]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":151,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":152,"s":[99.972,99.972]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.257,0.257]},"t":153,"s":[99.983,99.983]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":154,"s":[99.988,99.988]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":155,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.786,0.786]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":156,"s":[100.005,100.005]},{"i":{"x":[0.833,0.833],"y":[0.864,0.864]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":157,"s":[100.009,100.009]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.216,0.216]},"t":158,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.863,0.863]},"o":{"x":[0.167,0.167],"y":[0.374,0.374]},"t":159,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.032,1.032]},"o":{"x":[0.167,0.167],"y":[0.212,0.212]},"t":160,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.023,0.023]},"t":161,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.685,0.685]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":162,"s":[100.018,100.018]},{"i":{"x":[0.833,0.833],"y":[0.812,0.812]},"o":{"x":[0.167,0.167],"y":[0.113,0.113]},"t":163,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":164,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.237,0.237]},"t":165,"s":[100.011,100.011]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":166,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":167,"s":[100.007,100.007]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":168,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":169,"s":[100.002,100.002]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":170,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.294,0.294]},"t":171,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":172,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.901,0.901]},"o":{"x":[0.167,0.167],"y":[0.241,0.241]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.987,0.987]},"o":{"x":[0.167,0.167],"y":[0.521,0.521]},"t":174,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.523,0.523]},"o":{"x":[0.167,0.167],"y":[-0.016,-0.016]},"t":175,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.856,0.856]},"o":{"x":[0.167,0.167],"y":[0.101,0.101]},"t":176,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.713,0.713]},"o":{"x":[0.167,0.167],"y":[0.198,0.198]},"t":177,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.117,0.117]},"t":178,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.156,0.156]},"t":179,"s":[99.996,99.996]},{"t":180,"s":[99.997,99.997]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,100],[80,200]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":24,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,87.5],[80,212.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":44,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,112.5],[80,187.5]],"c":false}]},{"t":64,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[80,100],[80,200]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[100]},{"t":75,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":65,"s":[20]},{"t":75,"s":[10]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[50]},{"t":16,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[50]},{"t":16,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,120],[45,180]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,107.5],[45,192.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.6,"y":0},"t":40,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,132.5],[45,167.5]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0},"t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[45,120],[45,180]],"c":false}]},{"t":100,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[75,70],[75,230]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[50]},{"t":14,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[50]},{"t":14,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[150,150],"ix":2},"a":{"a":0,"k":[150,150],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":1,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":2,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":3,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":4,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":5,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":6,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":7,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":8,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":9,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":11,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":12,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":16,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":17,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":18,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":19,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":20,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":21,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":22,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":25,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":26,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":27,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":28,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":29,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":31,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":32,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":33,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":34,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":35,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":37,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":38,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":39,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":40,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":41,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":42,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":43,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":44,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":46,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":47,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":48,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":49,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":50,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":51,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":52,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":53,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":54,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":55,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":56,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":57,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.984,0.984]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":58,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.306,0.306]},"o":{"x":[0.167,0.167],"y":[0.083,0.083]},"t":59,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.77,0.77]},"o":{"x":[0.167,0.167],"y":[0.095,0.095]},"t":60,"s":[100.193,100.193]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":61,"s":[101.609,101.609]},{"i":{"x":[0.833,0.833],"y":[0.731,0.731]},"o":{"x":[0.167,0.167],"y":[0.219,0.219]},"t":62,"s":[104.093,104.093]},{"i":{"x":[0.833,0.833],"y":[0.829,0.829]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":63,"s":[105.618,105.618]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.163,0.163]},"t":64,"s":[109.01,109.01]},{"i":{"x":[0.833,0.833],"y":[0.76,0.76]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":65,"s":[112.579,112.579]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":66,"s":[114.336,114.336]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.179,0.179]},"t":67,"s":[117.647,117.647]},{"i":{"x":[0.833,0.833],"y":[0.794,0.794]},"o":{"x":[0.167,0.167],"y":[0.278,0.278]},"t":68,"s":[120.526,120.526]},{"i":{"x":[0.833,0.833],"y":[0.919,0.919]},"o":{"x":[0.167,0.167],"y":[0.14,0.14]},"t":69,"s":[121.762,121.762]},{"i":{"x":[0.833,0.833],"y":[-0.477,-0.477]},"o":{"x":[0.167,0.167],"y":[-3.646,-3.646]},"t":70,"s":[123.58,123.58]},{"i":{"x":[0.833,0.833],"y":[0.621,0.621]},"o":{"x":[0.167,0.167],"y":[0.088,0.088]},"t":71,"s":[123.54,123.54]},{"i":{"x":[0.833,0.833],"y":[0.798,0.798]},"o":{"x":[0.167,0.167],"y":[0.107,0.107]},"t":72,"s":[122.86,122.86]},{"i":{"x":[0.833,0.833],"y":[0.869,0.869]},"o":{"x":[0.167,0.167],"y":[0.142,0.142]},"t":73,"s":[120.447,120.447]},{"i":{"x":[0.833,0.833],"y":[0.74,0.74]},"o":{"x":[0.167,0.167],"y":[0.229,0.229]},"t":74,"s":[116.999,116.999]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.123,0.123]},"t":75,"s":[115.024,115.024]},{"i":{"x":[0.833,0.833],"y":[0.877,0.877]},"o":{"x":[0.167,0.167],"y":[0.166,0.166]},"t":76,"s":[110.83,110.83]},{"i":{"x":[0.833,0.833],"y":[0.764,0.764]},"o":{"x":[0.167,0.167],"y":[0.258,0.258]},"t":77,"s":[106.616,106.616]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.129,0.129]},"t":78,"s":[104.601,104.601]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":79,"s":[100.909,100.909]},{"i":{"x":[0.833,0.833],"y":[0.787,0.787]},"o":{"x":[0.167,0.167],"y":[0.284,0.284]},"t":80,"s":[97.822,97.822]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":81,"s":[96.542,96.542]},{"i":{"x":[0.833,0.833],"y":[0.893,0.893]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":82,"s":[94.549,94.549]},{"i":{"x":[0.833,0.833],"y":[0.866,0.866]},"o":{"x":[0.167,0.167],"y":[0.378,0.378]},"t":83,"s":[93.31,93.31]},{"i":{"x":[0.833,0.833],"y":[1.055,1.055]},"o":{"x":[0.167,0.167],"y":[0.221,0.221]},"t":84,"s":[92.96,92.96]},{"i":{"x":[0.833,0.833],"y":[0.834,0.834]},"o":{"x":[0.167,0.167],"y":[0.033,0.033]},"t":85,"s":[92.749,92.749]},{"i":{"x":[0.833,0.833],"y":[0.688,0.688]},"o":{"x":[0.167,0.167],"y":[0.168,0.168]},"t":86,"s":[93.098,93.098]},{"i":{"x":[0.833,0.833],"y":[0.813,0.813]},"o":{"x":[0.167,0.167],"y":[0.114,0.114]},"t":87,"s":[93.444,93.444]},{"i":{"x":[0.833,0.833],"y":[0.872,0.872]},"o":{"x":[0.167,0.167],"y":[0.15,0.15]},"t":88,"s":[94.393,94.393]},{"i":{"x":[0.833,0.833],"y":[0.747,0.747]},"o":{"x":[0.167,0.167],"y":[0.238,0.238]},"t":89,"s":[95.575,95.575]},{"i":{"x":[0.833,0.833],"y":[0.837,0.837]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":90,"s":[96.212,96.212]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.17,0.17]},"t":91,"s":[97.507,97.507]},{"i":{"x":[0.833,0.833],"y":[0.769,0.769]},"o":{"x":[0.167,0.167],"y":[0.263,0.263]},"t":92,"s":[98.747,98.747]},{"i":{"x":[0.833,0.833],"y":[0.85,0.85]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":93,"s":[99.32,99.32]},{"i":{"x":[0.833,0.833],"y":[0.884,0.884]},"o":{"x":[0.167,0.167],"y":[0.188,0.188]},"t":94,"s":[100.336,100.336]},{"i":{"x":[0.833,0.833],"y":[0.795,0.795]},"o":{"x":[0.167,0.167],"y":[0.295,0.295]},"t":95,"s":[101.144,101.144]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.141,0.141]},"t":96,"s":[101.462,101.462]},{"i":{"x":[0.833,0.833],"y":[0.902,0.902]},"o":{"x":[0.167,0.167],"y":[0.244,0.244]},"t":97,"s":[101.926,101.926]},{"i":{"x":[0.833,0.833],"y":[1.006,1.006]},"o":{"x":[0.167,0.167],"y":[0.544,0.544]},"t":98,"s":[102.166,102.166]},{"i":{"x":[0.833,0.833],"y":[0.572,0.572]},"o":{"x":[0.167,0.167],"y":[0.006,0.006]},"t":99,"s":[102.21,102.21]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.103,0.103]},"t":100,"s":[102.163,102.163]},{"i":{"x":[0.833,0.833],"y":[0.715,0.715]},"o":{"x":[0.167,0.167],"y":[0.199,0.199]},"t":101,"s":[101.969,101.969]},{"i":{"x":[0.833,0.833],"y":[0.822,0.822]},"o":{"x":[0.167,0.167],"y":[0.118,0.118]},"t":102,"s":[101.829,101.829]},{"i":{"x":[0.833,0.833],"y":[0.874,0.874]},"o":{"x":[0.167,0.167],"y":[0.157,0.157]},"t":103,"s":[101.49,101.49]},{"i":{"x":[0.833,0.833],"y":[0.754,0.754]},"o":{"x":[0.167,0.167],"y":[0.245,0.245]},"t":104,"s":[101.106,101.106]},{"i":{"x":[0.833,0.833],"y":[0.84,0.84]},"o":{"x":[0.167,0.167],"y":[0.126,0.126]},"t":105,"s":[100.908,100.908]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.174,0.174]},"t":106,"s":[100.52,100.52]},{"i":{"x":[0.833,0.833],"y":[0.774,0.774]},"o":{"x":[0.167,0.167],"y":[0.27,0.27]},"t":107,"s":[100.165,100.165]},{"i":{"x":[0.833,0.833],"y":[0.854,0.854]},"o":{"x":[0.167,0.167],"y":[0.132,0.132]},"t":108,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.886,0.886]},"o":{"x":[0.167,0.167],"y":[0.195,0.195]},"t":109,"s":[99.735,99.735]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.309,0.309]},"t":110,"s":[99.532,99.532]},{"i":{"x":[0.833,0.833],"y":[0.888,0.888]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":111,"s":[99.457,99.457]},{"i":{"x":[0.833,0.833],"y":[0.927,0.927]},"o":{"x":[0.167,0.167],"y":[0.322,0.322]},"t":112,"s":[99.359,99.359]},{"i":{"x":[0.833,0.833],"y":[0.032,0.032]},"o":{"x":[0.167,0.167],"y":[-0.607,-0.607]},"t":113,"s":[99.325,99.325]},{"i":{"x":[0.833,0.833],"y":[0.763,0.763]},"o":{"x":[0.167,0.167],"y":[0.091,0.091]},"t":114,"s":[99.329,99.329]},{"i":{"x":[0.833,0.833],"y":[0.865,0.865]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":115,"s":[99.373,99.373]},{"i":{"x":[0.833,0.833],"y":[0.73,0.73]},"o":{"x":[0.167,0.167],"y":[0.217,0.217]},"t":116,"s":[99.454,99.454]},{"i":{"x":[0.833,0.833],"y":[0.828,0.828]},"o":{"x":[0.167,0.167],"y":[0.12,0.12]},"t":117,"s":[99.505,99.505]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.162,0.162]},"t":118,"s":[99.618,99.618]},{"i":{"x":[0.833,0.833],"y":[0.759,0.759]},"o":{"x":[0.167,0.167],"y":[0.252,0.252]},"t":119,"s":[99.738,99.738]},{"i":{"x":[0.833,0.833],"y":[0.844,0.844]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":120,"s":[99.798,99.798]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.178,0.178]},"t":121,"s":[99.911,99.911]},{"i":{"x":[0.833,0.833],"y":[0.78,0.78]},"o":{"x":[0.167,0.167],"y":[0.276,0.276]},"t":122,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.859,0.859]},"o":{"x":[0.167,0.167],"y":[0.134,0.134]},"t":123,"s":[100.052,100.052]},{"i":{"x":[0.833,0.833],"y":[0.87,0.87]},"o":{"x":[0.167,0.167],"y":[0.204,0.204]},"t":124,"s":[100.122,100.122]},{"i":{"x":[0.833,0.833],"y":[0.897,0.897]},"o":{"x":[0.167,0.167],"y":[0.231,0.231]},"t":125,"s":[100.17,100.17]},{"i":{"x":[0.833,0.833],"y":[0.922,0.922]},"o":{"x":[0.167,0.167],"y":[0.444,0.444]},"t":126,"s":[100.198,100.198]},{"i":{"x":[0.833,0.833],"y":[-2.132,-2.132]},"o":{"x":[0.167,0.167],"y":[-1.2,-1.2]},"t":127,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.851,0.851]},"o":{"x":[0.167,0.167],"y":[0.086,0.086]},"t":128,"s":[100.204,100.204]},{"i":{"x":[0.833,0.833],"y":[0.706,0.706]},"o":{"x":[0.167,0.167],"y":[0.189,0.189]},"t":129,"s":[100.189,100.189]},{"i":{"x":[0.833,0.833],"y":[0.819,0.819]},"o":{"x":[0.167,0.167],"y":[0.116,0.116]},"t":130,"s":[100.177,100.177]},{"i":{"x":[0.833,0.833],"y":[0.873,0.873]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":131,"s":[100.147,100.147]},{"i":{"x":[0.833,0.833],"y":[0.751,0.751]},"o":{"x":[0.167,0.167],"y":[0.242,0.242]},"t":132,"s":[100.112,100.112]},{"i":{"x":[0.833,0.833],"y":[0.839,0.839]},"o":{"x":[0.167,0.167],"y":[0.125,0.125]},"t":133,"s":[100.094,100.094]},{"i":{"x":[0.833,0.833],"y":[0.879,0.879]},"o":{"x":[0.167,0.167],"y":[0.173,0.173]},"t":134,"s":[100.057,100.057]},{"i":{"x":[0.833,0.833],"y":[0.772,0.772]},"o":{"x":[0.167,0.167],"y":[0.267,0.267]},"t":135,"s":[100.023,100.023]},{"i":{"x":[0.833,0.833],"y":[0.853,0.853]},"o":{"x":[0.167,0.167],"y":[0.131,0.131]},"t":136,"s":[100.008,100.008]},{"i":{"x":[0.833,0.833],"y":[0.885,0.885]},"o":{"x":[0.167,0.167],"y":[0.192,0.192]},"t":137,"s":[99.981,99.981]},{"i":{"x":[0.833,0.833],"y":[0.802,0.802]},"o":{"x":[0.167,0.167],"y":[0.303,0.303]},"t":138,"s":[99.961,99.961]},{"i":{"x":[0.833,0.833],"y":[0.881,0.881]},"o":{"x":[0.167,0.167],"y":[0.144,0.144]},"t":139,"s":[99.953,99.953]},{"i":{"x":[0.833,0.833],"y":[0.912,0.912]},"o":{"x":[0.167,0.167],"y":[0.278,0.278]},"t":140,"s":[99.942,99.942]},{"i":{"x":[0.833,0.833],"y":[1.994,1.994]},"o":{"x":[0.167,0.167],"y":[1.71,1.71]},"t":141,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.731,0.731]},"o":{"x":[0.167,0.167],"y":[0.077,0.077]},"t":142,"s":[99.937,99.937]},{"i":{"x":[0.833,0.833],"y":[0.862,0.862]},"o":{"x":[0.167,0.167],"y":[0.121,0.121]},"t":143,"s":[99.94,99.94]},{"i":{"x":[0.833,0.833],"y":[0.725,0.725]},"o":{"x":[0.167,0.167],"y":[0.211,0.211]},"t":144,"s":[99.947,99.947]},{"i":{"x":[0.833,0.833],"y":[0.826,0.826]},"o":{"x":[0.167,0.167],"y":[0.119,0.119]},"t":145,"s":[99.952,99.952]},{"i":{"x":[0.833,0.833],"y":[0.875,0.875]},"o":{"x":[0.167,0.167],"y":[0.16,0.16]},"t":146,"s":[99.962,99.962]},{"i":{"x":[0.833,0.833],"y":[0.757,0.757]},"o":{"x":[0.167,0.167],"y":[0.249,0.249]},"t":147,"s":[99.973,99.973]},{"i":{"x":[0.833,0.833],"y":[0.842,0.842]},"o":{"x":[0.167,0.167],"y":[0.127,0.127]},"t":148,"s":[99.978,99.978]},{"i":{"x":[0.833,0.833],"y":[0.88,0.88]},"o":{"x":[0.167,0.167],"y":[0.177,0.177]},"t":149,"s":[99.989,99.989]},{"i":{"x":[0.833,0.833],"y":[0.778,0.778]},"o":{"x":[0.167,0.167],"y":[0.274,0.274]},"t":150,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.857,0.857]},"o":{"x":[0.167,0.167],"y":[0.133,0.133]},"t":151,"s":[100.003,100.003]},{"i":{"x":[0.833,0.833],"y":[0.887,0.887]},"o":{"x":[0.167,0.167],"y":[0.2,0.2]},"t":152,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.818,0.818]},"o":{"x":[0.167,0.167],"y":[0.321,0.321]},"t":153,"s":[100.015,100.015]},{"i":{"x":[0.833,0.833],"y":[0.903,0.903]},"o":{"x":[0.167,0.167],"y":[0.154,0.154]},"t":154,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[1.009,1.009]},"o":{"x":[0.167,0.167],"y":[0.58,0.58]},"t":155,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.553,0.553]},"o":{"x":[0.167,0.167],"y":[0.008,0.008]},"t":156,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.788,0.788]},"o":{"x":[0.167,0.167],"y":[0.102,0.102]},"t":157,"s":[100.019,100.019]},{"i":{"x":[0.833,0.833],"y":[0.868,0.868]},"o":{"x":[0.167,0.167],"y":[0.137,0.137]},"t":158,"s":[100.017,100.017]},{"i":{"x":[0.833,0.833],"y":[0.736,0.736]},"o":{"x":[0.167,0.167],"y":[0.225,0.225]},"t":159,"s":[100.014,100.014]},{"i":{"x":[0.833,0.833],"y":[0.831,0.831]},"o":{"x":[0.167,0.167],"y":[0.122,0.122]},"t":160,"s":[100.013,100.013]},{"i":{"x":[0.833,0.833],"y":[0.876,0.876]},"o":{"x":[0.167,0.167],"y":[0.165,0.165]},"t":161,"s":[100.01,100.01]},{"i":{"x":[0.833,0.833],"y":[0.762,0.762]},"o":{"x":[0.167,0.167],"y":[0.255,0.255]},"t":162,"s":[100.006,100.006]},{"i":{"x":[0.833,0.833],"y":[0.846,0.846]},"o":{"x":[0.167,0.167],"y":[0.128,0.128]},"t":163,"s":[100.004,100.004]},{"i":{"x":[0.833,0.833],"y":[0.882,0.882]},"o":{"x":[0.167,0.167],"y":[0.181,0.181]},"t":164,"s":[100.001,100.001]},{"i":{"x":[0.833,0.833],"y":[0.784,0.784]},"o":{"x":[0.167,0.167],"y":[0.281,0.281]},"t":165,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.862,0.862]},"o":{"x":[0.167,0.167],"y":[0.136,0.136]},"t":166,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.891,0.891]},"o":{"x":[0.167,0.167],"y":[0.211,0.211]},"t":167,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.847,0.847]},"o":{"x":[0.167,0.167],"y":[0.355,0.355]},"t":168,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.968,0.968]},"o":{"x":[0.167,0.167],"y":[0.183,0.183]},"t":169,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.807,0.807]},"o":{"x":[0.167,0.167],"y":[-0.053,-0.053]},"t":170,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.67,0.67]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":171,"s":[99.994,99.994]},{"i":{"x":[0.833,0.833],"y":[0.808,0.808]},"o":{"x":[0.167,0.167],"y":[0.111,0.111]},"t":172,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.871,0.871]},"o":{"x":[0.167,0.167],"y":[0.147,0.147]},"t":173,"s":[99.995,99.995]},{"i":{"x":[0.833,0.833],"y":[0.745,0.745]},"o":{"x":[0.167,0.167],"y":[0.235,0.235]},"t":174,"s":[99.996,99.996]},{"i":{"x":[0.833,0.833],"y":[0.835,0.835]},"o":{"x":[0.167,0.167],"y":[0.124,0.124]},"t":175,"s":[99.997,99.997]},{"i":{"x":[0.833,0.833],"y":[0.878,0.878]},"o":{"x":[0.167,0.167],"y":[0.169,0.169]},"t":176,"s":[99.998,99.998]},{"i":{"x":[0.833,0.833],"y":[0.767,0.767]},"o":{"x":[0.167,0.167],"y":[0.261,0.261]},"t":177,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.849,0.849]},"o":{"x":[0.167,0.167],"y":[0.13,0.13]},"t":178,"s":[99.999,99.999]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.186,0.186]},"t":179,"s":[100,100]},{"t":180,"s":[100.001,100.001]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/video_start.json b/TMessagesProj/src/main/res/raw/video_start.json new file mode 100644 index 0000000000..f59fd293a6 --- /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 0000000000..31b10a2713 --- /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-zh-rCN/strings_na.xml b/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml index 73f6b0325e..a8d246aa31 100644 --- a/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml +++ b/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml @@ -71,6 +71,7 @@ 万圣节 显示用户在线状态 在群组聊天时用户头像的右下角显示在线状态 + 显示用户最近在线状态 也在共同群操作 直接显示完整的群组简介 隐藏消息已读提示 @@ -90,4 +91,5 @@ 偷偷看动态 隐藏文件夹中的\"全部取消静音\" 本地名称颜色 + 显示方形头像 diff --git a/TMessagesProj/src/main/res/values/ids.xml b/TMessagesProj/src/main/res/values/ids.xml index 97fbaf3dce..0774a3a2b9 100644 --- a/TMessagesProj/src/main/res/values/ids.xml +++ b/TMessagesProj/src/main/res/values/ids.xml @@ -11,6 +11,7 @@ + diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 9fcff11773..a13bd640bf 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 @@ -528,6 +529,7 @@ joined %1$s Restricted users Administrators + Channel Settings Delete Channel Delete channel Wait! Deleting this channel will remove all members and all messages will be lost. Delete the channel anyway? @@ -588,6 +590,7 @@ Sorry, you are a member of too many groups and channels. Please leave some before joining a new one. un1 added you to this channel You joined this channel + You joined channel %s You joined this group Remove from channel Sorry, you can\'t send messages to this channel. @@ -986,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 @@ -1011,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 @@ -1067,6 +1079,8 @@ OPEN BOT sponsored recommended + Sponsored + Recommended Advertiser Info What are sponsored\nmessages? Unlike other apps, Telegram never uses your private data to target ads. [Learn more in the Privacy Policy](https://telegram.org/privacy#5-6-no-ads-based-on-user-data) @@ -1110,6 +1124,7 @@ No recent Message Message + Message in %1$s Schedule message SHARE MY PHONE NUMBER Share my contact @@ -1127,7 +1142,8 @@ Delete this chat Delete this chat Delete chats - SLIDE TO CANCEL + Slide to cancel + Cancel Save to downloads Save to GIFs Delete GIF? @@ -2176,8 +2192,8 @@ Blurred Motion Change Chat Background - Change Name Color - Change Name Color + Change Your Color + Appearance Chat Background Reset Chat Backgrounds Remove all uploaded chat backgrounds and restore the pre-installed ones. @@ -2266,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? @@ -2345,6 +2362,7 @@ Videos Press the volume buttons to turn sound on. The account was hidden by the user + The account was hidden by the user Auto-play media Raise to Speak Record voice messages by raising phone to your ear @@ -2352,7 +2370,8 @@ Switch sound to the earpiece by raising phone to your ear Save to Gallery Sound muted - Edit name + Edit Name + Edit Profile Color Customize Custom Enable Custom Notifications @@ -2440,6 +2459,8 @@ Other Paste Flip + Cut Out + Undo Cut Paste from clipboard Proxy Settings Proxy Details @@ -2985,6 +3006,7 @@ Shared Content Shared Links Shared Music + Similar Channels Share photos and videos in this chat and access them on any of your devices. Share music in this chat and access it on any of your devices. Share files and documents in this chat and access them on any of your devices. @@ -3595,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 @@ -3721,6 +3745,8 @@ Self-Destructing Video Photo has expired Video has expired + Round video has expired + Voice expired GIF Location Live Location @@ -3933,10 +3959,15 @@ Growth Followers Interactions + Views and Shares + Reactions + Story Views and Shares + Story Reactions Views by source New followers by source Languages Recent posts + Recent Posts Zoom out IV Interactions Loading stats... @@ -3949,6 +3980,10 @@ Clear Telegram Cache Overview Views Per Post + Views Per Story + Shares Per Story + Reactions Per Story + Reactions Per Post Shares Per Post Enabled Notifications Clear Local Database @@ -4008,6 +4043,7 @@ Public Shares Private Shares View Stats + View Statistics View Channel Stats Message Statistic Open Message @@ -4044,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**? @@ -4380,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. @@ -4830,6 +4874,21 @@ updated %1$d minutes ago updated %1$d minutes ago updated %1$d minutes ago + now + today + yesterday + %dm + %dm + %dm + %dm + %dm + %dm + %dh + %dh + %dh + %dh + %dh + %dh %1$d minutes ago %1$d minute ago %1$d minutes ago @@ -5474,9 +5533,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? @@ -5883,12 +5945,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 @@ -5924,6 +6017,8 @@ Add up to %d chats into each of your folders Connected Accounts Connect %d accounts with different mobile numbers + Similar Channels + View up to %d similar channels Doubled Limits Sorry, you can\'t add more than **%1$d** accounts. You can increase this limit to **%2$d** by upgrading to **Telegram Premium**. Sorry, you can\'t add more than **%1$d** accounts. @@ -6031,6 +6126,10 @@ Add any of thousands emojis next to your name to display current activity. Real-Time Translation Real-time translation of channels and chats into other languages. + Wallpaper for Both Sides + Set custom wallpapers for you and your chat partner. + Name and Profile Colors + Choose a color and logo for your profile and replies to your messages. Microphone for voice messages Built-In Headset @@ -6271,21 +6370,27 @@ Create Contact Suggested Photo Suggested Video - You suggested %s to use this photo for their account. - You suggested %s to use this video for their account. - %s suggests you to use this photo for your account. - %s suggests you to use this video for your account. + You suggested %s to use this photo for their account + You suggested %s to use this video for their account + %s suggests you to use this photo for your account + %s suggests you to use this video for your account **Photo updated** You can change it in **Settings.** Suggested profile photo Suggested profile video Set as My Photo Invite To Telegram - You allowed this bot to message you when you added it to your attachment menu. + You allowed this bot to message you when you added it to your attachment menu You shared un1 with un2 You shared a user with un2 You shared a chat with un2 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 @@ -6457,6 +6562,7 @@ Animated spoiler effect Night theme blur Zoom animations + Dust-effect deletion Animations in Calls Autoplay Videos Autoplay GIFs @@ -6590,10 +6696,14 @@ You can only have %1$d shareable folders. Try deleting some shareable folder. You can only have %1$d shareable folders. We are working to let you increase this limit in the future. Set Background From Gallery - You set a new wallpaper for this chat. - You set the same wallpaper for the chat. - %s set a new wallpaper for this chat. - %s set a same wallpaper for this chat. + Setting new wallpaper... + You set a new wallpaper for this chat + 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 + %s set a same wallpaper for this chat + You set a new wallpaper for %s and you Remove Folder Folder already added Add folder @@ -6706,7 +6816,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 @@ -6715,6 +6829,7 @@ Preview this background in night mode. Preview this background in day mode. View Wallpaper + Remove Wallpaper Set a new chat Wallpaper Set a same chat Wallpaper @@ -6760,6 +6875,8 @@ Couldn’t upload Try Again Story + Story Statistics + Post Statistics Message sent. Just now Expired story @@ -7012,6 +7129,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. @@ -7020,6 +7138,7 @@ Saved Stories New Story Edit + Repost Allow Screenshots **Select people** who won’t see your stories. **%d people** won’t see your stories. @@ -7127,7 +7246,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.** @@ -7170,13 +7289,29 @@ 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... + You can also **create your own** emoji packs and use them. + You can add emoji from any emoji pack as a reaction. + Update Reactions + Level %1$d Required + Level %1$d Required + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions. + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions. + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Your channel needs to reach Level **%2$d** to add **%1$d** custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link: + Custom Reactions + You have changed the list of reactions. Apply changes? + You can select maximum %1$d reaction. + You can select maximum %1$d reactions. All viewers Reactions First + Reposts First Newest First - Choose the order for the -list of viewers. + 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 @@ -7190,10 +7325,11 @@ list of viewers. 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**. @@ -7207,6 +7343,7 @@ list of viewers. Photo Send reaction as a private message Remove Audio + Remove Video Publish story as Who can view your story Style @@ -7249,6 +7386,11 @@ list of viewers. %s just started a giveaway of Telegram Premium subscriptions to its followers. Delete announcement Deleting this message won\'t cancel the giveaway - the winners will still be selected on **%s**.\n\nOnce deleted, the Giveaway Announcement cannot be restored. + %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. + %d winner of the giveaway were randomly selected by Telegram and received private message with giftcode. + %d winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes. + %d undistributed link codes were forwarded to channel administrators. + %d undistributed links codes were forwarded to channel administrators. %d boost %d boost %d boosts @@ -7301,6 +7443,7 @@ list of viewers. To be distributed %1$dm Giveaway + Giveaway results Channel started a giveaway The recipient will be selected when the giveaway ends. Incomplete Giveaway @@ -7373,11 +7516,22 @@ list of viewers. 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**. @@ -7519,12 +7673,15 @@ list of viewers. %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 @@ -7533,6 +7690,14 @@ list of viewers. 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 @@ -7548,7 +7713,10 @@ list of viewers. 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! @@ -7571,6 +7739,7 @@ list of viewers. 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 @@ -7591,12 +7760,19 @@ list of viewers. 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. @@ -7617,7 +7793,12 @@ list of viewers. **%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... @@ -7669,11 +7850,13 @@ list of viewers. Your selected color will also tint the link preview. Apply Color and Icon Subscribe to **Telegram Premium** to choose a custom color for your name. + Subscribe to **Telegram Premium** to choose a custom color for your profile. Add Icons to Replies - Make replies to your messages stand out by adding custom icons to them. + Add Icons to Profile + Choose a color and an icon for your profile Off Off - Your Channel Color + 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 @@ -7681,7 +7864,12 @@ list of viewers. Your selected color will also tint the link preview. Apply Color and Icon Add Icons to Replies - Make replies to your messages stand out by adding custom icons to them. + Add Icons to Profile + Choose a color and an icon for your profile + Name + Profile + Name + Profile Outdated Quote Quote too long! The selected text is too long to quote. @@ -7698,12 +7886,90 @@ list of viewers. Swipe left or right Warmth Intensity + Dimming 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! + Your profile color has been reset! + Your channel profile color has been reset! + Your profile emoji has been put! + Your channel profile emoji has been put! Copy Code + Similar Channels + Apply for Me + Apply for Me and %s + 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. + You have **%1$d** free voice transcriptions left. + You have **%1$d** free voice transcription left until %2$s. + You have **%1$d** free voice transcriptions left until %2$s. + You have used your **%1$d** free transcription this week. + You have used all your **%1$d** free transcriptions this week. + Wait until %1$s or subscribe to **Telegram Premium** now. + Subscribe to **Telegram Premium** to unlock unlimited transcriptions. + Reset Profile Color + Reset Profile Color + Subscribe to **Telegram Premium** to unlock up to %d similar channels. + You can set multiple reactions with Telegram Premium. + More Channels + Unlock more channels + Show More Channels + Subscribe to **Telegram Premium**\nto unlock up to %s similar channels. + 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/values/strings_na.xml b/TMessagesProj/src/main/res/values/strings_na.xml index 0086ba8bc8..4c24e5acd5 100644 --- a/TMessagesProj/src/main/res/values/strings_na.xml +++ b/TMessagesProj/src/main/res/values/strings_na.xml @@ -74,6 +74,7 @@ HalloWeen Show Online Status Show the online status of other people next to their profile photo in groups + Show Recent Online Status Applied in common groups Show full about info Hide message seen tooltip @@ -93,4 +94,5 @@ Disable Send Read Stories Hide filter mute all Use local quote color + Show square avatar 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 79ec6f5e25..0000000000 --- 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 d8044115b1..e7996ea533 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